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 "gst/gst-i18n-plugin.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 "qtatomparser.h"
63 #include "qtdemux_types.h"
64 #include "qtdemux_dump.h"
66 #include "descriptors.h"
67 #include "qtdemux_lang.h"
69 #include "qtpalette.h"
70 #include "qtdemux_tags.h"
71 #include "qtdemux_tree.h"
77 #include <gst/math-compat.h>
83 /* max. size considered 'sane' for non-mdat atoms */
84 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
86 /* if the sample index is larger than this, something is likely wrong */
87 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
89 /* For converting qt creation times to unix epoch times */
90 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
91 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
92 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
93 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
95 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
97 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
99 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
101 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
102 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
103 #define QTDEMUX_NTH_STREAM(demux,idx) \
104 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
105 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
106 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
108 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
110 GST_DEBUG_CATEGORY (qtdemux_debug);
111 #define GST_CAT_DEFAULT qtdemux_debug
113 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
114 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
116 /* Macros for converting to/from timescale */
117 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
118 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
120 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
121 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
123 /* timestamp is the DTS */
124 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
125 /* timestamp + offset + cslg_shift is the outgoing PTS */
126 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
127 /* timestamp + offset is the PTS used for internal seek calculations */
128 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
129 /* timestamp + duration - dts is the duration */
130 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
132 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
134 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
135 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
136 GST_TRACE("Locking from thread %p", g_thread_self()); \
137 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
138 GST_TRACE("Locked from thread %p", g_thread_self()); \
141 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
142 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
143 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
147 * Quicktime has tracks and segments. A track is a continuous piece of
148 * multimedia content. The track is not always played from start to finish but
149 * instead, pieces of the track are 'cut out' and played in sequence. This is
150 * what the segments do.
152 * Inside the track we have keyframes (K) and delta frames. The track has its
153 * own timing, which starts from 0 and extends to end. The position in the track
154 * is called the media_time.
156 * The segments now describe the pieces that should be played from this track
157 * and are basically tuples of media_time/duration/rate entries. We can have
158 * multiple segments and they are all played after one another. An example:
160 * segment 1: media_time: 1 second, duration: 1 second, rate 1
161 * segment 2: media_time: 3 second, duration: 2 second, rate 2
163 * To correctly play back this track, one must play: 1 second of media starting
164 * from media_time 1 followed by 2 seconds of media starting from media_time 3
167 * Each of the segments will be played at a specific time, the first segment at
168 * time 0, the second one after the duration of the first one, etc.. Note that
169 * the time in resulting playback is not identical to the media_time of the
172 * Visually, assuming the track has 4 second of media_time:
175 * .-----------------------------------------------------------.
176 * track: | K.....K.........K........K.......K.......K...........K... |
177 * '-----------------------------------------------------------'
179 * .------------^ ^ .----------^ ^
180 * / .-------------' / .------------------'
182 * .--------------. .--------------.
183 * | segment 1 | | segment 2 |
184 * '--------------' '--------------'
186 * The challenge here is to cut out the right pieces of the track for each of
187 * the playback segments. This fortunately can easily be done with the SEGMENT
188 * events of GStreamer.
190 * For playback of segment 1, we need to provide the decoder with the keyframe
191 * (a), in the above figure, but we must instruct it only to output the decoded
192 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
193 * position set to the time of the segment: 0.
195 * We then proceed to push data from keyframe (a) to frame (b). The decoder
196 * decodes but clips all before media_time 1.
198 * After finishing a segment, we push out a new SEGMENT event with the clipping
199 * boundaries of the new data.
201 * This is a good usecase for the GStreamer accumulated SEGMENT events.
204 struct _QtDemuxSegment
206 /* global time and duration, all gst time */
208 GstClockTime stop_time;
209 GstClockTime duration;
210 /* media time of trak, all gst time */
211 GstClockTime media_start;
212 GstClockTime media_stop;
214 /* Media start time in trak timescale units */
215 guint32 trak_media_start;
218 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
220 /* Used with fragmented MP4 files (mfra atom) */
221 struct _QtDemuxRandomAccessEntry
228 /* Contains properties and cryptographic info for a set of samples from a
229 * track protected using Common Encryption (cenc) */
230 struct _QtDemuxCencSampleSetInfo
232 GstStructure *default_properties;
234 /* @crypto_info holds one GstStructure per sample */
235 GPtrArray *crypto_info;
238 struct _QtDemuxAavdEncryptionInfo
240 GstStructure *default_properties;
244 qt_demux_state_string (enum QtDemuxState state)
247 case QTDEMUX_STATE_INITIAL:
249 case QTDEMUX_STATE_HEADER:
251 case QTDEMUX_STATE_MOVIE:
253 case QTDEMUX_STATE_BUFFER_MDAT:
254 return "<BUFFER_MDAT>";
260 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
262 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
264 static GstStaticPadTemplate gst_qtdemux_sink_template =
265 GST_STATIC_PAD_TEMPLATE ("sink",
268 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
272 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
273 GST_STATIC_PAD_TEMPLATE ("video_%u",
276 GST_STATIC_CAPS_ANY);
278 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
279 GST_STATIC_PAD_TEMPLATE ("audio_%u",
282 GST_STATIC_CAPS_ANY);
284 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
285 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
288 GST_STATIC_CAPS_ANY);
290 #define gst_qtdemux_parent_class parent_class
291 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
293 static void gst_qtdemux_dispose (GObject * object);
294 static void gst_qtdemux_finalize (GObject * object);
297 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
298 GstClockTime media_time);
300 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
301 QtDemuxStream * str, gint64 media_offset);
304 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
305 static GstIndex *gst_qtdemux_get_index (GstElement * element);
307 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
308 GstStateChange transition);
309 static void gst_qtdemux_set_context (GstElement * element,
310 GstContext * context);
311 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
312 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
313 GstObject * parent, GstPadMode mode, gboolean active);
315 static void gst_qtdemux_loop (GstPad * pad);
316 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
318 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
320 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
322 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
323 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
324 QtDemuxStream * stream);
325 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
326 QtDemuxStream * stream);
327 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
330 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
332 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
333 const guint8 * buffer, guint length);
334 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
335 const guint8 * buffer, guint length);
336 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
338 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
339 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
341 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
342 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
343 const guint8 * stsd_entry_data, gchar ** codec_name);
344 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
345 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
346 const guint8 * data, int len, gchar ** codec_name);
347 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
348 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
349 gchar ** codec_name);
350 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
351 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
352 const guint8 * stsd_entry_data, gchar ** codec_name);
354 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
355 QtDemuxStream * stream, guint32 n);
356 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
357 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
358 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
359 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
360 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
361 static void qtdemux_do_allocation (QtDemuxStream * stream,
362 GstQTDemux * qtdemux);
363 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
364 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
365 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
366 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
367 GstClockTime * _start, GstClockTime * _stop);
368 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
369 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
371 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
372 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
374 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
376 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
377 QtDemuxStream * stream, guint sample_index);
378 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
380 static void qtdemux_gst_structure_free (GstStructure * gststructure);
381 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
384 gst_qtdemux_class_init (GstQTDemuxClass * klass)
386 GObjectClass *gobject_class;
387 GstElementClass *gstelement_class;
389 gobject_class = (GObjectClass *) klass;
390 gstelement_class = (GstElementClass *) klass;
392 parent_class = g_type_class_peek_parent (klass);
394 gobject_class->dispose = gst_qtdemux_dispose;
395 gobject_class->finalize = gst_qtdemux_finalize;
397 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
399 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
400 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
402 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
404 gst_tag_register_musicbrainz_tags ();
406 gst_element_class_add_static_pad_template (gstelement_class,
407 &gst_qtdemux_sink_template);
408 gst_element_class_add_static_pad_template (gstelement_class,
409 &gst_qtdemux_videosrc_template);
410 gst_element_class_add_static_pad_template (gstelement_class,
411 &gst_qtdemux_audiosrc_template);
412 gst_element_class_add_static_pad_template (gstelement_class,
413 &gst_qtdemux_subsrc_template);
414 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
416 "Demultiplex a QuickTime file into audio and video streams",
417 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
419 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
424 gst_qtdemux_init (GstQTDemux * qtdemux)
427 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
428 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
429 gst_pad_set_activatemode_function (qtdemux->sinkpad,
430 qtdemux_sink_activate_mode);
431 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
432 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
433 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
434 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
436 qtdemux->adapter = gst_adapter_new ();
437 g_queue_init (&qtdemux->protection_event_queue);
438 qtdemux->flowcombiner = gst_flow_combiner_new ();
439 g_mutex_init (&qtdemux->expose_lock);
441 qtdemux->active_streams = g_ptr_array_new_with_free_func
442 ((GDestroyNotify) gst_qtdemux_stream_unref);
443 qtdemux->old_streams = g_ptr_array_new_with_free_func
444 ((GDestroyNotify) gst_qtdemux_stream_unref);
446 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
448 gst_qtdemux_reset (qtdemux, TRUE);
452 gst_qtdemux_finalize (GObject * object)
454 GstQTDemux *qtdemux = GST_QTDEMUX (object);
456 g_free (qtdemux->redirect_location);
458 G_OBJECT_CLASS (parent_class)->finalize (object);
462 gst_qtdemux_dispose (GObject * object)
464 GstQTDemux *qtdemux = GST_QTDEMUX (object);
466 if (qtdemux->adapter) {
467 g_object_unref (G_OBJECT (qtdemux->adapter));
468 qtdemux->adapter = NULL;
470 gst_tag_list_unref (qtdemux->tag_list);
471 gst_flow_combiner_free (qtdemux->flowcombiner);
472 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
474 g_queue_clear (&qtdemux->protection_event_queue);
476 g_free (qtdemux->cenc_aux_info_sizes);
477 qtdemux->cenc_aux_info_sizes = NULL;
478 g_mutex_clear (&qtdemux->expose_lock);
480 g_ptr_array_free (qtdemux->active_streams, TRUE);
481 g_ptr_array_free (qtdemux->old_streams, TRUE);
483 G_OBJECT_CLASS (parent_class)->dispose (object);
487 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
489 if (qtdemux->redirect_location) {
490 GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
491 (_("This file contains no playable streams.")),
492 ("no known streams found, a redirect message has been posted"),
493 ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
495 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
496 (_("This file contains no playable streams.")),
497 ("no known streams found"));
502 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
504 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
505 mem, size, 0, size, mem, free_func);
509 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
516 if (G_UNLIKELY (size == 0)) {
518 GstBuffer *tmp = NULL;
520 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
521 if (ret != GST_FLOW_OK)
524 gst_buffer_map (tmp, &map, GST_MAP_READ);
525 size = QT_UINT32 (map.data);
526 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
528 gst_buffer_unmap (tmp, &map);
529 gst_buffer_unref (tmp);
532 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
533 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
534 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
535 /* we're pulling header but already got most interesting bits,
536 * so never mind the rest (e.g. tags) (that much) */
537 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
541 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
542 (_("This file is invalid and cannot be played.")),
543 ("atom has bogus size %" G_GUINT64_FORMAT, size));
544 return GST_FLOW_ERROR;
548 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
550 if (G_UNLIKELY (flow != GST_FLOW_OK))
553 bsize = gst_buffer_get_size (*buf);
554 /* Catch short reads - we don't want any partial atoms */
555 if (G_UNLIKELY (bsize < size)) {
556 GST_WARNING_OBJECT (qtdemux,
557 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
558 gst_buffer_unref (*buf);
568 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
569 GstFormat src_format, gint64 src_value, GstFormat dest_format,
573 QtDemuxStream *stream = gst_pad_get_element_private (pad);
576 if (stream->subtype != FOURCC_vide) {
581 switch (src_format) {
582 case GST_FORMAT_TIME:
583 switch (dest_format) {
584 case GST_FORMAT_BYTES:{
585 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
591 *dest_value = stream->samples[index].offset;
593 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
594 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
595 GST_TIME_ARGS (src_value), *dest_value);
603 case GST_FORMAT_BYTES:
604 switch (dest_format) {
605 case GST_FORMAT_TIME:{
607 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
616 QTSTREAMTIME_TO_GSTTIME (stream,
617 stream->samples[index].timestamp);
618 GST_DEBUG_OBJECT (qtdemux,
619 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
620 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
639 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
641 gboolean res = FALSE;
643 *duration = GST_CLOCK_TIME_NONE;
645 if (qtdemux->duration != 0 &&
646 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
647 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
650 *duration = GST_CLOCK_TIME_NONE;
657 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
660 gboolean res = FALSE;
661 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
663 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
665 switch (GST_QUERY_TYPE (query)) {
666 case GST_QUERY_POSITION:{
669 gst_query_parse_position (query, &fmt, NULL);
670 if (fmt == GST_FORMAT_TIME
671 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
672 gst_query_set_position (query, GST_FORMAT_TIME,
673 qtdemux->segment.position);
678 case GST_QUERY_DURATION:{
681 gst_query_parse_duration (query, &fmt, NULL);
682 if (fmt == GST_FORMAT_TIME) {
683 /* First try to query upstream */
684 res = gst_pad_query_default (pad, parent, query);
686 GstClockTime duration;
687 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
688 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
695 case GST_QUERY_CONVERT:{
696 GstFormat src_fmt, dest_fmt;
697 gint64 src_value, dest_value = 0;
699 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
701 res = gst_qtdemux_src_convert (qtdemux, pad,
702 src_fmt, src_value, dest_fmt, &dest_value);
704 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
708 case GST_QUERY_FORMATS:
709 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
712 case GST_QUERY_SEEKING:{
716 /* try upstream first */
717 res = gst_pad_query_default (pad, parent, query);
720 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
721 if (fmt == GST_FORMAT_TIME) {
722 GstClockTime duration;
724 gst_qtdemux_get_duration (qtdemux, &duration);
726 if (!qtdemux->pullbased) {
729 /* we might be able with help from upstream */
731 q = gst_query_new_seeking (GST_FORMAT_BYTES);
732 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
733 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
734 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
738 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
744 case GST_QUERY_SEGMENT:
749 format = qtdemux->segment.format;
752 gst_segment_to_stream_time (&qtdemux->segment, format,
753 qtdemux->segment.start);
754 if ((stop = qtdemux->segment.stop) == -1)
755 stop = qtdemux->segment.duration;
757 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
759 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
764 res = gst_pad_query_default (pad, parent, query);
772 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
774 if (G_LIKELY (stream->pad)) {
775 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
776 GST_DEBUG_PAD_NAME (stream->pad));
778 if (!gst_tag_list_is_empty (stream->stream_tags)) {
779 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
780 stream->stream_tags);
781 gst_pad_push_event (stream->pad,
782 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
785 if (G_UNLIKELY (stream->send_global_tags)) {
786 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
788 gst_pad_push_event (stream->pad,
789 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
790 stream->send_global_tags = FALSE;
795 /* push event on all source pads; takes ownership of the event */
797 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
799 gboolean has_valid_stream = FALSE;
800 GstEventType etype = GST_EVENT_TYPE (event);
803 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
804 GST_EVENT_TYPE_NAME (event));
806 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
808 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
809 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
811 if ((pad = stream->pad)) {
812 has_valid_stream = TRUE;
814 if (etype == GST_EVENT_EOS) {
815 /* let's not send twice */
816 if (stream->sent_eos)
818 stream->sent_eos = TRUE;
821 gst_pad_push_event (pad, gst_event_ref (event));
825 gst_event_unref (event);
827 /* if it is EOS and there are no pads, post an error */
828 if (!has_valid_stream && etype == GST_EVENT_EOS) {
829 gst_qtdemux_post_no_playable_stream_error (qtdemux);
839 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
841 if ((gint64) s1->timestamp > *media_time)
843 if ((gint64) s1->timestamp == *media_time)
849 /* find the index of the sample that includes the data for @media_time using a
850 * binary search. Only to be called in optimized cases of linear search below.
852 * Returns the index of the sample with the corresponding *DTS*.
855 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
858 QtDemuxSample *result;
861 /* convert media_time to mov format */
863 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
865 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
866 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
867 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
869 if (G_LIKELY (result))
870 index = result - str->samples;
879 /* find the index of the sample that includes the data for @media_offset using a
882 * Returns the index of the sample.
885 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
886 QtDemuxStream * str, gint64 media_offset)
888 QtDemuxSample *result = str->samples;
891 if (result == NULL || str->n_samples == 0)
894 if (media_offset == result->offset)
898 while (index < str->n_samples - 1) {
899 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
902 if (media_offset < result->offset)
913 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
918 /* find the index of the sample that includes the data for @media_time using a
919 * linear search, and keeping in mind that not all samples may have been parsed
920 * yet. If possible, it will delegate to binary search.
922 * Returns the index of the sample.
925 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
926 GstClockTime media_time)
930 QtDemuxSample *sample;
932 /* convert media_time to mov format */
934 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
936 sample = str->samples;
937 if (mov_time == sample->timestamp + sample->pts_offset)
940 /* use faster search if requested time in already parsed range */
941 sample = str->samples + str->stbl_index;
942 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
943 index = gst_qtdemux_find_index (qtdemux, str, media_time);
944 sample = str->samples + index;
946 while (index < str->n_samples - 1) {
947 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
950 sample = str->samples + index + 1;
951 if (mov_time < sample->timestamp) {
952 sample = str->samples + index;
960 /* sample->timestamp is now <= media_time, need to find the corresponding
961 * PTS now by looking backwards */
962 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
964 sample = str->samples + index;
972 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
977 /* find the index of the keyframe needed to decode the sample at @index
978 * of stream @str, or of a subsequent keyframe (depending on @next)
980 * Returns the index of the keyframe.
983 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
984 guint32 index, gboolean next)
986 guint32 new_index = index;
988 if (index >= str->n_samples) {
989 new_index = str->n_samples;
993 /* all keyframes, return index */
994 if (str->all_keyframe) {
999 /* else search until we have a keyframe */
1000 while (new_index < str->n_samples) {
1001 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1004 if (str->samples[new_index].keyframe)
1016 if (new_index == str->n_samples) {
1017 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1022 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1023 "gave %u", next ? "after" : "before", index, new_index);
1030 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1035 /* find the segment for @time_position for @stream
1037 * Returns the index of the segment containing @time_position.
1038 * Returns the last segment and sets the @eos variable to TRUE
1039 * if the time is beyond the end. @eos may be NULL
1042 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1043 GstClockTime time_position)
1048 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1049 GST_TIME_ARGS (time_position));
1052 for (i = 0; i < stream->n_segments; i++) {
1053 QtDemuxSegment *segment = &stream->segments[i];
1055 GST_LOG_OBJECT (stream->pad,
1056 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1057 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1059 /* For the last segment we include stop_time in the last segment */
1060 if (i < stream->n_segments - 1) {
1061 if (segment->time <= time_position && time_position < segment->stop_time) {
1062 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1067 /* Last segment always matches */
1075 /* move the stream @str to the sample position @index.
1077 * Updates @str->sample_index and marks discontinuity if needed.
1080 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1083 /* no change needed */
1084 if (index == str->sample_index)
1087 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1090 /* position changed, we have a discont */
1091 str->sample_index = index;
1092 str->offset_in_sample = 0;
1093 /* Each time we move in the stream we store the position where we are
1095 str->from_sample = index;
1096 str->discont = TRUE;
1100 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1101 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1104 gint64 min_byte_offset = -1;
1107 min_offset = desired_time;
1109 /* for each stream, find the index of the sample in the segment
1110 * and move back to the previous keyframe. */
1111 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1113 guint32 index, kindex;
1115 GstClockTime media_start;
1116 GstClockTime media_time;
1117 GstClockTime seg_time;
1118 QtDemuxSegment *seg;
1119 gboolean empty_segment = FALSE;
1121 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1123 if (CUR_STREAM (str)->sparse && !use_sparse)
1126 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1127 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1129 /* get segment and time in the segment */
1130 seg = &str->segments[seg_idx];
1131 seg_time = (desired_time - seg->time) * seg->rate;
1133 while (QTSEGMENT_IS_EMPTY (seg)) {
1135 empty_segment = TRUE;
1136 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1139 if (seg_idx == str->n_segments)
1141 seg = &str->segments[seg_idx];
1144 if (seg_idx == str->n_segments) {
1145 /* FIXME track shouldn't have the last segment as empty, but if it
1146 * happens we better handle it */
1150 /* get the media time in the segment */
1151 media_start = seg->media_start + seg_time;
1153 /* get the index of the sample with media time */
1154 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1155 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1156 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1157 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1160 /* shift to next frame if we are looking for next keyframe */
1161 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1162 && index < str->stbl_index)
1165 if (!empty_segment) {
1166 /* find previous keyframe */
1167 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1169 /* we will settle for one before if none found after */
1170 if (next && kindex == -1)
1171 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1173 /* Update the requested time whenever a keyframe was found, to make it
1174 * accurate and avoid having the first buffer fall outside of the segment
1179 /* get timestamp of keyframe */
1180 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1181 GST_DEBUG_OBJECT (qtdemux,
1182 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1183 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1184 str->samples[kindex].offset);
1186 /* keyframes in the segment get a chance to change the
1187 * desired_offset. keyframes out of the segment are
1189 if (media_time >= seg->media_start) {
1190 GstClockTime seg_time;
1192 /* this keyframe is inside the segment, convert back to
1194 seg_time = (media_time - seg->media_start) + seg->time;
1195 if ((!next && (seg_time < min_offset)) ||
1196 (next && (seg_time > min_offset)))
1197 min_offset = seg_time;
1202 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1203 min_byte_offset = str->samples[index].offset;
1207 *key_time = min_offset;
1209 *key_offset = min_byte_offset;
1213 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1214 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1218 g_return_val_if_fail (format != NULL, FALSE);
1219 g_return_val_if_fail (cur != NULL, FALSE);
1220 g_return_val_if_fail (stop != NULL, FALSE);
1222 if (*format == GST_FORMAT_TIME)
1226 if (cur_type != GST_SEEK_TYPE_NONE)
1227 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1228 if (res && stop_type != GST_SEEK_TYPE_NONE)
1229 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1232 *format = GST_FORMAT_TIME;
1237 /* perform seek in push based mode:
1238 find BYTE position to move to based on time and delegate to upstream
1241 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1246 GstSeekType cur_type, stop_type;
1247 gint64 cur, stop, key_cur;
1250 gint64 original_stop;
1253 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1255 gst_event_parse_seek (event, &rate, &format, &flags,
1256 &cur_type, &cur, &stop_type, &stop);
1257 seqnum = gst_event_get_seqnum (event);
1259 /* Directly send the instant-rate-change event here before taking the
1260 * stream-lock so that it can be applied as soon as possible */
1261 if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1264 /* instant rate change only supported if direction does not change. All
1265 * other requirements are already checked before creating the seek event
1266 * but let's double-check here to be sure */
1267 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1268 (qtdemux->segment.rate < 0 && rate > 0) ||
1269 cur_type != GST_SEEK_TYPE_NONE ||
1270 stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1271 GST_ERROR_OBJECT (qtdemux,
1272 "Instant rate change seeks only supported in the "
1273 "same direction, without flushing and position change");
1277 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1278 (GstSegmentFlags) flags);
1279 gst_event_set_seqnum (ev, seqnum);
1280 gst_qtdemux_push_event (qtdemux, ev);
1284 /* only forward streaming and seeking is possible */
1286 goto unsupported_seek;
1288 /* convert to TIME if needed and possible */
1289 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1293 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1294 * the original stop position to use when upstream pushes the new segment
1296 original_stop = stop;
1299 /* find reasonable corresponding BYTE position,
1300 * also try to mind about keyframes, since we can not go back a bit for them
1302 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1303 * mostly just work, but let's not yet boldly go there ... */
1304 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1309 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1310 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1313 GST_OBJECT_LOCK (qtdemux);
1314 qtdemux->seek_offset = byte_cur;
1315 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1316 qtdemux->push_seek_start = cur;
1318 qtdemux->push_seek_start = key_cur;
1321 if (stop_type == GST_SEEK_TYPE_NONE) {
1322 qtdemux->push_seek_stop = qtdemux->segment.stop;
1324 qtdemux->push_seek_stop = original_stop;
1326 GST_OBJECT_UNLOCK (qtdemux);
1328 qtdemux->segment_seqnum = seqnum;
1329 /* BYTE seek event */
1330 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1332 gst_event_set_seqnum (event, seqnum);
1333 res = gst_pad_push_event (qtdemux->sinkpad, event);
1340 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1346 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1351 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1356 /* perform the seek.
1358 * We set all segment_indexes in the streams to unknown and
1359 * adjust the time_position to the desired position. this is enough
1360 * to trigger a segment switch in the streaming thread to start
1361 * streaming from the desired position.
1363 * Keyframe seeking is a little more complicated when dealing with
1364 * segments. Ideally we want to move to the previous keyframe in
1365 * the segment but there might not be a keyframe in the segment. In
1366 * fact, none of the segments could contain a keyframe. We take a
1367 * practical approach: seek to the previous keyframe in the segment,
1368 * if there is none, seek to the beginning of the segment.
1370 * Called with STREAM_LOCK
1373 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1374 guint32 seqnum, GstSeekFlags flags)
1376 gint64 desired_offset;
1379 desired_offset = segment->position;
1381 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1382 GST_TIME_ARGS (desired_offset));
1384 /* may not have enough fragmented info to do this adjustment,
1385 * and we can't scan (and probably should not) at this time with
1386 * possibly flushing upstream */
1387 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1389 gboolean next, before, after;
1391 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1392 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1393 next = after && !before;
1394 if (segment->rate < 0)
1397 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1399 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1400 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1401 desired_offset = min_offset;
1404 /* and set all streams to the final position */
1405 GST_OBJECT_LOCK (qtdemux);
1406 gst_flow_combiner_reset (qtdemux->flowcombiner);
1407 GST_OBJECT_UNLOCK (qtdemux);
1408 qtdemux->segment_seqnum = seqnum;
1409 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1410 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1412 stream->time_position = desired_offset;
1413 stream->accumulated_base = 0;
1414 stream->sample_index = -1;
1415 stream->offset_in_sample = 0;
1416 stream->segment_index = -1;
1417 stream->sent_eos = FALSE;
1418 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1420 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1421 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1423 segment->position = desired_offset;
1424 if (segment->rate >= 0) {
1425 segment->start = desired_offset;
1426 /* We need to update time as we update start in that direction */
1427 segment->time = desired_offset;
1429 /* we stop at the end */
1430 if (segment->stop == -1)
1431 segment->stop = segment->duration;
1433 segment->stop = desired_offset;
1436 if (qtdemux->fragmented)
1437 qtdemux->fragmented_seek_pending = TRUE;
1442 /* do a seek in pull based mode */
1444 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1449 GstSeekType cur_type, stop_type;
1451 gboolean flush, instant_rate_change;
1453 GstSegment seeksegment;
1454 guint32 seqnum = GST_SEQNUM_INVALID;
1455 GstEvent *flush_event;
1458 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1460 gst_event_parse_seek (event, &rate, &format, &flags,
1461 &cur_type, &cur, &stop_type, &stop);
1462 seqnum = gst_event_get_seqnum (event);
1464 /* we have to have a format as the segment format. Try to convert
1466 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1470 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1472 flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1473 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1475 /* Directly send the instant-rate-change event here before taking the
1476 * stream-lock so that it can be applied as soon as possible */
1477 if (instant_rate_change) {
1480 /* instant rate change only supported if direction does not change. All
1481 * other requirements are already checked before creating the seek event
1482 * but let's double-check here to be sure */
1483 if ((qtdemux->segment.rate > 0 && rate < 0) ||
1484 (qtdemux->segment.rate < 0 && rate > 0) ||
1485 cur_type != GST_SEEK_TYPE_NONE ||
1486 stop_type != GST_SEEK_TYPE_NONE || flush) {
1487 GST_ERROR_OBJECT (qtdemux,
1488 "Instant rate change seeks only supported in the "
1489 "same direction, without flushing and position change");
1493 ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1494 (GstSegmentFlags) flags);
1495 gst_event_set_seqnum (ev, seqnum);
1496 gst_qtdemux_push_event (qtdemux, ev);
1500 /* stop streaming, either by flushing or by pausing the task */
1502 flush_event = gst_event_new_flush_start ();
1503 if (seqnum != GST_SEQNUM_INVALID)
1504 gst_event_set_seqnum (flush_event, seqnum);
1505 /* unlock upstream pull_range */
1506 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1507 /* make sure out loop function exits */
1508 gst_qtdemux_push_event (qtdemux, flush_event);
1510 /* non flushing seek, pause the task */
1511 gst_pad_pause_task (qtdemux->sinkpad);
1514 /* wait for streaming to finish */
1515 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1517 /* copy segment, we need this because we still need the old
1518 * segment when we close the current segment. */
1519 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1521 /* configure the segment with the seek variables */
1522 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1523 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1524 cur_type, cur, stop_type, stop, &update)) {
1526 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1528 /* now do the seek */
1529 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1532 /* prepare for streaming again */
1534 flush_event = gst_event_new_flush_stop (TRUE);
1535 if (seqnum != GST_SEQNUM_INVALID)
1536 gst_event_set_seqnum (flush_event, seqnum);
1538 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1539 gst_qtdemux_push_event (qtdemux, flush_event);
1542 /* commit the new segment */
1543 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1545 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1546 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1547 qtdemux->segment.format, qtdemux->segment.position);
1548 if (seqnum != GST_SEQNUM_INVALID)
1549 gst_message_set_seqnum (msg, seqnum);
1550 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1553 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1554 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1555 qtdemux->sinkpad, NULL);
1557 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1564 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1570 qtdemux_ensure_index (GstQTDemux * qtdemux)
1574 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1576 /* Build complete index */
1577 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1578 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1580 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1581 GST_LOG_OBJECT (qtdemux,
1582 "Building complete index of track-id %u for seeking failed!",
1592 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1595 gboolean res = TRUE;
1596 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1598 switch (GST_EVENT_TYPE (event)) {
1599 case GST_EVENT_RECONFIGURE:
1600 GST_OBJECT_LOCK (qtdemux);
1601 gst_flow_combiner_reset (qtdemux->flowcombiner);
1602 GST_OBJECT_UNLOCK (qtdemux);
1603 res = gst_pad_event_default (pad, parent, event);
1605 case GST_EVENT_SEEK:
1607 GstSeekFlags flags = 0;
1608 gboolean instant_rate_change;
1610 #ifndef GST_DISABLE_GST_DEBUG
1611 GstClockTime ts = gst_util_get_timestamp ();
1613 guint32 seqnum = gst_event_get_seqnum (event);
1615 qtdemux->received_seek = TRUE;
1617 gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
1618 instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1620 if (seqnum == qtdemux->segment_seqnum) {
1621 GST_LOG_OBJECT (pad,
1622 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1623 gst_event_unref (event);
1627 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1628 /* seek should be handled by upstream, we might need to re-download fragments */
1629 GST_DEBUG_OBJECT (qtdemux,
1630 "let upstream handle seek for fragmented playback");
1634 gst_event_parse_seek_trickmode_interval (event,
1635 &qtdemux->trickmode_interval);
1637 /* Build complete index for seeking;
1638 * if not a fragmented file at least and we're really doing a seek,
1639 * not just an instant-rate-change */
1640 if (!qtdemux->fragmented && !instant_rate_change) {
1641 if (!qtdemux_ensure_index (qtdemux))
1644 #ifndef GST_DISABLE_GST_DEBUG
1645 ts = gst_util_get_timestamp () - ts;
1646 GST_INFO_OBJECT (qtdemux,
1647 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1649 if (qtdemux->pullbased) {
1650 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1651 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1652 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1654 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1655 && QTDEMUX_N_STREAMS (qtdemux)
1656 && !qtdemux->fragmented) {
1657 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1659 GST_DEBUG_OBJECT (qtdemux,
1660 "ignoring seek in push mode in current state");
1663 gst_event_unref (event);
1668 res = gst_pad_event_default (pad, parent, event);
1678 GST_ERROR_OBJECT (qtdemux, "Index failed");
1679 gst_event_unref (event);
1685 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1687 * If @fw is false, the coding order is explored backwards.
1689 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1690 * sample is found for that track.
1692 * The stream and sample index of the sample with the minimum offset in the direction explored
1693 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1695 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1696 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1697 * @_stream and @_index. */
1699 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1700 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1703 gint64 time, min_time;
1704 QtDemuxStream *stream;
1711 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1714 gboolean set_sample;
1716 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1723 i = str->n_samples - 1;
1727 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1728 if (str->samples[i].size == 0)
1731 if (fw && (str->samples[i].offset < byte_pos))
1734 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1737 /* move stream to first available sample */
1739 gst_qtdemux_move_stream (qtdemux, str, i);
1743 /* avoid index from sparse streams since they might be far away */
1744 if (!CUR_STREAM (str)->sparse) {
1745 /* determine min/max time */
1746 time = QTSAMPLE_PTS (str, &str->samples[i]);
1747 if (min_time == -1 || (!fw && time > min_time) ||
1748 (fw && time < min_time)) {
1752 /* determine stream with leading sample, to get its position */
1754 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1755 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1763 /* no sample for this stream, mark eos */
1765 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1776 /* Copied from mpegtsbase code */
1777 /* FIXME: replace this function when we add new util function for stream-id creation */
1779 _get_upstream_id (GstQTDemux * demux)
1781 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1784 /* Try to create one from the upstream URI, else use a randome number */
1788 /* Try to generate one from the URI query and
1789 * if it fails take a random number instead */
1790 query = gst_query_new_uri ();
1791 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1792 gst_query_parse_uri (query, &uri);
1798 /* And then generate an SHA256 sum of the URI */
1799 cs = g_checksum_new (G_CHECKSUM_SHA256);
1800 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1802 upstream_id = g_strdup (g_checksum_get_string (cs));
1803 g_checksum_free (cs);
1805 /* Just get some random number if the URI query fails */
1806 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1807 "implementing a deterministic way of creating a stream-id");
1809 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1810 g_random_int (), g_random_int ());
1813 gst_query_unref (query);
1818 static QtDemuxStream *
1819 _create_stream (GstQTDemux * demux, guint32 track_id)
1821 QtDemuxStream *stream;
1824 stream = g_new0 (QtDemuxStream, 1);
1825 stream->demux = demux;
1826 stream->track_id = track_id;
1827 upstream_id = _get_upstream_id (demux);
1828 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1829 g_free (upstream_id);
1830 /* new streams always need a discont */
1831 stream->discont = TRUE;
1832 /* we enable clipping for raw audio/video streams */
1833 stream->need_clip = FALSE;
1834 stream->need_process = FALSE;
1835 stream->segment_index = -1;
1836 stream->time_position = 0;
1837 stream->sample_index = -1;
1838 stream->offset_in_sample = 0;
1839 stream->new_stream = TRUE;
1840 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1841 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1842 stream->protected = FALSE;
1843 stream->protection_scheme_type = 0;
1844 stream->protection_scheme_version = 0;
1845 stream->protection_scheme_info = NULL;
1846 stream->n_samples_moof = 0;
1847 stream->duration_moof = 0;
1848 stream->duration_last_moof = 0;
1849 stream->alignment = 1;
1850 stream->stream_tags = gst_tag_list_new_empty ();
1851 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1852 g_queue_init (&stream->protection_scheme_event_queue);
1853 stream->ref_count = 1;
1854 /* consistent default for push based mode */
1855 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1860 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1862 GstStructure *structure;
1863 const gchar *variant;
1864 const GstCaps *mediacaps = NULL;
1866 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1868 structure = gst_caps_get_structure (caps, 0);
1869 variant = gst_structure_get_string (structure, "variant");
1871 if (variant && strcmp (variant, "mss-fragmented") == 0) {
1872 QtDemuxStream *stream;
1873 const GValue *value;
1875 demux->fragmented = TRUE;
1876 demux->mss_mode = TRUE;
1878 if (QTDEMUX_N_STREAMS (demux) > 1) {
1879 /* can't do this, we can only renegotiate for another mss format */
1883 value = gst_structure_get_value (structure, "media-caps");
1886 const GValue *timescale_v;
1888 /* TODO update when stream changes during playback */
1890 if (QTDEMUX_N_STREAMS (demux) == 0) {
1891 stream = _create_stream (demux, 1);
1892 g_ptr_array_add (demux->active_streams, stream);
1893 /* mss has no stsd/stsd entry, use id 0 as default */
1894 stream->stsd_entries_length = 1;
1895 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
1896 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
1898 stream = QTDEMUX_NTH_STREAM (demux, 0);
1901 timescale_v = gst_structure_get_value (structure, "timescale");
1903 stream->timescale = g_value_get_uint64 (timescale_v);
1905 /* default mss timescale */
1906 stream->timescale = 10000000;
1908 demux->timescale = stream->timescale;
1910 mediacaps = gst_value_get_caps (value);
1911 if (!CUR_STREAM (stream)->caps
1912 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
1913 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1915 stream->new_caps = TRUE;
1917 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
1918 structure = gst_caps_get_structure (mediacaps, 0);
1919 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1920 stream->subtype = FOURCC_vide;
1922 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
1923 gst_structure_get_int (structure, "height",
1924 &CUR_STREAM (stream)->height);
1925 gst_structure_get_fraction (structure, "framerate",
1926 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
1927 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1929 stream->subtype = FOURCC_soun;
1930 gst_structure_get_int (structure, "channels",
1931 &CUR_STREAM (stream)->n_channels);
1932 gst_structure_get_int (structure, "rate", &rate);
1933 CUR_STREAM (stream)->rate = rate;
1934 } else if (gst_structure_has_name (structure, "application/x-cenc")) {
1935 if (gst_structure_has_field (structure, "original-media-type")) {
1936 const gchar *media_type =
1937 gst_structure_get_string (structure, "original-media-type");
1938 if (g_str_has_prefix (media_type, "video")) {
1939 stream->subtype = FOURCC_vide;
1940 } else if (g_str_has_prefix (media_type, "audio")) {
1941 stream->subtype = FOURCC_soun;
1946 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1948 demux->mss_mode = FALSE;
1955 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1959 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1960 gst_pad_stop_task (qtdemux->sinkpad);
1962 if (hard || qtdemux->upstream_format_is_time) {
1963 qtdemux->state = QTDEMUX_STATE_INITIAL;
1964 qtdemux->neededbytes = 16;
1965 qtdemux->todrop = 0;
1966 qtdemux->pullbased = FALSE;
1967 g_clear_pointer (&qtdemux->redirect_location, g_free);
1968 qtdemux->first_mdat = -1;
1969 qtdemux->header_size = 0;
1970 qtdemux->mdatoffset = -1;
1971 qtdemux->restoredata_offset = -1;
1972 if (qtdemux->mdatbuffer)
1973 gst_buffer_unref (qtdemux->mdatbuffer);
1974 if (qtdemux->restoredata_buffer)
1975 gst_buffer_unref (qtdemux->restoredata_buffer);
1976 qtdemux->mdatbuffer = NULL;
1977 qtdemux->restoredata_buffer = NULL;
1978 qtdemux->mdatleft = 0;
1979 qtdemux->mdatsize = 0;
1980 if (qtdemux->comp_brands)
1981 gst_buffer_unref (qtdemux->comp_brands);
1982 qtdemux->comp_brands = NULL;
1983 qtdemux->last_moov_offset = -1;
1984 if (qtdemux->moov_node_compressed) {
1985 g_node_destroy (qtdemux->moov_node_compressed);
1986 if (qtdemux->moov_node)
1987 g_free (qtdemux->moov_node->data);
1989 qtdemux->moov_node_compressed = NULL;
1990 if (qtdemux->moov_node)
1991 g_node_destroy (qtdemux->moov_node);
1992 qtdemux->moov_node = NULL;
1993 if (qtdemux->tag_list)
1994 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1995 qtdemux->tag_list = gst_tag_list_new_empty ();
1996 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
1998 if (qtdemux->element_index)
1999 gst_object_unref (qtdemux->element_index);
2000 qtdemux->element_index = NULL;
2002 qtdemux->major_brand = 0;
2003 qtdemux->upstream_format_is_time = FALSE;
2004 qtdemux->upstream_seekable = FALSE;
2005 qtdemux->upstream_size = 0;
2007 qtdemux->fragment_start = -1;
2008 qtdemux->fragment_start_offset = -1;
2009 qtdemux->duration = 0;
2010 qtdemux->moof_offset = 0;
2011 qtdemux->chapters_track_id = 0;
2012 qtdemux->have_group_id = FALSE;
2013 qtdemux->group_id = G_MAXUINT;
2015 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2017 g_queue_clear (&qtdemux->protection_event_queue);
2019 qtdemux->received_seek = FALSE;
2020 qtdemux->first_moof_already_parsed = FALSE;
2022 qtdemux->offset = 0;
2023 gst_adapter_clear (qtdemux->adapter);
2024 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2025 qtdemux->need_segment = TRUE;
2028 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2029 qtdemux->trickmode_interval = 0;
2030 g_ptr_array_set_size (qtdemux->active_streams, 0);
2031 g_ptr_array_set_size (qtdemux->old_streams, 0);
2032 qtdemux->n_video_streams = 0;
2033 qtdemux->n_audio_streams = 0;
2034 qtdemux->n_sub_streams = 0;
2035 qtdemux->exposed = FALSE;
2036 qtdemux->fragmented = FALSE;
2037 qtdemux->mss_mode = FALSE;
2038 gst_caps_replace (&qtdemux->media_caps, NULL);
2039 qtdemux->timescale = 0;
2040 qtdemux->got_moov = FALSE;
2041 qtdemux->cenc_aux_info_offset = 0;
2042 qtdemux->cenc_aux_info_sizes = NULL;
2043 qtdemux->cenc_aux_sample_count = 0;
2044 if (qtdemux->protection_system_ids) {
2045 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2046 qtdemux->protection_system_ids = NULL;
2048 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2049 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2050 GST_BIN_FLAG_STREAMS_AWARE);
2052 if (qtdemux->preferred_protection_system_id) {
2053 g_free (qtdemux->preferred_protection_system_id);
2054 qtdemux->preferred_protection_system_id = NULL;
2056 } else if (qtdemux->mss_mode) {
2057 gst_flow_combiner_reset (qtdemux->flowcombiner);
2058 g_ptr_array_foreach (qtdemux->active_streams,
2059 (GFunc) gst_qtdemux_stream_clear, NULL);
2061 gst_flow_combiner_reset (qtdemux->flowcombiner);
2062 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2063 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2064 stream->sent_eos = FALSE;
2065 stream->time_position = 0;
2066 stream->accumulated_base = 0;
2067 stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2073 /* Maps the @segment to the qt edts internal segments and pushes
2074 * the corresponding segment event.
2076 * If it ends up being at a empty segment, a gap will be pushed and the next
2077 * edts segment will be activated in sequence.
2079 * To be used in push-mode only */
2081 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2085 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2086 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2088 stream->time_position = segment->start;
2090 /* in push mode we should be guaranteed that we will have empty segments
2091 * at the beginning and then one segment after, other scenarios are not
2092 * supported and are discarded when parsing the edts */
2093 for (i = 0; i < stream->n_segments; i++) {
2094 if (stream->segments[i].stop_time > segment->start) {
2095 /* push the empty segment and move to the next one */
2096 gst_qtdemux_activate_segment (qtdemux, stream, i,
2097 stream->time_position);
2098 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2099 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2100 stream->time_position);
2102 /* accumulate previous segments */
2103 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2104 stream->accumulated_base +=
2105 (stream->segment.stop -
2106 stream->segment.start) / ABS (stream->segment.rate);
2110 g_assert (i == stream->n_segments - 1);
2117 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2128 for (i = 0; i < len; i++) {
2129 QtDemuxStream *stream = g_ptr_array_index (src, i);
2131 #ifndef GST_DISABLE_GST_DEBUG
2132 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2133 stream, GST_STR_NULL (stream->stream_id), dest);
2135 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2138 g_ptr_array_set_size (src, 0);
2142 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2145 GstQTDemux *demux = GST_QTDEMUX (parent);
2146 gboolean res = TRUE;
2148 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2150 switch (GST_EVENT_TYPE (event)) {
2151 case GST_EVENT_SEGMENT:
2154 QtDemuxStream *stream;
2158 /* some debug output */
2159 gst_event_copy_segment (event, &segment);
2160 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2163 if (segment.format == GST_FORMAT_TIME) {
2164 demux->upstream_format_is_time = TRUE;
2165 demux->segment_seqnum = gst_event_get_seqnum (event);
2167 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2168 "not in time format");
2170 /* chain will send initial newsegment after pads have been added */
2171 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2172 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2177 /* check if this matches a time seek we received previously
2178 * FIXME for backwards compatibility reasons we use the
2179 * seek_offset here to compare. In the future we might want to
2180 * change this to use the seqnum as it uniquely should identify
2181 * the segment that corresponds to the seek. */
2182 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2183 ", received segment offset %" G_GINT64_FORMAT,
2184 demux->seek_offset, segment.start);
2185 if (segment.format == GST_FORMAT_BYTES
2186 && demux->seek_offset == segment.start) {
2187 GST_OBJECT_LOCK (demux);
2188 offset = segment.start;
2190 segment.format = GST_FORMAT_TIME;
2191 segment.start = demux->push_seek_start;
2192 segment.stop = demux->push_seek_stop;
2193 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2194 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2195 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2196 GST_OBJECT_UNLOCK (demux);
2199 /* we only expect a BYTE segment, e.g. following a seek */
2200 if (segment.format == GST_FORMAT_BYTES) {
2201 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2202 offset = segment.start;
2204 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2205 NULL, (gint64 *) & segment.start);
2206 if ((gint64) segment.start < 0)
2209 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2210 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2211 NULL, (gint64 *) & segment.stop);
2212 /* keyframe seeking should already arrange for start >= stop,
2213 * but make sure in other rare cases */
2214 segment.stop = MAX (segment.stop, segment.start);
2216 } else if (segment.format == GST_FORMAT_TIME) {
2217 /* push all data on the adapter before starting this
2219 gst_qtdemux_process_adapter (demux, TRUE);
2221 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2225 /* We shouldn't modify upstream driven TIME FORMAT segment */
2226 if (!demux->upstream_format_is_time) {
2227 /* accept upstream's notion of segment and distribute along */
2228 segment.format = GST_FORMAT_TIME;
2229 segment.position = segment.time = segment.start;
2230 segment.duration = demux->segment.duration;
2231 segment.base = gst_segment_to_running_time (&demux->segment,
2232 GST_FORMAT_TIME, demux->segment.position);
2235 gst_segment_copy_into (&segment, &demux->segment);
2236 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2238 /* map segment to internal qt segments and push on each stream */
2239 if (QTDEMUX_N_STREAMS (demux)) {
2240 demux->need_segment = TRUE;
2241 gst_qtdemux_check_send_pending_segment (demux);
2244 /* clear leftover in current segment, if any */
2245 gst_adapter_clear (demux->adapter);
2247 /* set up streaming thread */
2248 demux->offset = offset;
2249 if (demux->upstream_format_is_time) {
2250 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2251 "set values to restart reading from a new atom");
2252 demux->neededbytes = 16;
2255 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2258 demux->todrop = stream->samples[idx].offset - offset;
2259 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2261 /* set up for EOS */
2262 demux->neededbytes = -1;
2267 gst_event_unref (event);
2271 case GST_EVENT_FLUSH_START:
2273 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2274 gst_event_unref (event);
2277 QTDEMUX_EXPOSE_LOCK (demux);
2278 res = gst_pad_event_default (demux->sinkpad, parent, event);
2279 QTDEMUX_EXPOSE_UNLOCK (demux);
2282 case GST_EVENT_FLUSH_STOP:
2286 dur = demux->segment.duration;
2287 gst_qtdemux_reset (demux, FALSE);
2288 demux->segment.duration = dur;
2290 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2291 gst_event_unref (event);
2297 /* If we are in push mode, and get an EOS before we've seen any streams,
2298 * then error out - we have nowhere to send the EOS */
2299 if (!demux->pullbased) {
2301 gboolean has_valid_stream = FALSE;
2302 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2303 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2304 has_valid_stream = TRUE;
2308 if (!has_valid_stream)
2309 gst_qtdemux_post_no_playable_stream_error (demux);
2311 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2312 (guint) gst_adapter_available (demux->adapter));
2313 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2319 case GST_EVENT_CAPS:{
2320 GstCaps *caps = NULL;
2322 gst_event_parse_caps (event, &caps);
2323 gst_qtdemux_setcaps (demux, caps);
2325 gst_event_unref (event);
2328 case GST_EVENT_PROTECTION:
2330 const gchar *system_id = NULL;
2332 gst_event_parse_protection (event, &system_id, NULL, NULL);
2333 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2335 gst_qtdemux_append_protection_system_id (demux, system_id);
2336 /* save the event for later, for source pads that have not been created */
2337 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2338 /* send it to all pads that already exist */
2339 gst_qtdemux_push_event (demux, event);
2343 case GST_EVENT_STREAM_START:
2346 gst_event_unref (event);
2348 /* Drain all the buffers */
2349 gst_qtdemux_process_adapter (demux, TRUE);
2350 gst_qtdemux_reset (demux, FALSE);
2351 /* We expect new moov box after new stream-start event */
2352 if (demux->exposed) {
2353 gst_qtdemux_stream_concat (demux,
2354 demux->old_streams, demux->active_streams);
2363 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2370 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2373 GstQTDemux *demux = GST_QTDEMUX (parent);
2374 gboolean res = FALSE;
2376 switch (GST_QUERY_TYPE (query)) {
2377 case GST_QUERY_BITRATE:
2379 GstClockTime duration;
2381 /* populate demux->upstream_size if not done yet */
2382 gst_qtdemux_check_seekability (demux);
2384 if (demux->upstream_size != -1
2385 && gst_qtdemux_get_duration (demux, &duration)) {
2387 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2390 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2391 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2392 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2394 /* TODO: better results based on ranges/index tables */
2395 gst_query_set_bitrate (query, bitrate);
2401 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2411 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2413 GstQTDemux *demux = GST_QTDEMUX (element);
2415 GST_OBJECT_LOCK (demux);
2416 if (demux->element_index)
2417 gst_object_unref (demux->element_index);
2419 demux->element_index = gst_object_ref (index);
2421 demux->element_index = NULL;
2423 GST_OBJECT_UNLOCK (demux);
2424 /* object lock might be taken again */
2426 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2427 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2428 demux->element_index, demux->index_id);
2432 gst_qtdemux_get_index (GstElement * element)
2434 GstIndex *result = NULL;
2435 GstQTDemux *demux = GST_QTDEMUX (element);
2437 GST_OBJECT_LOCK (demux);
2438 if (demux->element_index)
2439 result = gst_object_ref (demux->element_index);
2440 GST_OBJECT_UNLOCK (demux);
2442 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2449 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2451 g_free ((gpointer) stream->stco.data);
2452 stream->stco.data = NULL;
2453 g_free ((gpointer) stream->stsz.data);
2454 stream->stsz.data = NULL;
2455 g_free ((gpointer) stream->stsc.data);
2456 stream->stsc.data = NULL;
2457 g_free ((gpointer) stream->stts.data);
2458 stream->stts.data = NULL;
2459 g_free ((gpointer) stream->stss.data);
2460 stream->stss.data = NULL;
2461 g_free ((gpointer) stream->stps.data);
2462 stream->stps.data = NULL;
2463 g_free ((gpointer) stream->ctts.data);
2464 stream->ctts.data = NULL;
2468 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2470 g_free (stream->segments);
2471 stream->segments = NULL;
2472 stream->segment_index = -1;
2473 stream->accumulated_base = 0;
2477 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2479 g_free (stream->samples);
2480 stream->samples = NULL;
2481 gst_qtdemux_stbl_free (stream);
2484 g_free (stream->ra_entries);
2485 stream->ra_entries = NULL;
2486 stream->n_ra_entries = 0;
2488 stream->sample_index = -1;
2489 stream->stbl_index = -1;
2490 stream->n_samples = 0;
2491 stream->time_position = 0;
2493 stream->n_samples_moof = 0;
2494 stream->duration_moof = 0;
2495 stream->duration_last_moof = 0;
2499 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2502 if (stream->allocator)
2503 gst_object_unref (stream->allocator);
2504 while (stream->buffers) {
2505 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2506 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2508 for (i = 0; i < stream->stsd_entries_length; i++) {
2509 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2510 if (entry->rgb8_palette) {
2511 gst_memory_unref (entry->rgb8_palette);
2512 entry->rgb8_palette = NULL;
2514 entry->sparse = FALSE;
2517 if (stream->stream_tags)
2518 gst_tag_list_unref (stream->stream_tags);
2520 stream->stream_tags = gst_tag_list_new_empty ();
2521 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2522 g_free (stream->redirect_uri);
2523 stream->redirect_uri = NULL;
2524 stream->sent_eos = FALSE;
2525 stream->protected = FALSE;
2526 if (stream->protection_scheme_info) {
2527 if (stream->protection_scheme_type == FOURCC_cenc) {
2528 QtDemuxCencSampleSetInfo *info =
2529 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2530 if (info->default_properties)
2531 gst_structure_free (info->default_properties);
2532 if (info->crypto_info)
2533 g_ptr_array_free (info->crypto_info, TRUE);
2535 if (stream->protection_scheme_type == FOURCC_aavd) {
2536 QtDemuxAavdEncryptionInfo *info =
2537 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2538 if (info->default_properties)
2539 gst_structure_free (info->default_properties);
2541 g_free (stream->protection_scheme_info);
2542 stream->protection_scheme_info = NULL;
2544 stream->protection_scheme_type = 0;
2545 stream->protection_scheme_version = 0;
2546 g_queue_foreach (&stream->protection_scheme_event_queue,
2547 (GFunc) gst_event_unref, NULL);
2548 g_queue_clear (&stream->protection_scheme_event_queue);
2549 gst_qtdemux_stream_flush_segments_data (stream);
2550 gst_qtdemux_stream_flush_samples_data (stream);
2554 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2557 gst_qtdemux_stream_clear (stream);
2558 for (i = 0; i < stream->stsd_entries_length; i++) {
2559 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2561 gst_caps_unref (entry->caps);
2565 g_free (stream->stsd_entries);
2566 stream->stsd_entries = NULL;
2567 stream->stsd_entries_length = 0;
2570 static QtDemuxStream *
2571 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2573 g_atomic_int_add (&stream->ref_count, 1);
2579 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2581 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2582 gst_qtdemux_stream_reset (stream);
2583 gst_tag_list_unref (stream->stream_tags);
2585 GstQTDemux *demux = stream->demux;
2586 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2587 GST_OBJECT_LOCK (demux);
2588 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2589 GST_OBJECT_UNLOCK (demux);
2591 g_free (stream->stream_id);
2596 static GstStateChangeReturn
2597 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2599 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2600 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2602 switch (transition) {
2603 case GST_STATE_CHANGE_READY_TO_PAUSED:
2604 gst_qtdemux_reset (qtdemux, TRUE);
2610 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2612 switch (transition) {
2613 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2614 gst_qtdemux_reset (qtdemux, TRUE);
2625 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2627 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2629 g_return_if_fail (GST_IS_CONTEXT (context));
2631 if (gst_context_has_context_type (context,
2632 "drm-preferred-decryption-system-id")) {
2633 const GstStructure *s;
2635 s = gst_context_get_structure (context);
2636 g_free (qtdemux->preferred_protection_system_id);
2637 qtdemux->preferred_protection_system_id =
2638 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2639 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2640 qtdemux->preferred_protection_system_id);
2643 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2647 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2649 /* counts as header data */
2650 qtdemux->header_size += length;
2652 /* only consider at least a sufficiently complete ftyp atom */
2656 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2657 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2658 GST_FOURCC_ARGS (qtdemux->major_brand));
2659 if (qtdemux->comp_brands)
2660 gst_buffer_unref (qtdemux->comp_brands);
2661 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2662 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2667 qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
2668 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
2671 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2672 gst_buffer_fill (kid_buf, 0, kid, 16);
2673 if (info->default_properties)
2674 gst_structure_free (info->default_properties);
2675 info->default_properties =
2676 gst_structure_new ("application/x-cenc",
2677 "iv_size", G_TYPE_UINT, iv_size,
2678 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2679 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2680 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2681 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2682 gst_buffer_unref (kid_buf);
2686 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2687 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2689 guint32 algorithm_id = 0;
2691 gboolean is_encrypted = TRUE;
2694 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2695 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2700 if (algorithm_id == 0) {
2701 is_encrypted = FALSE;
2702 } else if (algorithm_id == 1) {
2703 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2704 } else if (algorithm_id == 2) {
2705 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2708 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2711 if (!gst_byte_reader_get_data (br, 16, &kid))
2714 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
2715 is_encrypted, iv_size, kid);
2716 gst_structure_set (info->default_properties, "piff_algorithm_id",
2717 G_TYPE_UINT, algorithm_id, NULL);
2723 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2731 QtDemuxStream *stream;
2732 GstStructure *structure;
2733 QtDemuxCencSampleSetInfo *ss_info = NULL;
2734 const gchar *system_id;
2735 gboolean uses_sub_sample_encryption = FALSE;
2736 guint32 sample_count;
2738 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2741 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2743 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2744 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2745 GST_WARNING_OBJECT (qtdemux,
2746 "Attempting PIFF box parsing on an unencrypted stream.");
2750 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2751 G_TYPE_STRING, &system_id, NULL);
2752 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2754 stream->protected = TRUE;
2755 stream->protection_scheme_type = FOURCC_cenc;
2757 if (!stream->protection_scheme_info)
2758 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2760 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2761 if (!ss_info->default_properties) {
2762 ss_info->default_properties =
2763 gst_structure_new ("application/x-cenc",
2764 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2769 if (ss_info->crypto_info) {
2770 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2771 g_ptr_array_free (ss_info->crypto_info, TRUE);
2772 ss_info->crypto_info = NULL;
2776 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2778 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2779 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2783 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2784 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2788 if ((flags & 0x000001)) {
2789 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2792 } else if ((flags & 0x000002)) {
2793 uses_sub_sample_encryption = TRUE;
2796 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2798 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2802 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2803 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2807 ss_info->crypto_info =
2808 g_ptr_array_new_full (sample_count,
2809 (GDestroyNotify) qtdemux_gst_structure_free);
2811 for (i = 0; i < sample_count; ++i) {
2812 GstStructure *properties;
2816 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2817 if (properties == NULL) {
2818 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2819 qtdemux->cenc_aux_sample_count = i;
2823 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2824 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2825 gst_structure_free (properties);
2826 qtdemux->cenc_aux_sample_count = i;
2829 buf = gst_buffer_new_wrapped (data, iv_size);
2830 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2831 gst_buffer_unref (buf);
2833 if (uses_sub_sample_encryption) {
2834 guint16 n_subsamples;
2835 const GValue *kid_buf_value;
2837 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2838 || n_subsamples == 0) {
2839 GST_ERROR_OBJECT (qtdemux,
2840 "failed to get subsample count for sample %u", i);
2841 gst_structure_free (properties);
2842 qtdemux->cenc_aux_sample_count = i;
2845 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2846 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2847 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2849 gst_structure_free (properties);
2850 qtdemux->cenc_aux_sample_count = i;
2853 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2856 gst_structure_get_value (ss_info->default_properties, "kid");
2858 gst_structure_set (properties,
2859 "subsample_count", G_TYPE_UINT, n_subsamples,
2860 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2861 gst_structure_set_value (properties, "kid", kid_buf_value);
2862 gst_buffer_unref (buf);
2864 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2867 g_ptr_array_add (ss_info->crypto_info, properties);
2870 qtdemux->cenc_aux_sample_count = sample_count;
2874 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2876 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2877 0x97, 0xA9, 0x42, 0xE8,
2878 0x9C, 0x71, 0x99, 0x94,
2879 0x91, 0xE3, 0xAF, 0xAC
2881 static const guint8 playready_uuid[] = {
2882 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2883 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2886 static const guint8 piff_sample_encryption_uuid[] = {
2887 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2888 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2893 /* counts as header data */
2894 qtdemux->header_size += length;
2896 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2898 if (length <= offset + 16) {
2899 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2903 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2905 GstTagList *taglist;
2907 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2908 length - offset - 16, NULL);
2909 taglist = gst_tag_list_from_xmp_buffer (buf);
2910 gst_buffer_unref (buf);
2912 /* make sure we have a usable taglist */
2913 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2915 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2917 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2919 const gunichar2 *s_utf16;
2922 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2923 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2924 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2925 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2929 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2930 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2932 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2933 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2935 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2936 GST_READ_UINT32_LE (buffer + offset),
2937 GST_READ_UINT32_LE (buffer + offset + 4),
2938 GST_READ_UINT32_LE (buffer + offset + 8),
2939 GST_READ_UINT32_LE (buffer + offset + 12));
2944 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2946 GstSidxParser sidx_parser;
2947 GstIsoffParserResult res;
2950 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2953 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2955 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2956 if (res == GST_ISOFF_QT_PARSER_DONE) {
2957 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
2959 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
2962 /* caller verifies at least 8 bytes in buf */
2964 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2965 guint64 * plength, guint32 * pfourcc)
2970 length = QT_UINT32 (data);
2971 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2972 fourcc = QT_FOURCC (data + 4);
2973 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2976 length = G_MAXUINT64;
2977 } else if (length == 1 && size >= 16) {
2978 /* this means we have an extended size, which is the 64 bit value of
2979 * the next 8 bytes */
2980 length = QT_UINT64 (data + 8);
2981 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2991 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2993 guint32 version = 0;
2994 GstClockTime duration = 0;
2996 if (!gst_byte_reader_get_uint32_be (br, &version))
3001 if (!gst_byte_reader_get_uint64_be (br, &duration))
3006 if (!gst_byte_reader_get_uint32_be (br, &dur))
3011 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3012 qtdemux->duration = duration;
3018 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3024 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3025 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3027 if (!stream->parsed_trex && qtdemux->moov_node) {
3029 GstByteReader trex_data;
3031 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3033 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3036 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3038 /* skip version/flags */
3039 if (!gst_byte_reader_skip (&trex_data, 4))
3041 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3043 if (id != stream->track_id)
3045 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3047 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3049 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3051 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3054 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3055 "duration %d, size %d, flags 0x%x", stream->track_id,
3058 stream->parsed_trex = TRUE;
3059 stream->def_sample_description_index = sdi;
3060 stream->def_sample_duration = dur;
3061 stream->def_sample_size = size;
3062 stream->def_sample_flags = flags;
3065 /* iterate all siblings */
3066 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3072 *ds_duration = stream->def_sample_duration;
3073 *ds_size = stream->def_sample_size;
3074 *ds_flags = stream->def_sample_flags;
3076 /* even then, above values are better than random ... */
3077 if (G_UNLIKELY (!stream->parsed_trex)) {
3078 GST_WARNING_OBJECT (qtdemux,
3079 "failed to find fragment defaults for stream %d", stream->track_id);
3086 /* This method should be called whenever a more accurate duration might
3087 * have been found. It will update all relevant variables if/where needed
3090 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3094 GstClockTime prevdur;
3096 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3098 if (movdur > qtdemux->duration) {
3099 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3100 GST_DEBUG_OBJECT (qtdemux,
3101 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3102 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3103 qtdemux->duration = movdur;
3104 GST_DEBUG_OBJECT (qtdemux,
3105 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3106 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3107 GST_TIME_ARGS (qtdemux->segment.stop));
3108 if (qtdemux->segment.duration == prevdur) {
3109 /* If the current segment has duration/stop identical to previous duration
3110 * update them also (because they were set at that point in time with
3111 * the wrong duration */
3112 /* We convert the value *from* the timescale version to avoid rounding errors */
3113 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3114 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3115 qtdemux->segment.duration = fixeddur;
3116 qtdemux->segment.stop = fixeddur;
3120 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3121 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3123 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3124 if (movdur > stream->duration) {
3125 GST_DEBUG_OBJECT (qtdemux,
3126 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3127 GST_TIME_ARGS (duration));
3128 stream->duration = movdur;
3129 /* internal duration tracking state has been updated above, so */
3130 /* preserve an open-ended dummy segment rather than repeatedly updating
3131 * it and spamming downstream accordingly with segment events */
3132 /* also mangle the edit list end time when fragmented with a single edit
3133 * list that may only cover any non-fragmented data */
3134 if ((stream->dummy_segment ||
3135 (qtdemux->fragmented && stream->n_segments == 1)) &&
3136 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3137 /* Update all dummy values to new duration */
3138 stream->segments[0].stop_time = duration;
3139 stream->segments[0].duration = duration;
3140 stream->segments[0].media_stop = duration;
3142 /* let downstream know we possibly have a new stop time */
3143 if (stream->segment_index != -1) {
3146 if (qtdemux->segment.rate >= 0) {
3147 pos = stream->segment.start;
3149 pos = stream->segment.stop;
3152 gst_qtdemux_stream_update_segment (qtdemux, stream,
3153 stream->segment_index, pos, NULL, NULL);
3161 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3162 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3163 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3164 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3167 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3169 gint32 data_offset = 0;
3170 guint32 flags = 0, first_flags = 0, samples_count = 0;
3173 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3174 QtDemuxSample *sample;
3175 gboolean ismv = FALSE;
3176 gint64 initial_offset;
3178 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3179 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3180 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3181 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3183 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3184 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3188 /* presence of stss or not can't really tell us much,
3189 * and flags and so on tend to be marginally reliable in these files */
3190 if (stream->subtype == FOURCC_soun) {
3191 GST_DEBUG_OBJECT (qtdemux,
3192 "sound track in fragmented file; marking all keyframes");
3193 stream->all_keyframe = TRUE;
3196 if (!gst_byte_reader_skip (trun, 1) ||
3197 !gst_byte_reader_get_uint24_be (trun, &flags))
3200 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3203 if (flags & TR_DATA_OFFSET) {
3204 /* note this is really signed */
3205 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3207 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3208 /* default base offset = first byte of moof */
3209 if (*base_offset == -1) {
3210 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3211 *base_offset = moof_offset;
3213 *running_offset = *base_offset + data_offset;
3215 /* if no offset at all, that would mean data starts at moof start,
3216 * which is a bit wrong and is ismv crappy way, so compensate
3217 * assuming data is in mdat following moof */
3218 if (*base_offset == -1) {
3219 *base_offset = moof_offset + moof_length + 8;
3220 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3223 if (*running_offset == -1)
3224 *running_offset = *base_offset;
3227 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3229 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3230 data_offset, flags, samples_count);
3232 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3233 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3234 GST_DEBUG_OBJECT (qtdemux,
3235 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3236 flags ^= TR_FIRST_SAMPLE_FLAGS;
3238 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3240 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3244 /* FIXME ? spec says other bits should also be checked to determine
3245 * entry size (and prefix size for that matter) */
3247 dur_offset = size_offset = 0;
3248 if (flags & TR_SAMPLE_DURATION) {
3249 GST_LOG_OBJECT (qtdemux, "entry duration present");
3250 dur_offset = entry_size;
3253 if (flags & TR_SAMPLE_SIZE) {
3254 GST_LOG_OBJECT (qtdemux, "entry size present");
3255 size_offset = entry_size;
3258 if (flags & TR_SAMPLE_FLAGS) {
3259 GST_LOG_OBJECT (qtdemux, "entry flags present");
3260 flags_offset = entry_size;
3263 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3264 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3265 ct_offset = entry_size;
3269 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3271 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3273 if (stream->n_samples + samples_count >=
3274 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3277 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3278 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3279 (stream->n_samples + samples_count) *
3280 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3282 /* create a new array of samples if it's the first sample parsed */
3283 if (stream->n_samples == 0) {
3284 g_assert (stream->samples == NULL);
3285 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3286 /* or try to reallocate it with space enough to insert the new samples */
3288 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3289 stream->n_samples + samples_count);
3290 if (stream->samples == NULL)
3293 if (qtdemux->fragment_start != -1) {
3294 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3295 qtdemux->fragment_start = -1;
3297 if (stream->n_samples == 0) {
3298 if (decode_ts > 0) {
3299 timestamp = decode_ts;
3300 } else if (stream->pending_seek != NULL) {
3301 /* if we don't have a timestamp from a tfdt box, we'll use the one
3302 * from the mfra seek table */
3303 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3304 GST_TIME_ARGS (stream->pending_seek->ts));
3306 /* FIXME: this is not fully correct, the timestamp refers to the random
3307 * access sample refered to in the tfra entry, which may not necessarily
3308 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3309 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3314 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3315 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3316 GST_TIME_ARGS (gst_ts));
3318 /* subsequent fragments extend stream */
3320 stream->samples[stream->n_samples - 1].timestamp +
3321 stream->samples[stream->n_samples - 1].duration;
3323 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3324 * difference (1 sec.) between decode_ts and timestamp, prefer the
3326 if (has_tfdt && !qtdemux->upstream_format_is_time
3327 && ABSDIFF (decode_ts, timestamp) >
3328 MAX (stream->duration_last_moof / 2,
3329 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3330 GST_INFO_OBJECT (qtdemux,
3331 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3332 ") are significantly different (more than %" GST_TIME_FORMAT
3333 "), using decode_ts",
3334 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3335 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3336 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3337 MAX (stream->duration_last_moof / 2,
3338 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3339 timestamp = decode_ts;
3342 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3343 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3344 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3348 initial_offset = *running_offset;
3350 sample = stream->samples + stream->n_samples;
3351 for (i = 0; i < samples_count; i++) {
3352 guint32 dur, size, sflags, ct;
3354 /* first read sample data */
3355 if (flags & TR_SAMPLE_DURATION) {
3356 dur = QT_UINT32 (data + dur_offset);
3358 dur = d_sample_duration;
3360 if (flags & TR_SAMPLE_SIZE) {
3361 size = QT_UINT32 (data + size_offset);
3363 size = d_sample_size;
3365 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3367 sflags = first_flags;
3369 sflags = d_sample_flags;
3371 } else if (flags & TR_SAMPLE_FLAGS) {
3372 sflags = QT_UINT32 (data + flags_offset);
3374 sflags = d_sample_flags;
3376 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3377 ct = QT_UINT32 (data + ct_offset);
3383 /* fill the sample information */
3384 sample->offset = *running_offset;
3385 sample->pts_offset = ct;
3386 sample->size = size;
3387 sample->timestamp = timestamp;
3388 sample->duration = dur;
3389 /* sample-is-difference-sample */
3390 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3391 * now idea how it relates to bitfield other than massive LE/BE confusion */
3392 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3393 *running_offset += size;
3395 stream->duration_moof += dur;
3399 /* Update total duration if needed */
3400 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3402 /* Pre-emptively figure out size of mdat based on trun information.
3403 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3404 * size, else we will still be able to use this when dealing with gap'ed
3406 qtdemux->mdatleft = *running_offset - initial_offset;
3407 qtdemux->mdatoffset = initial_offset;
3408 qtdemux->mdatsize = qtdemux->mdatleft;
3410 stream->n_samples += samples_count;
3411 stream->n_samples_moof += samples_count;
3413 if (stream->pending_seek != NULL)
3414 stream->pending_seek = NULL;
3420 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3425 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3431 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3432 "be larger than %uMB (broken file?)", stream->n_samples,
3433 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3438 /* find stream with @id */
3439 static inline QtDemuxStream *
3440 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3442 QtDemuxStream *stream;
3446 if (G_UNLIKELY (!id)) {
3447 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3451 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3452 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3453 if (stream->track_id == id)
3456 if (qtdemux->mss_mode) {
3457 /* mss should have only 1 stream anyway */
3458 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3465 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3466 guint32 * fragment_number)
3468 if (!gst_byte_reader_skip (mfhd, 4))
3470 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3475 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3481 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3482 QtDemuxStream ** stream, guint32 * default_sample_duration,
3483 guint32 * default_sample_size, guint32 * default_sample_flags,
3484 gint64 * base_offset)
3487 guint32 track_id = 0;
3489 if (!gst_byte_reader_skip (tfhd, 1) ||
3490 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3493 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3496 *stream = qtdemux_find_stream (qtdemux, track_id);
3497 if (G_UNLIKELY (!*stream))
3498 goto unknown_stream;
3500 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3501 *base_offset = qtdemux->moof_offset;
3503 if (flags & TF_BASE_DATA_OFFSET)
3504 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3507 /* obtain stream defaults */
3508 qtdemux_parse_trex (qtdemux, *stream,
3509 default_sample_duration, default_sample_size, default_sample_flags);
3511 (*stream)->stsd_sample_description_id =
3512 (*stream)->def_sample_description_index - 1;
3514 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3515 guint32 sample_description_index;
3516 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3518 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3521 if (qtdemux->mss_mode) {
3522 /* mss has no stsd entry */
3523 (*stream)->stsd_sample_description_id = 0;
3526 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3527 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3530 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3531 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3534 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3535 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3542 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3547 GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
3553 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3554 guint64 * decode_time)
3556 guint32 version = 0;
3558 if (!gst_byte_reader_get_uint32_be (br, &version))
3563 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3566 guint32 dec_time = 0;
3567 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3569 *decode_time = dec_time;
3572 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3579 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3584 /* Returns a pointer to a GstStructure containing the properties of
3585 * the stream sample identified by @sample_index. The caller must unref
3586 * the returned object after use. Returns NULL if unsuccessful. */
3587 static GstStructure *
3588 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3589 QtDemuxStream * stream, guint sample_index)
3591 QtDemuxCencSampleSetInfo *info = NULL;
3593 g_return_val_if_fail (stream != NULL, NULL);
3594 g_return_val_if_fail (stream->protected, NULL);
3595 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3597 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3599 /* Currently, cenc properties for groups of samples are not supported, so
3600 * simply return a copy of the default sample properties */
3601 return gst_structure_copy (info->default_properties);
3604 /* Parses the sizes of sample auxiliary information contained within a stream,
3605 * as given in a saiz box. Returns array of sample_count guint8 size values,
3606 * or NULL on failure */
3608 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3609 GstByteReader * br, guint32 * sample_count)
3613 guint8 default_info_size;
3615 g_return_val_if_fail (qtdemux != NULL, NULL);
3616 g_return_val_if_fail (stream != NULL, NULL);
3617 g_return_val_if_fail (br != NULL, NULL);
3618 g_return_val_if_fail (sample_count != NULL, NULL);
3620 if (!gst_byte_reader_get_uint32_be (br, &flags))
3624 /* aux_info_type and aux_info_type_parameter are ignored */
3625 if (!gst_byte_reader_skip (br, 8))
3629 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3631 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3633 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3635 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3638 if (default_info_size == 0) {
3639 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3643 info_sizes = g_new (guint8, *sample_count);
3644 memset (info_sizes, default_info_size, *sample_count);
3650 /* Parses the offset of sample auxiliary information contained within a stream,
3651 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3653 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3654 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3659 guint32 aux_info_type = 0;
3660 guint32 aux_info_type_parameter = 0;
3661 guint32 entry_count;
3664 const guint8 *aux_info_type_data = NULL;
3666 g_return_val_if_fail (qtdemux != NULL, FALSE);
3667 g_return_val_if_fail (stream != NULL, FALSE);
3668 g_return_val_if_fail (br != NULL, FALSE);
3669 g_return_val_if_fail (offset != NULL, FALSE);
3671 if (!gst_byte_reader_get_uint8 (br, &version))
3674 if (!gst_byte_reader_get_uint24_be (br, &flags))
3679 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3681 aux_info_type = QT_FOURCC (aux_info_type_data);
3683 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3685 } else if (stream->protected) {
3686 aux_info_type = stream->protection_scheme_type;
3688 aux_info_type = CUR_STREAM (stream)->fourcc;
3692 *info_type = aux_info_type;
3693 if (info_type_parameter)
3694 *info_type_parameter = aux_info_type_parameter;
3696 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3697 "aux_info_type_parameter: %#06x",
3698 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3700 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3703 if (entry_count != 1) {
3704 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3709 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3711 *offset = (guint64) off_32;
3713 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3718 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3723 qtdemux_gst_structure_free (GstStructure * gststructure)
3726 gst_structure_free (gststructure);
3730 /* Parses auxiliary information relating to samples protected using Common
3731 * Encryption (cenc); the format of this information is defined in
3732 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3734 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3735 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3737 QtDemuxCencSampleSetInfo *ss_info = NULL;
3740 GPtrArray *old_crypto_info = NULL;
3741 guint old_entries = 0;
3743 g_return_val_if_fail (qtdemux != NULL, FALSE);
3744 g_return_val_if_fail (stream != NULL, FALSE);
3745 g_return_val_if_fail (br != NULL, FALSE);
3746 g_return_val_if_fail (stream->protected, FALSE);
3747 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3749 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3751 if (ss_info->crypto_info) {
3752 old_crypto_info = ss_info->crypto_info;
3753 /* Count number of non-null entries remaining at the tail end */
3754 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3755 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3761 ss_info->crypto_info =
3762 g_ptr_array_new_full (sample_count + old_entries,
3763 (GDestroyNotify) qtdemux_gst_structure_free);
3765 /* We preserve old entries because we parse the next moof in advance
3766 * of consuming all samples from the previous moof, and otherwise
3767 * we'd discard the corresponding crypto info for the samples
3768 * from the previous fragment. */
3770 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3772 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3773 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3775 g_ptr_array_index (old_crypto_info, i) = NULL;
3779 if (old_crypto_info) {
3780 /* Everything now belongs to the new array */
3781 g_ptr_array_free (old_crypto_info, TRUE);
3784 for (i = 0; i < sample_count; ++i) {
3785 GstStructure *properties;
3786 guint16 n_subsamples = 0;
3791 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3792 if (properties == NULL) {
3793 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3796 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3797 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3798 gst_structure_free (properties);
3801 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3802 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3803 gst_structure_free (properties);
3806 buf = gst_buffer_new_wrapped (data, iv_size);
3807 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3808 gst_buffer_unref (buf);
3809 size = info_sizes[i];
3810 if (size > iv_size) {
3811 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3812 || !(n_subsamples > 0)) {
3813 gst_structure_free (properties);
3814 GST_ERROR_OBJECT (qtdemux,
3815 "failed to get subsample count for sample %u", i);
3818 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3819 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3820 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3822 gst_structure_free (properties);
3825 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3827 gst_structure_free (properties);
3830 gst_structure_set (properties,
3831 "subsample_count", G_TYPE_UINT, n_subsamples,
3832 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3833 gst_buffer_unref (buf);
3835 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3837 g_ptr_array_add (ss_info->crypto_info, properties);
3842 /* Converts a UUID in raw byte form to a string representation, as defined in
3843 * RFC 4122. The caller takes ownership of the returned string and is
3844 * responsible for freeing it after use. */
3846 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3848 const guint8 *uuid = (const guint8 *) uuid_bytes;
3850 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3851 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3852 uuid[0], uuid[1], uuid[2], uuid[3],
3853 uuid[4], uuid[5], uuid[6], uuid[7],
3854 uuid[8], uuid[9], uuid[10], uuid[11],
3855 uuid[12], uuid[13], uuid[14], uuid[15]);
3858 /* Parses a Protection System Specific Header box (pssh), as defined in the
3859 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3860 * information needed by a specific content protection system in order to
3861 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3864 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3866 gchar *sysid_string;
3867 guint32 pssh_size = QT_UINT32 (node->data);
3868 GstBuffer *pssh = NULL;
3869 GstEvent *event = NULL;
3870 guint32 parent_box_type;
3873 if (G_UNLIKELY (pssh_size < 32U)) {
3874 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3879 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3881 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3883 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3884 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3885 gst_buffer_get_size (pssh));
3887 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3889 /* Push an event containing the pssh box onto the queues of all streams. */
3890 event = gst_event_new_protection (sysid_string, pssh,
3891 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3892 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3893 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3894 GST_TRACE_OBJECT (qtdemux,
3895 "adding protection event for stream %s and system %s",
3896 stream->stream_id, sysid_string);
3897 g_queue_push_tail (&stream->protection_scheme_event_queue,
3898 gst_event_ref (event));
3900 g_free (sysid_string);
3901 gst_event_unref (event);
3902 gst_buffer_unref (pssh);
3907 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3908 guint64 moof_offset, QtDemuxStream * stream)
3910 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3912 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3913 GNode *saiz_node, *saio_node, *pssh_node;
3914 GstByteReader saiz_data, saio_data;
3915 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3916 gint64 base_offset, running_offset;
3918 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
3920 /* NOTE @stream ignored */
3922 moof_node = g_node_new ((guint8 *) buffer);
3923 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3924 qtdemux_node_dump (qtdemux, moof_node);
3926 /* Get fragment number from mfhd and check it's valid */
3928 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3929 if (mfhd_node == NULL)
3931 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3933 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3935 /* unknown base_offset to start with */
3936 base_offset = running_offset = -1;
3937 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3939 guint64 decode_time = 0;
3941 /* Fragment Header node */
3943 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3947 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3948 &ds_size, &ds_flags, &base_offset))
3951 /* The following code assumes at most a single set of sample auxiliary
3952 * data in the fragment (consisting of a saiz box and a corresponding saio
3953 * box); in theory, however, there could be multiple sets of sample
3954 * auxiliary data in a fragment. */
3956 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3959 guint32 info_type = 0;
3961 guint32 info_type_parameter = 0;
3963 g_free (qtdemux->cenc_aux_info_sizes);
3965 qtdemux->cenc_aux_info_sizes =
3966 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3967 &qtdemux->cenc_aux_sample_count);
3968 if (qtdemux->cenc_aux_info_sizes == NULL) {
3969 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3973 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3976 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3977 g_free (qtdemux->cenc_aux_info_sizes);
3978 qtdemux->cenc_aux_info_sizes = NULL;
3982 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3983 &info_type, &info_type_parameter, &offset))) {
3984 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3985 g_free (qtdemux->cenc_aux_info_sizes);
3986 qtdemux->cenc_aux_info_sizes = NULL;
3989 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
3990 offset += (guint64) (base_offset - qtdemux->moof_offset);
3991 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3993 if (offset > length) {
3994 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
3995 qtdemux->cenc_aux_info_offset = offset;
3997 gst_byte_reader_init (&br, buffer + offset, length - offset);
3998 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3999 qtdemux->cenc_aux_info_sizes,
4000 qtdemux->cenc_aux_sample_count)) {
4001 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4002 g_free (qtdemux->cenc_aux_info_sizes);
4003 qtdemux->cenc_aux_info_sizes = NULL;
4011 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4014 /* We'll use decode_time to interpolate timestamps
4015 * in case the input timestamps are missing */
4016 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4018 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4019 " (%" GST_TIME_FORMAT ")", decode_time,
4020 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4021 decode_time) : GST_CLOCK_TIME_NONE));
4023 /* Discard the fragment buffer timestamp info to avoid using it.
4024 * Rely on tfdt instead as it is more accurate than the timestamp
4025 * that is fetched from a manifest/playlist and is usually
4027 qtdemux->fragment_start = -1;
4030 if (G_UNLIKELY (!stream)) {
4031 /* we lost track of offset, we'll need to regain it,
4032 * but can delay complaining until later or avoid doing so altogether */
4036 if (G_UNLIKELY (base_offset < -1))
4039 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4041 if (!qtdemux->pullbased) {
4042 /* Sample tables can grow enough to be problematic if the system memory
4043 * is very low (e.g. embedded devices) and the videos very long
4044 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4045 * Fortunately, we can easily discard them for each new fragment when
4046 * we know qtdemux will not receive seeks outside of the current fragment.
4047 * adaptivedemux honors this assumption.
4048 * This optimization is also useful for applications that use qtdemux as
4049 * a push-based simple demuxer, like Media Source Extensions. */
4050 gst_qtdemux_stream_flush_samples_data (stream);
4053 /* initialise moof sample data */
4054 stream->n_samples_moof = 0;
4055 stream->duration_last_moof = stream->duration_moof;
4056 stream->duration_moof = 0;
4058 /* Track Run node */
4060 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4063 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4064 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4065 &running_offset, decode_time, (tfdt_node != NULL));
4066 /* iterate all siblings */
4067 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4071 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4073 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4074 guint32 box_length = QT_UINT32 (uuid_buffer);
4076 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4079 /* if no new base_offset provided for next traf,
4080 * base is end of current traf */
4081 base_offset = running_offset;
4082 running_offset = -1;
4084 if (stream->n_samples_moof && stream->duration_moof)
4085 stream->new_caps = TRUE;
4088 /* iterate all siblings */
4089 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4092 /* parse any protection system info */
4093 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4095 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4096 qtdemux_parse_pssh (qtdemux, pssh_node);
4097 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4100 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4101 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4103 /* Unless the user has explicitly requested another seek, perform an
4104 * internal seek to the time specified in the tfdt.
4106 * This way if the user opens a file where the first tfdt is 1 hour
4107 * into the presentation, they will not have to wait 1 hour for run
4108 * time to catch up and actual playback to start. */
4111 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4112 "performing an internal seek to %" GST_TIME_FORMAT,
4113 GST_TIME_ARGS (min_dts));
4115 qtdemux->segment.start = min_dts;
4116 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4118 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4119 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4120 stream->time_position = min_dts;
4123 /* Before this code was run a segment was already sent when the moov was
4124 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4125 * be emitted after a moov, and we can emit a second segment anyway for
4126 * special cases like this. */
4127 qtdemux->need_segment = TRUE;
4130 qtdemux->first_moof_already_parsed = TRUE;
4132 g_node_destroy (moof_node);
4137 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4142 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4147 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4152 g_node_destroy (moof_node);
4153 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4154 (_("This file is corrupt and cannot be played.")), (NULL));
4160 /* might be used if some day we actually use mfra & co
4161 * for random access to fragments,
4162 * but that will require quite some modifications and much less relying
4163 * on a sample array */
4167 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4169 QtDemuxStream *stream;
4170 guint32 ver_flags, track_id, len, num_entries, i;
4171 guint value_size, traf_size, trun_size, sample_size;
4172 guint64 time = 0, moof_offset = 0;
4174 GstBuffer *buf = NULL;
4179 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4181 if (!gst_byte_reader_skip (&tfra, 8))
4184 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4187 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4188 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4189 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4192 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4194 stream = qtdemux_find_stream (qtdemux, track_id);
4196 goto unknown_trackid;
4198 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4199 sample_size = (len & 3) + 1;
4200 trun_size = ((len & 12) >> 2) + 1;
4201 traf_size = ((len & 48) >> 4) + 1;
4203 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4204 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4206 if (num_entries == 0)
4209 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4210 value_size + value_size + traf_size + trun_size + sample_size))
4213 g_free (stream->ra_entries);
4214 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4215 stream->n_ra_entries = num_entries;
4217 for (i = 0; i < num_entries; i++) {
4218 qt_atom_parser_get_offset (&tfra, value_size, &time);
4219 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4220 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4221 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4222 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4224 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4226 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4227 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4229 stream->ra_entries[i].ts = time;
4230 stream->ra_entries[i].moof_offset = moof_offset;
4232 /* don't want to go through the entire file and read all moofs at startup */
4234 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4235 if (ret != GST_FLOW_OK)
4237 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4238 moof_offset, stream);
4239 gst_buffer_unref (buf);
4243 check_update_duration (qtdemux, time);
4250 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4255 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4260 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4266 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4268 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4269 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4270 GstBuffer *mfro = NULL, *mfra = NULL;
4272 gboolean ret = FALSE;
4273 GNode *mfra_node, *tfra_node;
4274 guint64 mfra_offset = 0;
4275 guint32 fourcc, mfra_size;
4278 /* query upstream size in bytes */
4279 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4280 goto size_query_failed;
4282 /* mfro box should be at the very end of the file */
4283 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4284 if (flow != GST_FLOW_OK)
4287 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4289 fourcc = QT_FOURCC (mfro_map.data + 4);
4290 if (fourcc != FOURCC_mfro)
4293 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4294 if (mfro_map.size < 16)
4295 goto invalid_mfro_size;
4297 mfra_size = QT_UINT32 (mfro_map.data + 12);
4298 if (mfra_size >= len)
4299 goto invalid_mfra_size;
4301 mfra_offset = len - mfra_size;
4303 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4304 mfra_offset, mfra_size);
4306 /* now get and parse mfra box */
4307 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4308 if (flow != GST_FLOW_OK)
4311 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4313 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4314 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4316 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4319 qtdemux_parse_tfra (qtdemux, tfra_node);
4320 /* iterate all siblings */
4321 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4323 g_node_destroy (mfra_node);
4325 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4331 if (mfro_map.memory != NULL)
4332 gst_buffer_unmap (mfro, &mfro_map);
4333 gst_buffer_unref (mfro);
4336 if (mfra_map.memory != NULL)
4337 gst_buffer_unmap (mfra, &mfra_map);
4338 gst_buffer_unref (mfra);
4345 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4350 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4355 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4360 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4366 add_offset (guint64 offset, guint64 advance)
4368 /* Avoid 64-bit overflow by clamping */
4369 if (offset > G_MAXUINT64 - advance)
4371 return offset + advance;
4374 static GstFlowReturn
4375 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4379 GstBuffer *buf = NULL;
4380 GstFlowReturn ret = GST_FLOW_OK;
4381 guint64 cur_offset = qtdemux->offset;
4384 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4385 if (G_UNLIKELY (ret != GST_FLOW_OK))
4387 gst_buffer_map (buf, &map, GST_MAP_READ);
4388 if (G_LIKELY (map.size >= 8))
4389 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4390 gst_buffer_unmap (buf, &map);
4391 gst_buffer_unref (buf);
4393 /* maybe we already got most we needed, so only consider this eof */
4394 if (G_UNLIKELY (length == 0)) {
4395 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4396 (_("Invalid atom size.")),
4397 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4398 GST_FOURCC_ARGS (fourcc)));
4405 /* record for later parsing when needed */
4406 if (!qtdemux->moof_offset) {
4407 qtdemux->moof_offset = qtdemux->offset;
4409 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4412 qtdemux->offset += length; /* skip moof and keep going */
4414 if (qtdemux->got_moov) {
4415 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4427 GST_LOG_OBJECT (qtdemux,
4428 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4429 GST_FOURCC_ARGS (fourcc), cur_offset);
4430 qtdemux->offset = add_offset (qtdemux->offset, length);
4435 GstBuffer *moov = NULL;
4437 if (qtdemux->got_moov) {
4438 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4439 qtdemux->offset = add_offset (qtdemux->offset, length);
4443 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4444 if (ret != GST_FLOW_OK)
4446 gst_buffer_map (moov, &map, GST_MAP_READ);
4448 if (length != map.size) {
4449 /* Some files have a 'moov' atom at the end of the file which contains
4450 * a terminal 'free' atom where the body of the atom is missing.
4451 * Check for, and permit, this special case.
4453 if (map.size >= 8) {
4454 guint8 *final_data = map.data + (map.size - 8);
4455 guint32 final_length = QT_UINT32 (final_data);
4456 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4458 if (final_fourcc == FOURCC_free
4459 && map.size + final_length - 8 == length) {
4460 /* Ok, we've found that special case. Allocate a new buffer with
4461 * that free atom actually present. */
4462 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4463 gst_buffer_fill (newmoov, 0, map.data, map.size);
4464 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4465 gst_buffer_unmap (moov, &map);
4466 gst_buffer_unref (moov);
4468 gst_buffer_map (moov, &map, GST_MAP_READ);
4473 if (length != map.size) {
4474 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4475 (_("This file is incomplete and cannot be played.")),
4476 ("We got less than expected (received %" G_GSIZE_FORMAT
4477 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4478 (guint) length, cur_offset));
4479 gst_buffer_unmap (moov, &map);
4480 gst_buffer_unref (moov);
4481 ret = GST_FLOW_ERROR;
4484 qtdemux->offset += length;
4486 qtdemux_parse_moov (qtdemux, map.data, length);
4487 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4489 qtdemux_parse_tree (qtdemux);
4490 if (qtdemux->moov_node_compressed) {
4491 g_node_destroy (qtdemux->moov_node_compressed);
4492 g_free (qtdemux->moov_node->data);
4494 qtdemux->moov_node_compressed = NULL;
4495 g_node_destroy (qtdemux->moov_node);
4496 qtdemux->moov_node = NULL;
4497 gst_buffer_unmap (moov, &map);
4498 gst_buffer_unref (moov);
4499 qtdemux->got_moov = TRUE;
4505 GstBuffer *ftyp = NULL;
4507 /* extract major brand; might come in handy for ISO vs QT issues */
4508 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4509 if (ret != GST_FLOW_OK)
4511 qtdemux->offset += length;
4512 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4513 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4514 gst_buffer_unmap (ftyp, &map);
4515 gst_buffer_unref (ftyp);
4520 GstBuffer *uuid = NULL;
4522 /* uuid are extension atoms */
4523 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4524 if (ret != GST_FLOW_OK)
4526 qtdemux->offset += length;
4527 gst_buffer_map (uuid, &map, GST_MAP_READ);
4528 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4529 gst_buffer_unmap (uuid, &map);
4530 gst_buffer_unref (uuid);
4535 GstBuffer *sidx = NULL;
4536 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4537 if (ret != GST_FLOW_OK)
4539 qtdemux->offset += length;
4540 gst_buffer_map (sidx, &map, GST_MAP_READ);
4541 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4542 gst_buffer_unmap (sidx, &map);
4543 gst_buffer_unref (sidx);
4548 GstBuffer *unknown = NULL;
4550 GST_LOG_OBJECT (qtdemux,
4551 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4552 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4554 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4555 if (ret != GST_FLOW_OK)
4557 gst_buffer_map (unknown, &map, GST_MAP_READ);
4558 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4559 gst_buffer_unmap (unknown, &map);
4560 gst_buffer_unref (unknown);
4561 qtdemux->offset += length;
4567 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4568 /* digested all data, show what we have */
4569 qtdemux_prepare_streams (qtdemux);
4570 QTDEMUX_EXPOSE_LOCK (qtdemux);
4571 ret = qtdemux_expose_streams (qtdemux);
4572 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4574 qtdemux->state = QTDEMUX_STATE_MOVIE;
4575 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4582 /* Seeks to the previous keyframe of the indexed stream and
4583 * aligns other streams with respect to the keyframe timestamp
4584 * of indexed stream. Only called in case of Reverse Playback
4586 static GstFlowReturn
4587 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4589 guint32 seg_idx = 0, k_index = 0;
4590 guint32 ref_seg_idx, ref_k_index;
4591 GstClockTime k_pos = 0, last_stop = 0;
4592 QtDemuxSegment *seg = NULL;
4593 QtDemuxStream *ref_str = NULL;
4594 guint64 seg_media_start_mov; /* segment media start time in mov format */
4598 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4599 * and finally align all the other streams on that timestamp with their
4600 * respective keyframes */
4601 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4602 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4604 /* No candidate yet, take the first stream */
4610 /* So that stream has a segment, we prefer video streams */
4611 if (str->subtype == FOURCC_vide) {
4617 if (G_UNLIKELY (!ref_str)) {
4618 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4622 if (G_UNLIKELY (!ref_str->from_sample)) {
4623 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4627 /* So that stream has been playing from from_sample to to_sample. We will
4628 * get the timestamp of the previous sample and search for a keyframe before
4629 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4630 if (ref_str->subtype == FOURCC_vide) {
4631 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4632 ref_str->from_sample - 1, FALSE);
4634 if (ref_str->from_sample >= 10)
4635 k_index = ref_str->from_sample - 10;
4641 ref_str->samples[k_index].timestamp +
4642 ref_str->samples[k_index].pts_offset;
4644 /* get current segment for that stream */
4645 seg = &ref_str->segments[ref_str->segment_index];
4646 /* Use segment start in original timescale for comparisons */
4647 seg_media_start_mov = seg->trak_media_start;
4649 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4650 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
4651 k_index, target_ts, seg_media_start_mov,
4652 GST_TIME_ARGS (seg->media_start));
4654 /* Crawl back through segments to find the one containing this I frame */
4655 while (target_ts < seg_media_start_mov) {
4656 GST_DEBUG_OBJECT (qtdemux,
4657 "keyframe position (sample %u) is out of segment %u " " target %"
4658 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4659 ref_str->segment_index, target_ts, seg_media_start_mov);
4661 if (G_UNLIKELY (!ref_str->segment_index)) {
4662 /* Reached first segment, let's consider it's EOS */
4665 ref_str->segment_index--;
4666 seg = &ref_str->segments[ref_str->segment_index];
4667 /* Use segment start in original timescale for comparisons */
4668 seg_media_start_mov = seg->trak_media_start;
4670 /* Calculate time position of the keyframe and where we should stop */
4672 QTSTREAMTIME_TO_GSTTIME (ref_str,
4673 target_ts - seg->trak_media_start) + seg->time;
4675 QTSTREAMTIME_TO_GSTTIME (ref_str,
4676 ref_str->samples[ref_str->from_sample].timestamp -
4677 seg->trak_media_start) + seg->time;
4679 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4680 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4681 k_index, GST_TIME_ARGS (k_pos));
4683 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4684 qtdemux->segment.position = last_stop;
4685 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4686 GST_TIME_ARGS (last_stop));
4688 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4689 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4693 ref_seg_idx = ref_str->segment_index;
4694 ref_k_index = k_index;
4696 /* Align them all on this */
4697 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4699 GstClockTime seg_time = 0;
4700 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4702 /* aligning reference stream again might lead to backing up to yet another
4703 * keyframe (due to timestamp rounding issues),
4704 * potentially putting more load on downstream; so let's try to avoid */
4705 if (str == ref_str) {
4706 seg_idx = ref_seg_idx;
4707 seg = &str->segments[seg_idx];
4708 k_index = ref_k_index;
4709 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4710 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4712 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4713 GST_DEBUG_OBJECT (qtdemux,
4714 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4715 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4717 /* get segment and time in the segment */
4718 seg = &str->segments[seg_idx];
4719 seg_time = k_pos - seg->time;
4721 /* get the media time in the segment.
4722 * No adjustment for empty "filler" segments */
4723 if (seg->media_start != GST_CLOCK_TIME_NONE)
4724 seg_time += seg->media_start;
4726 /* get the index of the sample with media time */
4727 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4728 GST_DEBUG_OBJECT (qtdemux,
4729 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4730 GST_TIME_ARGS (seg_time), index);
4732 /* find previous keyframe */
4733 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4736 /* Remember until where we want to go */
4737 str->to_sample = str->from_sample - 1;
4738 /* Define our time position */
4740 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4741 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4742 if (seg->media_start != GST_CLOCK_TIME_NONE)
4743 str->time_position -= seg->media_start;
4745 /* Now seek back in time */
4746 gst_qtdemux_move_stream (qtdemux, str, k_index);
4747 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4748 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4749 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4755 return GST_FLOW_EOS;
4759 * Gets the current qt segment start, stop and position for the
4760 * given time offset. This is used in update_segment()
4763 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4764 QtDemuxStream * stream, GstClockTime offset,
4765 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4767 GstClockTime seg_time;
4768 GstClockTime start, stop, time;
4769 QtDemuxSegment *segment;
4771 segment = &stream->segments[stream->segment_index];
4773 /* get time in this segment */
4774 seg_time = (offset - segment->time) * segment->rate;
4776 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4777 GST_TIME_ARGS (seg_time));
4779 if (G_UNLIKELY (seg_time > segment->duration)) {
4780 GST_LOG_OBJECT (stream->pad,
4781 "seg_time > segment->duration %" GST_TIME_FORMAT,
4782 GST_TIME_ARGS (segment->duration));
4783 seg_time = segment->duration;
4786 /* qtdemux->segment.stop is in outside-time-realm, whereas
4787 * segment->media_stop is in track-time-realm.
4789 * In order to compare the two, we need to bring segment.stop
4790 * into the track-time-realm
4792 * FIXME - does this comment still hold? Don't see any conversion here */
4794 stop = qtdemux->segment.stop;
4795 if (stop == GST_CLOCK_TIME_NONE)
4796 stop = qtdemux->segment.duration;
4797 if (stop == GST_CLOCK_TIME_NONE)
4798 stop = segment->media_stop;
4801 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4803 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4804 start = segment->time + seg_time;
4806 stop = start - seg_time + segment->duration;
4807 } else if (qtdemux->segment.rate >= 0) {
4808 start = MIN (segment->media_start + seg_time, stop);
4811 if (segment->media_start >= qtdemux->segment.start) {
4812 time = segment->time;
4814 time = segment->time + (qtdemux->segment.start - segment->media_start);
4817 start = MAX (segment->media_start, qtdemux->segment.start);
4818 stop = MIN (segment->media_start + seg_time, stop);
4827 * Updates the qt segment used for the stream and pushes a new segment event
4828 * downstream on this stream's pad.
4831 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4832 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4833 GstClockTime * _stop)
4835 QtDemuxSegment *segment;
4836 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4840 /* update the current segment */
4841 stream->segment_index = seg_idx;
4843 /* get the segment */
4844 segment = &stream->segments[seg_idx];
4846 if (G_UNLIKELY (offset < segment->time)) {
4847 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4848 GST_TIME_ARGS (segment->time));
4852 /* segment lies beyond total indicated duration */
4853 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4854 segment->time > qtdemux->segment.duration)) {
4855 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4856 " < segment->time %" GST_TIME_FORMAT,
4857 GST_TIME_ARGS (qtdemux->segment.duration),
4858 GST_TIME_ARGS (segment->time));
4862 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4863 &start, &stop, &time);
4865 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4866 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4867 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4869 /* combine global rate with that of the segment */
4870 rate = segment->rate * qtdemux->segment.rate;
4872 /* Copy flags from main segment */
4873 stream->segment.flags = qtdemux->segment.flags;
4875 /* update the segment values used for clipping */
4876 stream->segment.offset = qtdemux->segment.offset;
4877 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4878 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4879 stream->segment.rate = rate;
4880 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4881 stream->cslg_shift);
4882 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4883 stream->cslg_shift);
4884 stream->segment.time = time;
4885 stream->segment.position = stream->segment.start;
4887 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4890 /* now prepare and send the segment */
4892 event = gst_event_new_segment (&stream->segment);
4893 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4894 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4896 gst_pad_push_event (stream->pad, event);
4897 /* assume we can send more data now */
4898 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4899 /* clear to send tags on this pad now */
4900 gst_qtdemux_push_tags (qtdemux, stream);
4911 /* activate the given segment number @seg_idx of @stream at time @offset.
4912 * @offset is an absolute global position over all the segments.
4914 * This will push out a NEWSEGMENT event with the right values and
4915 * position the stream index to the first decodable sample before
4919 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4920 guint32 seg_idx, GstClockTime offset)
4922 QtDemuxSegment *segment;
4923 guint32 index, kf_index;
4924 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4926 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4927 seg_idx, GST_TIME_ARGS (offset));
4929 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4933 segment = &stream->segments[stream->segment_index];
4935 /* in the fragmented case, we pick a fragment that starts before our
4936 * desired position and rely on downstream to wait for a keyframe
4937 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4938 * tfra entries tells us which trun/sample the key unit is in, but we don't
4939 * make use of this additional information at the moment) */
4940 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4941 stream->to_sample = G_MAXUINT32;
4944 /* well, it will be taken care of below */
4945 qtdemux->fragmented_seek_pending = FALSE;
4946 /* FIXME ideally the do_fragmented_seek can be done right here,
4947 * rather than at loop level
4948 * (which might even allow handling edit lists in a fragmented file) */
4951 /* We don't need to look for a sample in push-based */
4952 if (!qtdemux->pullbased)
4955 /* and move to the keyframe before the indicated media time of the
4957 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4958 if (qtdemux->segment.rate >= 0) {
4959 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4960 stream->to_sample = G_MAXUINT32;
4961 GST_DEBUG_OBJECT (stream->pad,
4962 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4963 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4964 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4966 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4967 stream->to_sample = index;
4968 GST_DEBUG_OBJECT (stream->pad,
4969 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4970 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4971 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4974 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4975 "this is an empty segment");
4979 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4980 * encountered an error and printed a message so we return appropriately */
4984 /* we're at the right spot */
4985 if (index == stream->sample_index) {
4986 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4990 /* find keyframe of the target index */
4991 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
4993 /* go back two frames to provide lead-in for non-raw audio decoders */
4994 if (stream->subtype == FOURCC_soun && !stream->need_clip) {
4995 guint32 lead_in = 2;
4996 guint32 old_index = kf_index;
4997 GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
4999 if (gst_structure_has_name (s, "audio/mpeg")) {
5001 if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5002 && mpegversion == 1) {
5003 /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5008 kf_index = MAX (kf_index, lead_in) - lead_in;
5009 if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5010 GST_DEBUG_OBJECT (stream->pad,
5011 "Moving backwards %u frames to ensure sufficient sound lead-in",
5012 old_index - kf_index);
5014 kf_index = old_index;
5018 /* if we move forwards, we don't have to go back to the previous
5019 * keyframe since we already sent that. We can also just jump to
5020 * the keyframe right before the target index if there is one. */
5021 if (index > stream->sample_index) {
5022 /* moving forwards check if we move past a keyframe */
5023 if (kf_index > stream->sample_index) {
5024 GST_DEBUG_OBJECT (stream->pad,
5025 "moving forwards to keyframe at %u "
5026 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5028 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5029 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5030 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5032 GST_DEBUG_OBJECT (stream->pad,
5033 "moving forwards, keyframe at %u "
5034 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5036 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5037 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5040 GST_DEBUG_OBJECT (stream->pad,
5041 "moving backwards to %sframe at %u "
5042 "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5043 (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5044 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5045 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5046 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5052 /* prepare to get the current sample of @stream, getting essential values.
5054 * This function will also prepare and send the segment when needed.
5056 * Return FALSE if the stream is EOS.
5061 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5062 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5063 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5064 gboolean * keyframe)
5066 QtDemuxSample *sample;
5067 GstClockTime time_position;
5070 g_return_val_if_fail (stream != NULL, FALSE);
5072 time_position = stream->time_position;
5073 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5076 seg_idx = stream->segment_index;
5077 if (G_UNLIKELY (seg_idx == -1)) {
5078 /* find segment corresponding to time_position if we are looking
5080 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5083 /* different segment, activate it, sample_index will be set. */
5084 if (G_UNLIKELY (stream->segment_index != seg_idx))
5085 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5087 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5088 segments[stream->segment_index]))) {
5089 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5091 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5092 " prepare empty sample");
5095 *pts = *dts = time_position;
5096 *duration = seg->duration - (time_position - seg->time);
5103 if (stream->sample_index == -1)
5104 stream->sample_index = 0;
5106 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5107 stream->sample_index, stream->n_samples);
5109 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5110 if (!qtdemux->fragmented)
5113 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5117 GST_OBJECT_LOCK (qtdemux);
5118 flow = qtdemux_add_fragmented_samples (qtdemux);
5119 GST_OBJECT_UNLOCK (qtdemux);
5121 if (flow != GST_FLOW_OK)
5124 while (stream->sample_index >= stream->n_samples);
5127 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5128 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5129 stream->sample_index);
5133 /* now get the info for the sample we're at */
5134 sample = &stream->samples[stream->sample_index];
5136 *dts = QTSAMPLE_DTS (stream, sample);
5137 *pts = QTSAMPLE_PTS (stream, sample);
5138 *offset = sample->offset;
5139 *size = sample->size;
5140 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5141 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5148 stream->time_position = GST_CLOCK_TIME_NONE;
5153 /* move to the next sample in @stream.
5155 * Moves to the next segment when needed.
5158 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5160 QtDemuxSample *sample;
5161 QtDemuxSegment *segment;
5163 /* get current segment */
5164 segment = &stream->segments[stream->segment_index];
5166 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5167 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5171 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5172 /* Mark the stream as EOS */
5173 GST_DEBUG_OBJECT (qtdemux,
5174 "reached max allowed sample %u, mark EOS", stream->to_sample);
5175 stream->time_position = GST_CLOCK_TIME_NONE;
5179 /* move to next sample */
5180 stream->sample_index++;
5181 stream->offset_in_sample = 0;
5183 GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
5186 /* reached the last sample, we need the next segment */
5187 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5190 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5191 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5192 stream->sample_index);
5196 /* get next sample */
5197 sample = &stream->samples[stream->sample_index];
5199 GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
5200 GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
5201 GST_TIME_ARGS (segment->media_stop));
5203 /* see if we are past the segment */
5204 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5207 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5208 /* inside the segment, update time_position, looks very familiar to
5209 * GStreamer segments, doesn't it? */
5210 stream->time_position =
5211 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5213 /* not yet in segment, time does not yet increment. This means
5214 * that we are still prerolling keyframes to the decoder so it can
5215 * decode the first sample of the segment. */
5216 stream->time_position = segment->time;
5220 /* move to the next segment */
5223 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5225 if (stream->segment_index == stream->n_segments - 1) {
5226 /* are we at the end of the last segment, we're EOS */
5227 stream->time_position = GST_CLOCK_TIME_NONE;
5229 /* else we're only at the end of the current segment */
5230 stream->time_position = segment->stop_time;
5232 /* make sure we select a new segment */
5234 /* accumulate previous segments */
5235 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5236 stream->accumulated_base +=
5237 (stream->segment.stop -
5238 stream->segment.start) / ABS (stream->segment.rate);
5240 stream->segment_index = -1;
5245 gst_qtdemux_sync_streams (GstQTDemux * demux)
5249 if (QTDEMUX_N_STREAMS (demux) <= 1)
5252 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5253 QtDemuxStream *stream;
5254 GstClockTime end_time;
5256 stream = QTDEMUX_NTH_STREAM (demux, i);
5261 /* TODO advance time on subtitle streams here, if any some day */
5263 /* some clips/trailers may have unbalanced streams at the end,
5264 * so send EOS on shorter stream to prevent stalling others */
5266 /* do not mess with EOS if SEGMENT seeking */
5267 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5270 if (demux->pullbased) {
5271 /* loop mode is sample time based */
5272 if (!STREAM_IS_EOS (stream))
5275 /* push mode is byte position based */
5276 if (stream->n_samples &&
5277 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5281 if (stream->sent_eos)
5284 /* only act if some gap */
5285 end_time = stream->segments[stream->n_segments - 1].stop_time;
5286 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5287 ", stream end: %" GST_TIME_FORMAT,
5288 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5289 if (GST_CLOCK_TIME_IS_VALID (end_time)
5290 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5293 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5294 GST_PAD_NAME (stream->pad));
5295 stream->sent_eos = TRUE;
5296 event = gst_event_new_eos ();
5297 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5298 gst_event_set_seqnum (event, demux->segment_seqnum);
5299 gst_pad_push_event (stream->pad, event);
5304 /* EOS and NOT_LINKED need to be combined. This means that we return:
5306 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5307 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5309 static GstFlowReturn
5310 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5313 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5316 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5319 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5321 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5325 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5326 * completely clipped
5328 * Should be used only with raw buffers */
5330 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5333 guint64 start, stop, cstart, cstop, diff;
5334 GstClockTime pts, duration;
5336 gint num_rate, denom_rate;
5341 osize = size = gst_buffer_get_size (buf);
5344 /* depending on the type, setup the clip parameters */
5345 if (stream->subtype == FOURCC_soun) {
5346 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5347 num_rate = GST_SECOND;
5348 denom_rate = (gint) CUR_STREAM (stream)->rate;
5350 } else if (stream->subtype == FOURCC_vide) {
5352 num_rate = CUR_STREAM (stream)->fps_n;
5353 denom_rate = CUR_STREAM (stream)->fps_d;
5358 if (frame_size <= 0)
5359 goto bad_frame_size;
5361 /* we can only clip if we have a valid pts */
5362 pts = GST_BUFFER_PTS (buf);
5363 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5366 duration = GST_BUFFER_DURATION (buf);
5368 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5370 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5374 stop = start + duration;
5376 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5377 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5380 /* see if some clipping happened */
5381 diff = cstart - start;
5387 /* bring clipped time to samples and to bytes */
5388 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5391 GST_DEBUG_OBJECT (qtdemux,
5392 "clipping start to %" GST_TIME_FORMAT " %"
5393 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5399 diff = stop - cstop;
5404 /* bring clipped time to samples and then to bytes */
5405 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5407 GST_DEBUG_OBJECT (qtdemux,
5408 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5409 " bytes", GST_TIME_ARGS (cstop), diff);
5414 if (offset != 0 || size != osize)
5415 gst_buffer_resize (buf, offset, size);
5417 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5418 GST_BUFFER_PTS (buf) = pts;
5419 GST_BUFFER_DURATION (buf) = duration;
5423 /* dropped buffer */
5426 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5431 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5436 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5441 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5442 gst_buffer_unref (buf);
5448 gst_qtdemux_align_buffer (GstQTDemux * demux,
5449 GstBuffer * buffer, gsize alignment)
5453 gst_buffer_map (buffer, &map, GST_MAP_READ);
5455 if (map.size < sizeof (guintptr)) {
5456 gst_buffer_unmap (buffer, &map);
5460 if (((guintptr) map.data) & (alignment - 1)) {
5461 GstBuffer *new_buffer;
5462 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5464 new_buffer = gst_buffer_new_allocate (NULL,
5465 gst_buffer_get_size (buffer), ¶ms);
5467 /* Copy data "by hand", so ensure alignment is kept: */
5468 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5470 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5471 GST_DEBUG_OBJECT (demux,
5472 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5475 gst_buffer_unmap (buffer, &map);
5476 gst_buffer_unref (buffer);
5481 gst_buffer_unmap (buffer, &map);
5486 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
5492 /* We are converting from pairs to triplets */
5493 *res = ccpair_size / 2 * 3;
5494 storage = g_malloc (*res);
5495 for (i = 0; i * 2 < ccpair_size; i += 1) {
5496 /* FIXME: Use line offset 0 as we simply can't know here */
5498 storage[i * 3] = 0x80 | 0x00;
5500 storage[i * 3] = 0x00 | 0x00;
5501 storage[i * 3 + 1] = ccpair[i * 2];
5502 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5509 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5513 guint32 atom_length, fourcc;
5514 QtDemuxStreamStsdEntry *stsd_entry;
5516 GST_MEMDUMP ("caption atom", data, size);
5518 /* There might be multiple atoms */
5523 atom_length = QT_UINT32 (data);
5524 fourcc = QT_FOURCC (data + 4);
5525 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5528 GST_DEBUG_OBJECT (stream->pad, "here");
5530 /* Check if we have something compatible */
5531 stsd_entry = CUR_STREAM (stream);
5532 switch (stsd_entry->fourcc) {
5534 guint8 *cdat = NULL, *cdt2 = NULL;
5535 gsize cdat_size = 0, cdt2_size = 0;
5536 /* Should be cdat or cdt2 */
5537 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5538 GST_WARNING_OBJECT (stream->pad,
5539 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5540 GST_FOURCC_ARGS (fourcc));
5544 /* Convert to S334-1 Annex A byte triplet */
5545 if (fourcc == FOURCC_cdat)
5546 cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
5548 cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
5549 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5552 /* Check for another atom ? */
5553 if (size > atom_length + 8) {
5554 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5555 if (size >= atom_length + new_atom_length) {
5556 fourcc = QT_FOURCC (data + atom_length + 4);
5557 if (fourcc == FOURCC_cdat) {
5560 convert_to_s334_1a (data + atom_length + 8,
5561 new_atom_length - 8, 1, &cdat_size);
5563 GST_WARNING_OBJECT (stream->pad,
5564 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5568 convert_to_s334_1a (data + atom_length + 8,
5569 new_atom_length - 8, 2, &cdt2_size);
5571 GST_WARNING_OBJECT (stream->pad,
5572 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5577 *cclen = cdat_size + cdt2_size;
5578 res = g_malloc (*cclen);
5580 memcpy (res, cdat, cdat_size);
5582 memcpy (res + cdat_size, cdt2, cdt2_size);
5588 if (fourcc != FOURCC_ccdp) {
5589 GST_WARNING_OBJECT (stream->pad,
5590 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5591 GST_FOURCC_ARGS (fourcc));
5594 *cclen = atom_length - 8;
5595 res = g_memdup (data + 8, *cclen);
5598 /* Keep this here in case other closed caption formats are added */
5599 g_assert_not_reached ();
5603 GST_MEMDUMP ("Output", res, *cclen);
5608 GST_WARNING ("[cdat] atom is too small or invalid");
5612 /* the input buffer metadata must be writable,
5613 * but time/duration etc not yet set and need not be preserved */
5615 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5622 /* not many cases for now */
5623 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5624 /* send a one time dvd clut event */
5625 if (stream->pending_event && stream->pad)
5626 gst_pad_push_event (stream->pad, stream->pending_event);
5627 stream->pending_event = NULL;
5630 if (G_UNLIKELY (stream->subtype != FOURCC_text
5631 && stream->subtype != FOURCC_sbtl &&
5632 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5636 gst_buffer_map (buf, &map, GST_MAP_READ);
5638 /* empty buffer is sent to terminate previous subtitle */
5639 if (map.size <= 2) {
5640 gst_buffer_unmap (buf, &map);
5641 gst_buffer_unref (buf);
5644 if (stream->subtype == FOURCC_subp) {
5645 /* That's all the processing needed for subpictures */
5646 gst_buffer_unmap (buf, &map);
5650 if (stream->subtype == FOURCC_clcp) {
5653 /* For closed caption, we need to extract the information from the
5654 * [cdat],[cdt2] or [ccdp] atom */
5655 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5656 gst_buffer_unmap (buf, &map);
5657 gst_buffer_unref (buf);
5659 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5661 /* Conversion failed or there's nothing */
5667 nsize = GST_READ_UINT16_BE (map.data);
5668 nsize = MIN (nsize, map.size - 2);
5670 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5673 /* takes care of UTF-8 validation or UTF-16 recognition,
5674 * no other encoding expected */
5675 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5676 gst_buffer_unmap (buf, &map);
5678 gst_buffer_unref (buf);
5679 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5681 /* this should not really happen unless the subtitle is corrupted */
5682 gst_buffer_unref (buf);
5686 /* FIXME ? convert optional subsequent style info to markup */
5691 static GstFlowReturn
5692 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5695 GstFlowReturn ret = GST_FLOW_OK;
5696 GstClockTime pts, duration;
5698 if (stream->need_clip)
5699 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5701 if (G_UNLIKELY (buf == NULL))
5704 if (G_UNLIKELY (stream->discont)) {
5705 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5706 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5707 stream->discont = FALSE;
5709 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5712 GST_LOG_OBJECT (qtdemux,
5713 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5714 ", duration %" GST_TIME_FORMAT " on pad %s",
5715 GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
5716 GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
5717 GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
5719 if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
5720 GstStructure *crypto_info;
5721 QtDemuxAavdEncryptionInfo *info =
5722 (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
5724 crypto_info = gst_structure_copy (info->default_properties);
5725 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5726 GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
5729 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5730 GstStructure *crypto_info;
5731 QtDemuxCencSampleSetInfo *info =
5732 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5736 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5737 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5738 GST_PTR_FORMAT, event);
5739 gst_pad_push_event (stream->pad, event);
5742 if (info->crypto_info == NULL) {
5743 GST_DEBUG_OBJECT (qtdemux,
5744 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5746 /* The end of the crypto_info array matches our n_samples position,
5747 * so count backward from there */
5748 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5749 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5750 /* steal structure from array */
5751 crypto_info = g_ptr_array_index (info->crypto_info, index);
5752 g_ptr_array_index (info->crypto_info, index) = NULL;
5753 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5754 info->crypto_info->len);
5755 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5756 GST_ERROR_OBJECT (qtdemux,
5757 "failed to attach cenc metadata to buffer");
5759 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5760 index, stream->sample_index);
5765 if (stream->alignment > 1)
5766 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5768 pts = GST_BUFFER_PTS (buf);
5769 duration = GST_BUFFER_DURATION (buf);
5771 ret = gst_pad_push (stream->pad, buf);
5773 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5774 /* mark position in stream, we'll need this to know when to send GAP event */
5775 stream->segment.position = pts + duration;
5783 static GstFlowReturn
5784 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5787 GstFlowReturn ret = GST_FLOW_OK;
5789 if (stream->subtype == FOURCC_clcp
5790 && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
5792 guint n_output_buffers, n_field1 = 0, n_field2 = 0;
5793 guint n_triplets, i;
5794 guint field1_off = 0, field2_off = 0;
5796 /* We have to split CEA608 buffers so that each outgoing buffer contains
5797 * one byte pair per field according to the framerate of the video track.
5799 * If there is only a single byte pair per field we don't have to do
5803 gst_buffer_map (buf, &map, GST_MAP_READ);
5805 n_triplets = map.size / 3;
5806 for (i = 0; i < n_triplets; i++) {
5807 if (map.data[3 * i] & 0x80)
5813 g_assert (n_field1 || n_field2);
5815 /* If there's more than 1 frame we have to split, otherwise we can just
5817 if (n_field1 > 1 || n_field2 > 1) {
5819 gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
5820 CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
5822 for (i = 0; i < n_output_buffers; i++) {
5824 gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
5828 gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
5829 outptr = outmap.data;
5832 gboolean found = FALSE;
5834 while (map.data + field1_off < map.data + map.size) {
5835 if (map.data[field1_off] & 0x80) {
5836 memcpy (outptr, &map.data[field1_off], 3);
5845 const guint8 empty[] = { 0x80, 0x80, 0x80 };
5847 memcpy (outptr, empty, 3);
5854 gboolean found = FALSE;
5856 while (map.data + field2_off < map.data + map.size) {
5857 if ((map.data[field2_off] & 0x80) == 0) {
5858 memcpy (outptr, &map.data[field2_off], 3);
5867 const guint8 empty[] = { 0x00, 0x80, 0x80 };
5869 memcpy (outptr, empty, 3);
5875 gst_buffer_unmap (outbuf, &outmap);
5877 GST_BUFFER_PTS (outbuf) =
5878 GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
5879 GST_SECOND * CUR_STREAM (stream)->fps_d,
5880 CUR_STREAM (stream)->fps_n);
5881 GST_BUFFER_DURATION (outbuf) =
5882 gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
5883 CUR_STREAM (stream)->fps_n);
5884 GST_BUFFER_OFFSET (outbuf) = -1;
5885 GST_BUFFER_OFFSET_END (outbuf) = -1;
5887 ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
5889 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
5892 gst_buffer_unmap (buf, &map);
5893 gst_buffer_unref (buf);
5895 gst_buffer_unmap (buf, &map);
5896 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
5899 ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
5905 /* Sets a buffer's attributes properly and pushes it downstream.
5906 * Also checks for additional actions and custom processing that may
5907 * need to be done first.
5909 static GstFlowReturn
5910 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5911 QtDemuxStream * stream, GstBuffer * buf,
5912 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5913 gboolean keyframe, GstClockTime position, guint64 byte_position)
5915 GstFlowReturn ret = GST_FLOW_OK;
5917 /* offset the timestamps according to the edit list */
5919 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5923 gst_buffer_map (buf, &map, GST_MAP_READ);
5924 url = g_strndup ((gchar *) map.data, map.size);
5925 gst_buffer_unmap (buf, &map);
5926 if (url != NULL && strlen (url) != 0) {
5927 /* we have RTSP redirect now */
5928 g_free (qtdemux->redirect_location);
5929 qtdemux->redirect_location = g_strdup (url);
5930 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5931 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5932 gst_structure_new ("redirect",
5933 "new-location", G_TYPE_STRING, url, NULL)));
5935 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5941 /* position reporting */
5942 if (qtdemux->segment.rate >= 0) {
5943 qtdemux->segment.position = position;
5944 gst_qtdemux_sync_streams (qtdemux);
5947 if (G_UNLIKELY (!stream->pad)) {
5948 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5949 gst_buffer_unref (buf);
5953 /* send out pending buffers */
5954 while (stream->buffers) {
5955 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5957 if (G_UNLIKELY (stream->discont)) {
5958 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5959 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5960 stream->discont = FALSE;
5962 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5965 if (stream->alignment > 1)
5966 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5967 gst_pad_push (stream->pad, buffer);
5969 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5972 /* we're going to modify the metadata */
5973 buf = gst_buffer_make_writable (buf);
5975 if (G_UNLIKELY (stream->need_process))
5976 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5982 GST_BUFFER_DTS (buf) = dts;
5983 GST_BUFFER_PTS (buf) = pts;
5984 GST_BUFFER_DURATION (buf) = duration;
5985 GST_BUFFER_OFFSET (buf) = -1;
5986 GST_BUFFER_OFFSET_END (buf) = -1;
5989 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5990 stream->on_keyframe = FALSE;
5992 stream->on_keyframe = TRUE;
5995 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5996 gst_buffer_append_memory (buf,
5997 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5999 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6000 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6003 if (G_UNLIKELY (qtdemux->element_index)) {
6004 GstClockTime stream_time;
6007 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6009 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6010 GST_LOG_OBJECT (qtdemux,
6011 "adding association %" GST_TIME_FORMAT "-> %"
6012 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6013 gst_index_add_association (qtdemux->element_index,
6015 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6016 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6017 GST_FORMAT_BYTES, byte_position, NULL);
6022 ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6028 static const QtDemuxRandomAccessEntry *
6029 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6030 GstClockTime pos, gboolean after)
6032 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6033 guint n_entries = stream->n_ra_entries;
6036 /* we assume the table is sorted */
6037 for (i = 0; i < n_entries; ++i) {
6038 if (entries[i].ts > pos)
6042 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6043 * probably okay to assume that the index lists the very first fragment */
6050 return &entries[i - 1];
6054 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6056 const QtDemuxRandomAccessEntry *best_entry = NULL;
6059 GST_OBJECT_LOCK (qtdemux);
6061 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6063 /* first see if we can determine where to go to using mfra,
6064 * before we start clearing things */
6065 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6066 const QtDemuxRandomAccessEntry *entry;
6067 QtDemuxStream *stream;
6068 gboolean is_audio_or_video;
6070 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6072 if (stream->ra_entries == NULL)
6075 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6076 is_audio_or_video = TRUE;
6078 is_audio_or_video = FALSE;
6081 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6082 stream->time_position, !is_audio_or_video);
6084 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6085 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6087 stream->pending_seek = entry;
6089 /* decide position to jump to just based on audio/video tracks, not subs */
6090 if (!is_audio_or_video)
6093 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6097 /* no luck, will handle seek otherwise */
6098 if (best_entry == NULL) {
6099 GST_OBJECT_UNLOCK (qtdemux);
6103 /* ok, now we can prepare for processing as of located moof */
6104 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6105 QtDemuxStream *stream;
6107 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6109 g_free (stream->samples);
6110 stream->samples = NULL;
6111 stream->n_samples = 0;
6112 stream->stbl_index = -1; /* no samples have yet been parsed */
6113 stream->sample_index = -1;
6115 if (stream->protection_scheme_info) {
6116 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6117 if (stream->protection_scheme_type == FOURCC_cenc) {
6118 QtDemuxCencSampleSetInfo *info =
6119 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6120 if (info->crypto_info) {
6121 g_ptr_array_free (info->crypto_info, TRUE);
6122 info->crypto_info = NULL;
6128 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6129 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6130 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6131 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6133 qtdemux->moof_offset = best_entry->moof_offset;
6135 qtdemux_add_fragmented_samples (qtdemux);
6137 GST_OBJECT_UNLOCK (qtdemux);
6141 static GstFlowReturn
6142 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6144 GstFlowReturn ret = GST_FLOW_OK;
6145 GstBuffer *buf = NULL;
6146 QtDemuxStream *stream, *target_stream = NULL;
6147 GstClockTime min_time;
6149 GstClockTime dts = GST_CLOCK_TIME_NONE;
6150 GstClockTime pts = GST_CLOCK_TIME_NONE;
6151 GstClockTime duration = 0;
6152 gboolean keyframe = FALSE;
6153 guint sample_size = 0;
6154 guint num_samples = 1;
6159 if (qtdemux->fragmented_seek_pending) {
6160 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6161 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6162 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6163 qtdemux->fragmented_seek_pending = FALSE;
6165 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6169 /* Figure out the next stream sample to output, min_time is expressed in
6170 * global time and runs over the edit list segments. */
6171 min_time = G_MAXUINT64;
6172 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6173 GstClockTime position;
6175 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6176 position = stream->time_position;
6178 if (!GST_CLOCK_TIME_IS_VALID (position))
6181 if (stream->segment_index != -1) {
6182 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6183 position += segment->media_start;
6186 /* position of -1 is EOS */
6187 if (position < min_time) {
6188 min_time = position;
6189 target_stream = stream;
6193 if (G_UNLIKELY (target_stream == NULL)) {
6194 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6198 /* check for segment end */
6199 if (G_UNLIKELY (qtdemux->segment.stop != -1
6200 && qtdemux->segment.rate >= 0
6201 && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
6202 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6203 target_stream->time_position = GST_CLOCK_TIME_NONE;
6207 /* gap events for subtitle streams */
6208 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6209 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6211 GstClockTime gap_threshold;
6213 /* Only send gap events on non-subtitle streams if lagging way behind. */
6214 if (stream->subtype == FOURCC_subp
6215 || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)
6216 gap_threshold = 1 * GST_SECOND;
6218 gap_threshold = 3 * GST_SECOND;
6220 /* send gap events until the stream catches up */
6221 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6222 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6223 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6224 stream->segment.position + gap_threshold < min_time) {
6226 gst_event_new_gap (stream->segment.position, gap_threshold);
6227 gst_pad_push_event (stream->pad, gap);
6228 stream->segment.position += gap_threshold;
6233 stream = target_stream;
6234 /* fetch info for the current sample of this stream */
6235 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6236 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6239 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6240 if (stream->new_caps) {
6241 gst_qtdemux_configure_stream (qtdemux, stream);
6242 qtdemux_do_allocation (stream, qtdemux);
6245 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6246 if (G_UNLIKELY (qtdemux->segment.
6247 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6248 if (stream->subtype == FOURCC_vide) {
6250 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6253 } else if (qtdemux->trickmode_interval > 0) {
6254 GstClockTimeDiff interval;
6256 if (qtdemux->segment.rate > 0)
6257 interval = stream->time_position - stream->last_keyframe_dts;
6259 interval = stream->last_keyframe_dts - stream->time_position;
6261 if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
6262 && interval < qtdemux->trickmode_interval) {
6263 GST_LOG_OBJECT (qtdemux,
6264 "Skipping keyframe within interval on track-id %u",
6268 stream->last_keyframe_dts = stream->time_position;
6274 GST_DEBUG_OBJECT (qtdemux,
6275 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6276 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6277 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6278 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6279 GST_TIME_ARGS (duration));
6281 if (G_UNLIKELY (empty)) {
6282 /* empty segment, push a gap if there's a second or more
6283 * difference and move to the next one */
6284 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6285 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6286 stream->segment.position = pts + duration;
6290 /* hmm, empty sample, skip and move to next sample */
6291 if (G_UNLIKELY (sample_size <= 0))
6294 /* last pushed sample was out of boundary, goto next sample */
6295 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6298 if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
6299 GST_DEBUG_OBJECT (qtdemux,
6300 "size %d larger than stream max_buffer_size %d, trimming",
6301 sample_size, stream->max_buffer_size);
6303 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6304 } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
6305 && sample_size < stream->min_buffer_size) {
6306 guint start_sample_index = stream->sample_index;
6307 guint accumulated_size = sample_size;
6308 guint64 expected_next_offset = offset + sample_size;
6310 GST_DEBUG_OBJECT (qtdemux,
6311 "size %d smaller than stream min_buffer_size %d, combining with the next",
6312 sample_size, stream->min_buffer_size);
6314 while (stream->sample_index < stream->to_sample
6315 && stream->sample_index + 1 < stream->n_samples) {
6316 const QtDemuxSample *next_sample;
6318 /* Increment temporarily */
6319 stream->sample_index++;
6321 /* Failed to parse sample so let's go back to the previous one that was
6322 * still successful */
6323 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6324 stream->sample_index--;
6328 next_sample = &stream->samples[stream->sample_index];
6330 /* Not contiguous with the previous sample so let's go back to the
6331 * previous one that was still successful */
6332 if (next_sample->offset != expected_next_offset) {
6333 stream->sample_index--;
6337 accumulated_size += next_sample->size;
6338 expected_next_offset += next_sample->size;
6339 if (accumulated_size >= stream->min_buffer_size)
6343 num_samples = stream->sample_index + 1 - start_sample_index;
6344 stream->sample_index = start_sample_index;
6345 GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
6346 num_samples, accumulated_size);
6347 size = accumulated_size;
6352 if (qtdemux->cenc_aux_info_offset > 0) {
6355 GstBuffer *aux_info = NULL;
6357 /* pull the data stored before the sample */
6359 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6360 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6361 if (G_UNLIKELY (ret != GST_FLOW_OK))
6363 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6364 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6365 gst_byte_reader_init (&br, map.data + 8, map.size);
6366 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6367 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6368 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6369 gst_buffer_unmap (aux_info, &map);
6370 gst_buffer_unref (aux_info);
6371 ret = GST_FLOW_ERROR;
6374 gst_buffer_unmap (aux_info, &map);
6375 gst_buffer_unref (aux_info);
6378 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6381 if (stream->use_allocator) {
6382 /* if we have a per-stream allocator, use it */
6383 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6386 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6388 if (G_UNLIKELY (ret != GST_FLOW_OK))
6391 /* Update for both splitting and combining of samples */
6392 if (size != sample_size) {
6393 pts += gst_util_uint64_scale_int (GST_SECOND,
6394 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6397 gst_util_uint64_scale_int (GST_SECOND,
6398 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6401 gst_util_uint64_scale_int (GST_SECOND,
6402 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6405 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6406 dts, pts, duration, keyframe, min_time, offset);
6408 if (size < sample_size) {
6409 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6410 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6412 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6414 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6415 if (time_position >= segment->media_start) {
6416 /* inside the segment, update time_position, looks very familiar to
6417 * GStreamer segments, doesn't it? */
6418 stream->time_position = (time_position - segment->media_start) +
6421 /* not yet in segment, time does not yet increment. This means
6422 * that we are still prerolling keyframes to the decoder so it can
6423 * decode the first sample of the segment. */
6424 stream->time_position = segment->time;
6426 } else if (size > sample_size) {
6427 /* Increase to the last sample we already pulled so that advancing
6428 * below brings us to the next sample we need to pull */
6429 stream->sample_index += num_samples - 1;
6433 GST_OBJECT_LOCK (qtdemux);
6434 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6435 GST_OBJECT_UNLOCK (qtdemux);
6436 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6437 * we have no more data for the pad to push */
6438 if (ret == GST_FLOW_EOS)
6441 stream->offset_in_sample += size;
6442 if (stream->offset_in_sample >= sample_size) {
6443 gst_qtdemux_advance_sample (qtdemux, stream);
6448 gst_qtdemux_advance_sample (qtdemux, stream);
6456 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6462 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6463 /* EOS will be raised if all are EOS */
6470 gst_qtdemux_loop (GstPad * pad)
6472 GstQTDemux *qtdemux;
6476 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6478 cur_offset = qtdemux->offset;
6479 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6480 cur_offset, qt_demux_state_string (qtdemux->state));
6482 switch (qtdemux->state) {
6483 case QTDEMUX_STATE_INITIAL:
6484 case QTDEMUX_STATE_HEADER:
6485 ret = gst_qtdemux_loop_state_header (qtdemux);
6487 case QTDEMUX_STATE_MOVIE:
6488 ret = gst_qtdemux_loop_state_movie (qtdemux);
6489 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6490 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6498 /* if something went wrong, pause */
6499 if (ret != GST_FLOW_OK)
6503 gst_object_unref (qtdemux);
6509 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6510 (NULL), ("streaming stopped, invalid state"));
6511 gst_pad_pause_task (pad);
6512 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6517 const gchar *reason = gst_flow_get_name (ret);
6519 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6521 gst_pad_pause_task (pad);
6523 /* fatal errors need special actions */
6525 if (ret == GST_FLOW_EOS) {
6526 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6527 /* we have no streams, post an error */
6528 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6530 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6533 if ((stop = qtdemux->segment.stop) == -1)
6534 stop = qtdemux->segment.duration;
6536 if (qtdemux->segment.rate >= 0) {
6537 GstMessage *message;
6540 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6541 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6542 GST_FORMAT_TIME, stop);
6543 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6544 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6545 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6546 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6548 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6549 gst_qtdemux_push_event (qtdemux, event);
6551 GstMessage *message;
6554 /* For Reverse Playback */
6555 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6556 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6557 GST_FORMAT_TIME, qtdemux->segment.start);
6558 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6559 qtdemux->segment.start);
6560 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6561 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6562 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6564 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6565 gst_qtdemux_push_event (qtdemux, event);
6570 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6571 event = gst_event_new_eos ();
6572 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6573 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6574 gst_qtdemux_push_event (qtdemux, event);
6576 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6577 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6578 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6587 * Returns if there are samples to be played.
6590 has_next_entry (GstQTDemux * demux)
6592 QtDemuxStream *stream;
6595 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6597 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6598 stream = QTDEMUX_NTH_STREAM (demux, i);
6600 if (stream->sample_index == -1) {
6601 stream->sample_index = 0;
6602 stream->offset_in_sample = 0;
6605 if (stream->sample_index >= stream->n_samples) {
6606 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6609 GST_DEBUG_OBJECT (demux, "Found a sample");
6613 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6620 * Returns the size of the first entry at the current offset.
6621 * If -1, there are none (which means EOS or empty file).
6624 next_entry_size (GstQTDemux * demux)
6626 QtDemuxStream *stream, *target_stream = NULL;
6627 guint64 smalloffs = (guint64) - 1;
6628 QtDemuxSample *sample;
6631 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6634 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6635 stream = QTDEMUX_NTH_STREAM (demux, i);
6637 if (stream->sample_index == -1) {
6638 stream->sample_index = 0;
6639 stream->offset_in_sample = 0;
6642 if (stream->sample_index >= stream->n_samples) {
6643 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6647 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6648 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6649 stream->sample_index);
6653 sample = &stream->samples[stream->sample_index];
6655 GST_LOG_OBJECT (demux,
6656 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6657 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6658 stream->sample_index, sample->offset, sample->size);
6660 if (((smalloffs == -1)
6661 || (sample->offset < smalloffs)) && (sample->size)) {
6662 smalloffs = sample->offset;
6663 target_stream = stream;
6670 GST_LOG_OBJECT (demux,
6671 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6672 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6674 stream = target_stream;
6675 sample = &stream->samples[stream->sample_index];
6677 if (sample->offset >= demux->offset) {
6678 demux->todrop = sample->offset - demux->offset;
6679 return sample->size + demux->todrop;
6682 GST_DEBUG_OBJECT (demux,
6683 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6688 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6690 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6692 gst_element_post_message (GST_ELEMENT_CAST (demux),
6693 gst_message_new_element (GST_OBJECT_CAST (demux),
6694 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6698 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6703 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6706 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6707 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6708 GST_SEEK_TYPE_NONE, -1);
6710 /* store seqnum to drop flush events, they don't need to reach downstream */
6711 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6712 res = gst_pad_push_event (demux->sinkpad, event);
6713 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6718 /* check for seekable upstream, above and beyond a mere query */
6720 gst_qtdemux_check_seekability (GstQTDemux * demux)
6723 gboolean seekable = FALSE;
6724 gint64 start = -1, stop = -1;
6726 if (demux->upstream_size)
6729 if (demux->upstream_format_is_time)
6732 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6733 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6734 GST_DEBUG_OBJECT (demux, "seeking query failed");
6738 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6740 /* try harder to query upstream size if we didn't get it the first time */
6741 if (seekable && stop == -1) {
6742 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6743 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6746 /* if upstream doesn't know the size, it's likely that it's not seekable in
6747 * practice even if it technically may be seekable */
6748 if (seekable && (start != 0 || stop <= start)) {
6749 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6754 gst_query_unref (query);
6756 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6757 G_GUINT64_FORMAT ")", seekable, start, stop);
6758 demux->upstream_seekable = seekable;
6759 demux->upstream_size = seekable ? stop : -1;
6763 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6765 g_return_if_fail (bytes <= demux->todrop);
6767 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6768 gst_adapter_flush (demux->adapter, bytes);
6769 demux->neededbytes -= bytes;
6770 demux->offset += bytes;
6771 demux->todrop -= bytes;
6774 /* PUSH-MODE only: Send a segment, if not done already. */
6776 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6778 if (G_UNLIKELY (demux->need_segment)) {
6781 if (!demux->upstream_format_is_time) {
6782 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6784 GstEvent *segment_event;
6785 segment_event = gst_event_new_segment (&demux->segment);
6786 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6787 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6788 gst_qtdemux_push_event (demux, segment_event);
6791 demux->need_segment = FALSE;
6793 /* clear to send tags on all streams */
6794 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6795 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6796 gst_qtdemux_push_tags (demux, stream);
6797 if (CUR_STREAM (stream)->sparse) {
6798 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6799 gst_pad_push_event (stream->pad,
6800 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6806 /* Used for push mode only. */
6808 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6809 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6811 GstClockTime ts, dur;
6815 stream->segments[segment_index].duration - (pos -
6816 stream->segments[segment_index].time);
6817 stream->time_position += dur;
6819 /* Only gaps with a duration of at least one second are propagated.
6820 * Same workaround as in pull mode.
6821 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6822 if (dur >= GST_SECOND) {
6824 gap = gst_event_new_gap (ts, dur);
6826 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6827 "segment: %" GST_PTR_FORMAT, gap);
6828 gst_pad_push_event (stream->pad, gap);
6832 static GstFlowReturn
6833 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6837 demux = GST_QTDEMUX (parent);
6839 GST_DEBUG_OBJECT (demux,
6840 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6841 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6842 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6843 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6844 gst_buffer_get_size (inbuf), demux->offset);
6846 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6847 gboolean is_gap_input = FALSE;
6850 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6852 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6853 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6856 /* Check if we can land back on our feet in the case where upstream is
6857 * handling the seeking/pushing of samples with gaps in between (like
6858 * in the case of trick-mode DASH for example) */
6859 if (demux->upstream_format_is_time
6860 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6861 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6863 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6864 GST_LOG_OBJECT (demux,
6865 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6866 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6868 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6869 stream, GST_BUFFER_OFFSET (inbuf));
6871 QtDemuxSample *sample = &stream->samples[res];
6872 GST_LOG_OBJECT (demux,
6873 "Checking if sample %d from track-id %u is valid (offset:%"
6874 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6875 stream->track_id, sample->offset, sample->size);
6876 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6877 GST_LOG_OBJECT (demux,
6878 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6880 is_gap_input = TRUE;
6881 /* We can go back to standard playback mode */
6882 demux->state = QTDEMUX_STATE_MOVIE;
6883 /* Remember which sample this stream is at */
6884 stream->sample_index = res;
6885 /* Finally update all push-based values to the expected values */
6886 demux->neededbytes = stream->samples[res].size;
6887 demux->offset = GST_BUFFER_OFFSET (inbuf);
6889 demux->mdatsize - demux->offset + demux->mdatoffset;
6894 if (!is_gap_input) {
6895 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6896 /* Reset state if it's a real discont */
6897 demux->neededbytes = 16;
6898 demux->state = QTDEMUX_STATE_INITIAL;
6899 demux->offset = GST_BUFFER_OFFSET (inbuf);
6900 gst_adapter_clear (demux->adapter);
6903 /* Reverse fragmented playback, need to flush all we have before
6904 * consuming a new fragment.
6905 * The samples array have the timestamps calculated by accumulating the
6906 * durations but this won't work for reverse playback of fragments as
6907 * the timestamps of a subsequent fragment should be smaller than the
6908 * previously received one. */
6909 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6910 gst_qtdemux_process_adapter (demux, TRUE);
6911 g_ptr_array_foreach (demux->active_streams,
6912 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6916 gst_adapter_push (demux->adapter, inbuf);
6918 GST_DEBUG_OBJECT (demux,
6919 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6920 demux->neededbytes, gst_adapter_available (demux->adapter));
6922 return gst_qtdemux_process_adapter (demux, FALSE);
6925 static GstFlowReturn
6926 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6928 GstFlowReturn ret = GST_FLOW_OK;
6930 /* we never really mean to buffer that much */
6931 if (demux->neededbytes == -1) {
6935 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6936 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6938 #ifndef GST_DISABLE_GST_DEBUG
6940 guint64 discont_offset, distance_from_discont;
6942 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6943 distance_from_discont =
6944 gst_adapter_distance_from_discont (demux->adapter);
6946 GST_DEBUG_OBJECT (demux,
6947 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6948 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6949 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6950 demux->offset, discont_offset, distance_from_discont);
6954 switch (demux->state) {
6955 case QTDEMUX_STATE_INITIAL:{
6960 gst_qtdemux_check_seekability (demux);
6962 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6964 /* get fourcc/length, set neededbytes */
6965 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6967 gst_adapter_unmap (demux->adapter);
6969 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6970 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6972 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6973 (_("This file is invalid and cannot be played.")),
6974 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6975 GST_FOURCC_ARGS (fourcc)));
6976 ret = GST_FLOW_ERROR;
6979 if (fourcc == FOURCC_mdat) {
6980 gint next_entry = next_entry_size (demux);
6981 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
6982 || !demux->fragmented)) {
6983 /* we have the headers, start playback */
6984 demux->state = QTDEMUX_STATE_MOVIE;
6985 demux->neededbytes = next_entry;
6986 demux->mdatleft = size;
6987 demux->mdatsize = demux->mdatleft;
6989 /* no headers yet, try to get them */
6992 guint64 old, target;
6995 old = demux->offset;
6996 target = old + size;
6998 /* try to jump over the atom with a seek */
6999 /* only bother if it seems worth doing so,
7000 * and avoids possible upstream/server problems */
7001 if (demux->upstream_seekable &&
7002 demux->upstream_size > 4 * (1 << 20)) {
7003 res = qtdemux_seek_offset (demux, target);
7005 GST_DEBUG_OBJECT (demux, "skipping seek");
7010 GST_DEBUG_OBJECT (demux, "seek success");
7011 /* remember the offset fo the first mdat so we can seek back to it
7012 * after we have the headers */
7013 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7014 demux->first_mdat = old;
7015 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7018 /* seek worked, continue reading */
7019 demux->offset = target;
7020 demux->neededbytes = 16;
7021 demux->state = QTDEMUX_STATE_INITIAL;
7023 /* seek failed, need to buffer */
7024 demux->offset = old;
7025 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7026 /* there may be multiple mdat (or alike) buffers */
7028 if (demux->mdatbuffer)
7029 bs = gst_buffer_get_size (demux->mdatbuffer);
7032 if (size + bs > 10 * (1 << 20))
7034 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7035 demux->neededbytes = size;
7036 if (!demux->mdatbuffer)
7037 demux->mdatoffset = demux->offset;
7040 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7041 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7042 (_("This file is invalid and cannot be played.")),
7043 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7044 GST_FOURCC_ARGS (fourcc), size));
7045 ret = GST_FLOW_ERROR;
7048 /* this means we already started buffering and still no moov header,
7049 * let's continue buffering everything till we get moov */
7050 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7051 || fourcc == FOURCC_moof))
7053 demux->neededbytes = size;
7054 demux->state = QTDEMUX_STATE_HEADER;
7058 case QTDEMUX_STATE_HEADER:{
7062 GST_DEBUG_OBJECT (demux, "In header");
7064 data = gst_adapter_map (demux->adapter, demux->neededbytes);
7066 /* parse the header */
7067 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7069 if (fourcc == FOURCC_moov) {
7070 /* in usual fragmented setup we could try to scan for more
7071 * and end up at the the moov (after mdat) again */
7072 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7074 || demux->last_moov_offset == demux->offset)) {
7075 GST_DEBUG_OBJECT (demux,
7076 "Skipping moov atom as we have (this) one already");
7078 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7080 if (demux->got_moov && demux->fragmented) {
7081 GST_DEBUG_OBJECT (demux,
7082 "Got a second moov, clean up data from old one");
7083 if (demux->moov_node_compressed) {
7084 g_node_destroy (demux->moov_node_compressed);
7085 if (demux->moov_node)
7086 g_free (demux->moov_node->data);
7088 demux->moov_node_compressed = NULL;
7089 if (demux->moov_node)
7090 g_node_destroy (demux->moov_node);
7091 demux->moov_node = NULL;
7094 demux->last_moov_offset = demux->offset;
7096 /* Update streams with new moov */
7097 gst_qtdemux_stream_concat (demux,
7098 demux->old_streams, demux->active_streams);
7100 qtdemux_parse_moov (demux, data, demux->neededbytes);
7101 qtdemux_node_dump (demux, demux->moov_node);
7102 qtdemux_parse_tree (demux);
7103 qtdemux_prepare_streams (demux);
7104 QTDEMUX_EXPOSE_LOCK (demux);
7105 qtdemux_expose_streams (demux);
7106 QTDEMUX_EXPOSE_UNLOCK (demux);
7108 demux->got_moov = TRUE;
7110 gst_qtdemux_check_send_pending_segment (demux);
7112 if (demux->moov_node_compressed) {
7113 g_node_destroy (demux->moov_node_compressed);
7114 g_free (demux->moov_node->data);
7116 demux->moov_node_compressed = NULL;
7117 g_node_destroy (demux->moov_node);
7118 demux->moov_node = NULL;
7119 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7121 } else if (fourcc == FOURCC_moof) {
7122 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7124 GstClockTime prev_pts;
7125 guint64 prev_offset;
7126 guint64 adapter_discont_offset, adapter_discont_dist;
7128 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7131 * The timestamp of the moof buffer is relevant as some scenarios
7132 * won't have the initial timestamp in the atoms. Whenever a new
7133 * buffer has started, we get that buffer's PTS and use it as a base
7134 * timestamp for the trun entries.
7136 * To keep track of the current buffer timestamp and starting point
7137 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7138 * from the beginning of the buffer, with the distance and demux->offset
7139 * we know if it is still the same buffer or not.
7141 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7142 prev_offset = demux->offset - dist;
7143 if (demux->fragment_start_offset == -1
7144 || prev_offset > demux->fragment_start_offset) {
7145 demux->fragment_start_offset = prev_offset;
7146 demux->fragment_start = prev_pts;
7147 GST_DEBUG_OBJECT (demux,
7148 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7149 GST_TIME_FORMAT, demux->fragment_start_offset,
7150 GST_TIME_ARGS (demux->fragment_start));
7153 /* We can't use prev_offset() here because this would require
7154 * upstream to set consistent and correct offsets on all buffers
7155 * since the discont. Nothing ever did that in the past and we
7156 * would break backwards compatibility here then.
7157 * Instead take the offset we had at the last discont and count
7158 * the bytes from there. This works with old code as there would
7159 * be no discont between moov and moof, and also works with
7160 * adaptivedemux which correctly sets offset and will set the
7161 * DISCONT flag accordingly when needed.
7163 * We also only do this for upstream TIME segments as otherwise
7164 * there are potential backwards compatibility problems with
7165 * seeking in PUSH mode and upstream providing inconsistent
7167 adapter_discont_offset =
7168 gst_adapter_offset_at_discont (demux->adapter);
7169 adapter_discont_dist =
7170 gst_adapter_distance_from_discont (demux->adapter);
7172 GST_DEBUG_OBJECT (demux,
7173 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7174 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7175 demux->offset, adapter_discont_offset, adapter_discont_dist);
7177 if (demux->upstream_format_is_time) {
7178 demux->moof_offset = adapter_discont_offset;
7179 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7180 demux->moof_offset += adapter_discont_dist;
7181 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7182 demux->moof_offset = demux->offset;
7184 demux->moof_offset = demux->offset;
7187 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7188 demux->moof_offset, NULL)) {
7189 gst_adapter_unmap (demux->adapter);
7190 ret = GST_FLOW_ERROR;
7194 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7195 if (demux->mss_mode && !demux->exposed) {
7196 QTDEMUX_EXPOSE_LOCK (demux);
7197 qtdemux_expose_streams (demux);
7198 QTDEMUX_EXPOSE_UNLOCK (demux);
7201 gst_qtdemux_check_send_pending_segment (demux);
7203 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7205 } else if (fourcc == FOURCC_ftyp) {
7206 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7207 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7208 } else if (fourcc == FOURCC_uuid) {
7209 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7210 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7211 } else if (fourcc == FOURCC_sidx) {
7212 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7213 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7217 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7221 /* [free] and [skip] are padding atoms */
7222 GST_DEBUG_OBJECT (demux,
7223 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7224 GST_FOURCC_ARGS (fourcc));
7227 GST_WARNING_OBJECT (demux,
7228 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7229 GST_FOURCC_ARGS (fourcc));
7230 /* Let's jump that one and go back to initial state */
7234 gst_adapter_unmap (demux->adapter);
7237 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7238 gsize remaining_data_size = 0;
7240 /* the mdat was before the header */
7241 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7242 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7243 /* restore our adapter/offset view of things with upstream;
7244 * put preceding buffered data ahead of current moov data.
7245 * This should also handle evil mdat, moov, mdat cases and alike */
7246 gst_adapter_flush (demux->adapter, demux->neededbytes);
7248 /* Store any remaining data after the mdat for later usage */
7249 remaining_data_size = gst_adapter_available (demux->adapter);
7250 if (remaining_data_size > 0) {
7251 g_assert (demux->restoredata_buffer == NULL);
7252 demux->restoredata_buffer =
7253 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7254 demux->restoredata_offset = demux->offset + demux->neededbytes;
7255 GST_DEBUG_OBJECT (demux,
7256 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7257 G_GUINT64_FORMAT, remaining_data_size,
7258 demux->restoredata_offset);
7261 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7262 demux->mdatbuffer = NULL;
7263 demux->offset = demux->mdatoffset;
7264 demux->neededbytes = next_entry_size (demux);
7265 demux->state = QTDEMUX_STATE_MOVIE;
7266 demux->mdatleft = gst_adapter_available (demux->adapter);
7267 demux->mdatsize = demux->mdatleft;
7269 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7270 gst_adapter_flush (demux->adapter, demux->neededbytes);
7272 /* only go back to the mdat if there are samples to play */
7273 if (demux->got_moov && demux->first_mdat != -1
7274 && has_next_entry (demux)) {
7277 /* we need to seek back */
7278 res = qtdemux_seek_offset (demux, demux->first_mdat);
7280 demux->offset = demux->first_mdat;
7282 GST_DEBUG_OBJECT (demux, "Seek back failed");
7285 demux->offset += demux->neededbytes;
7287 demux->neededbytes = 16;
7288 demux->state = QTDEMUX_STATE_INITIAL;
7293 case QTDEMUX_STATE_BUFFER_MDAT:{
7297 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7299 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7300 gst_buffer_extract (buf, 0, fourcc, 4);
7301 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7302 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7303 if (demux->mdatbuffer)
7304 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7306 demux->mdatbuffer = buf;
7307 demux->offset += demux->neededbytes;
7308 demux->neededbytes = 16;
7309 demux->state = QTDEMUX_STATE_INITIAL;
7310 gst_qtdemux_post_progress (demux, 1, 1);
7314 case QTDEMUX_STATE_MOVIE:{
7315 QtDemuxStream *stream = NULL;
7316 QtDemuxSample *sample;
7317 GstClockTime dts, pts, duration;
7321 GST_DEBUG_OBJECT (demux,
7322 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7324 if (demux->fragmented) {
7325 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7327 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7328 /* if needed data starts within this atom,
7329 * then it should not exceed this atom */
7330 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7331 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7332 (_("This file is invalid and cannot be played.")),
7333 ("sample data crosses atom boundary"));
7334 ret = GST_FLOW_ERROR;
7337 demux->mdatleft -= demux->neededbytes;
7339 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7340 /* so we are dropping more than left in this atom */
7341 gst_qtdemux_drop_data (demux, demux->mdatleft);
7342 demux->mdatleft = 0;
7344 /* need to resume atom parsing so we do not miss any other pieces */
7345 demux->state = QTDEMUX_STATE_INITIAL;
7346 demux->neededbytes = 16;
7348 /* check if there was any stored post mdat data from previous buffers */
7349 if (demux->restoredata_buffer) {
7350 g_assert (gst_adapter_available (demux->adapter) == 0);
7352 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7353 demux->restoredata_buffer = NULL;
7354 demux->offset = demux->restoredata_offset;
7361 if (demux->todrop) {
7362 if (demux->cenc_aux_info_offset > 0) {
7366 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7367 data = gst_adapter_map (demux->adapter, demux->todrop);
7368 gst_byte_reader_init (&br, data + 8, demux->todrop);
7369 if (!qtdemux_parse_cenc_aux_info (demux,
7370 QTDEMUX_NTH_STREAM (demux, 0), &br,
7371 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7372 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7373 ret = GST_FLOW_ERROR;
7374 gst_adapter_unmap (demux->adapter);
7375 g_free (demux->cenc_aux_info_sizes);
7376 demux->cenc_aux_info_sizes = NULL;
7379 demux->cenc_aux_info_offset = 0;
7380 g_free (demux->cenc_aux_info_sizes);
7381 demux->cenc_aux_info_sizes = NULL;
7382 gst_adapter_unmap (demux->adapter);
7384 gst_qtdemux_drop_data (demux, demux->todrop);
7388 /* initial newsegment sent here after having added pads,
7389 * possible others in sink_event */
7390 gst_qtdemux_check_send_pending_segment (demux);
7392 /* Figure out which stream this packet belongs to */
7393 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7394 stream = QTDEMUX_NTH_STREAM (demux, i);
7395 if (stream->sample_index >= stream->n_samples) {
7396 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7400 GST_LOG_OBJECT (demux,
7401 "Checking track-id %u (sample_index:%d / offset:%"
7402 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7403 stream->sample_index,
7404 stream->samples[stream->sample_index].offset,
7405 stream->samples[stream->sample_index].size);
7407 if (stream->samples[stream->sample_index].offset == demux->offset)
7411 if (G_UNLIKELY (stream == NULL))
7412 goto unknown_stream;
7414 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7416 if (stream->new_caps) {
7417 gst_qtdemux_configure_stream (demux, stream);
7420 /* Put data in a buffer, set timestamps, caps, ... */
7421 sample = &stream->samples[stream->sample_index];
7423 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7424 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7425 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7427 dts = QTSAMPLE_DTS (stream, sample);
7428 pts = QTSAMPLE_PTS (stream, sample);
7429 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7430 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7432 /* check for segment end */
7433 if (G_UNLIKELY (demux->segment.stop != -1
7434 && demux->segment.stop <= pts && stream->on_keyframe)
7435 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7436 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7437 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7439 /* skip this data, stream is EOS */
7440 gst_adapter_flush (demux->adapter, demux->neededbytes);
7441 demux->offset += demux->neededbytes;
7443 /* check if all streams are eos */
7445 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7446 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7455 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7457 /* FIXME: should either be an assert or a plain check */
7458 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7460 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7461 dts, pts, duration, keyframe, dts, demux->offset);
7465 GST_OBJECT_LOCK (demux);
7466 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7467 GST_OBJECT_UNLOCK (demux);
7469 /* skip this data, stream is EOS */
7470 gst_adapter_flush (demux->adapter, demux->neededbytes);
7473 stream->sample_index++;
7474 stream->offset_in_sample = 0;
7476 /* update current offset and figure out size of next buffer */
7477 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7478 demux->offset, demux->neededbytes);
7479 demux->offset += demux->neededbytes;
7480 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7484 if (ret == GST_FLOW_EOS) {
7485 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7486 demux->neededbytes = -1;
7490 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7491 if (demux->fragmented) {
7492 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7493 /* there may be more to follow, only finish this atom */
7494 demux->todrop = demux->mdatleft;
7495 demux->neededbytes = demux->todrop;
7500 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7501 goto non_ok_unlinked_flow;
7510 /* when buffering movie data, at least show user something is happening */
7511 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7512 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7513 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7514 demux->neededbytes);
7521 non_ok_unlinked_flow:
7523 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7524 gst_flow_get_name (ret));
7529 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7530 ret = GST_FLOW_ERROR;
7535 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7541 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7542 (NULL), ("qtdemuxer invalid state %d", demux->state));
7543 ret = GST_FLOW_ERROR;
7548 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7549 (NULL), ("no 'moov' atom within the first 10 MB"));
7550 ret = GST_FLOW_ERROR;
7556 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7561 query = gst_query_new_scheduling ();
7563 if (!gst_pad_peer_query (sinkpad, query)) {
7564 gst_query_unref (query);
7568 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7569 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7570 gst_query_unref (query);
7575 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7576 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7580 GST_DEBUG_OBJECT (sinkpad, "activating push");
7581 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7586 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7587 GstPadMode mode, gboolean active)
7590 GstQTDemux *demux = GST_QTDEMUX (parent);
7593 case GST_PAD_MODE_PUSH:
7594 demux->pullbased = FALSE;
7597 case GST_PAD_MODE_PULL:
7599 demux->pullbased = TRUE;
7600 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7603 res = gst_pad_stop_task (sinkpad);
7615 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7621 memset (&z, 0, sizeof (z));
7626 if ((ret = inflateInit (&z)) != Z_OK) {
7627 GST_ERROR ("inflateInit() returned %d", ret);
7631 z.next_in = z_buffer;
7632 z.avail_in = z_length;
7634 buffer = (guint8 *) g_malloc (*length);
7635 z.avail_out = *length;
7636 z.next_out = (Bytef *) buffer;
7638 ret = inflate (&z, Z_NO_FLUSH);
7639 if (ret == Z_STREAM_END) {
7641 } else if (ret != Z_OK) {
7642 GST_WARNING ("inflate() returned %d", ret);
7647 buffer = (guint8 *) g_realloc (buffer, *length);
7648 z.next_out = (Bytef *) (buffer + z.total_out);
7649 z.avail_out += 4096;
7650 } while (z.avail_in > 0);
7652 if (ret != Z_STREAM_END) {
7657 *length = z.total_out;
7664 #endif /* HAVE_ZLIB */
7667 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7671 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7673 /* counts as header data */
7674 qtdemux->header_size += length;
7676 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7677 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7679 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7686 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7687 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7688 if (dcom == NULL || cmvd == NULL)
7689 goto invalid_compression;
7691 dcom_len = QT_UINT32 (dcom->data);
7693 goto invalid_compression;
7695 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7699 guint uncompressed_length;
7700 guint compressed_length;
7704 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7706 goto invalid_compression;
7708 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7709 compressed_length = cmvd_len - 12;
7710 GST_LOG ("length = %u", uncompressed_length);
7713 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7714 compressed_length, &uncompressed_length);
7717 qtdemux->moov_node_compressed = qtdemux->moov_node;
7718 qtdemux->moov_node = g_node_new (buf);
7720 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7721 uncompressed_length);
7725 #endif /* HAVE_ZLIB */
7727 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7728 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7735 invalid_compression:
7737 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7743 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7746 while (G_UNLIKELY (buf < end)) {
7750 if (G_UNLIKELY (buf + 4 > end)) {
7751 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7754 len = QT_UINT32 (buf);
7755 if (G_UNLIKELY (len == 0)) {
7756 GST_LOG_OBJECT (qtdemux, "empty container");
7759 if (G_UNLIKELY (len < 8)) {
7760 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7763 if (G_UNLIKELY (len > (end - buf))) {
7764 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7765 (gint) (end - buf));
7769 child = g_node_new ((guint8 *) buf);
7770 g_node_append (node, child);
7771 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7772 qtdemux_parse_node (qtdemux, child, buf, len);
7780 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7783 int len = QT_UINT32 (xdxt->data);
7784 guint8 *buf = xdxt->data;
7785 guint8 *end = buf + len;
7788 /* skip size and type */
7796 size = QT_UINT32 (buf);
7797 type = QT_FOURCC (buf + 4);
7799 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7801 if (buf + size > end || size <= 0)
7807 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7808 GST_FOURCC_ARGS (type));
7812 buffer = gst_buffer_new_and_alloc (size);
7813 gst_buffer_fill (buffer, 0, buf, size);
7814 stream->buffers = g_slist_append (stream->buffers, buffer);
7815 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7818 buffer = gst_buffer_new_and_alloc (size);
7819 gst_buffer_fill (buffer, 0, buf, size);
7820 stream->buffers = g_slist_append (stream->buffers, buffer);
7821 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7824 buffer = gst_buffer_new_and_alloc (size);
7825 gst_buffer_fill (buffer, 0, buf, size);
7826 stream->buffers = g_slist_append (stream->buffers, buffer);
7827 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7830 GST_WARNING_OBJECT (qtdemux,
7831 "unknown theora cookie %" GST_FOURCC_FORMAT,
7832 GST_FOURCC_ARGS (type));
7841 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7845 guint32 node_length = 0;
7846 const QtNodeType *type;
7849 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7851 if (G_UNLIKELY (length < 8))
7852 goto not_enough_data;
7854 node_length = QT_UINT32 (buffer);
7855 fourcc = QT_FOURCC (buffer + 4);
7857 /* ignore empty nodes */
7858 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7861 type = qtdemux_type_get (fourcc);
7863 end = buffer + length;
7865 GST_LOG_OBJECT (qtdemux,
7866 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7867 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7869 if (node_length > length)
7870 goto broken_atom_size;
7872 if (type->flags & QT_FLAG_CONTAINER) {
7873 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7878 if (node_length < 20) {
7879 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7882 GST_DEBUG_OBJECT (qtdemux,
7883 "parsing stsd (sample table, sample description) atom");
7884 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7885 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7897 /* also read alac (or whatever) in stead of mp4a in the following,
7898 * since a similar layout is used in other cases as well */
7899 if (fourcc == FOURCC_mp4a)
7901 else if (fourcc == FOURCC_fLaC)
7906 /* There are two things we might encounter here: a true mp4a atom, and
7907 an mp4a entry in an stsd atom. The latter is what we're interested
7908 in, and it looks like an atom, but isn't really one. The true mp4a
7909 atom is short, so we detect it based on length here. */
7910 if (length < min_size) {
7911 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7912 GST_FOURCC_ARGS (fourcc));
7916 /* 'version' here is the sound sample description version. Types 0 and
7917 1 are documented in the QTFF reference, but type 2 is not: it's
7918 described in Apple header files instead (struct SoundDescriptionV2
7920 version = QT_UINT16 (buffer + 16);
7922 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7923 GST_FOURCC_ARGS (fourcc), version);
7925 /* parse any esds descriptors */
7937 GST_WARNING_OBJECT (qtdemux,
7938 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7939 GST_FOURCC_ARGS (fourcc), version);
7944 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7972 /* codec_data is contained inside these atoms, which all have
7973 * the same format. */
7974 /* video sample description size is 86 bytes without extension.
7975 * node_length have to be bigger than 86 bytes because video sample
7976 * description can include extensions such as esds, fiel, glbl, etc. */
7977 if (node_length < 86) {
7978 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7979 " sample description length too short (%u < 86)",
7980 GST_FOURCC_ARGS (fourcc), node_length);
7984 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7985 GST_FOURCC_ARGS (fourcc));
7987 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7989 * revision level (2 bytes) : must be set to 0. */
7990 version = QT_UINT32 (buffer + 16);
7991 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7993 /* compressor name : PASCAL string and informative purposes
7994 * first byte : the number of bytes to be displayed.
7995 * it has to be less than 32 because it is reserved
7996 * space of 32 bytes total including itself. */
7997 str_len = QT_UINT8 (buffer + 50);
7999 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8000 (char *) buffer + 51);
8002 GST_WARNING_OBJECT (qtdemux,
8003 "compressorname length too big (%u > 31)", str_len);
8005 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8007 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8012 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8014 /* You are reading this correctly. QTFF specifies that the
8015 * metadata atom is a short atom, whereas ISO BMFF specifies
8016 * it's a full atom. But since so many people are doing things
8017 * differently, we actually peek into the atom to see which
8020 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8021 GST_FOURCC_ARGS (fourcc));
8024 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8025 /* Variant 1: What QTFF specifies. 'meta' is a short header which
8026 * starts with a 'hdlr' atom */
8027 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8028 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8029 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8030 * with version/flags both set to zero */
8031 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8033 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8038 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8039 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8040 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8049 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8050 GST_FOURCC_ARGS (fourcc));
8054 version = QT_UINT32 (buffer + 12);
8055 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8062 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8067 if (length < offset) {
8068 GST_WARNING_OBJECT (qtdemux,
8069 "skipping too small %" GST_FOURCC_FORMAT " box",
8070 GST_FOURCC_ARGS (fourcc));
8073 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8079 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8084 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8089 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8093 if (!strcmp (type->name, "unknown"))
8094 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8098 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8099 GST_FOURCC_ARGS (fourcc));
8105 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8106 (_("This file is corrupt and cannot be played.")),
8107 ("Not enough data for an atom header, got only %u bytes", length));
8112 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8113 (_("This file is corrupt and cannot be played.")),
8114 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8115 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8122 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8124 /* FIXME: This can only reliably work if demuxers have a
8125 * separate streaming thread per srcpad. This should be
8126 * done in a demuxer base class, which integrates parts
8129 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8134 query = gst_query_new_allocation (stream->caps, FALSE);
8136 if (!gst_pad_peer_query (stream->pad, query)) {
8137 /* not a problem, just debug a little */
8138 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8141 if (stream->allocator)
8142 gst_object_unref (stream->allocator);
8144 if (gst_query_get_n_allocation_params (query) > 0) {
8145 /* try the allocator */
8146 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8148 stream->use_allocator = TRUE;
8150 stream->allocator = NULL;
8151 gst_allocation_params_init (&stream->params);
8152 stream->use_allocator = FALSE;
8154 gst_query_unref (query);
8159 pad_query (const GValue * item, GValue * value, gpointer user_data)
8161 GstPad *pad = g_value_get_object (item);
8162 GstQuery *query = user_data;
8165 res = gst_pad_peer_query (pad, query);
8168 g_value_set_boolean (value, TRUE);
8172 GST_INFO_OBJECT (pad, "pad peer query failed");
8177 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8178 GstPadDirection direction)
8181 GstIteratorFoldFunction func = pad_query;
8182 GValue res = { 0, };
8184 g_value_init (&res, G_TYPE_BOOLEAN);
8185 g_value_set_boolean (&res, FALSE);
8188 if (direction == GST_PAD_SRC)
8189 it = gst_element_iterate_src_pads (element);
8191 it = gst_element_iterate_sink_pads (element);
8193 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8194 gst_iterator_resync (it);
8196 gst_iterator_free (it);
8198 return g_value_get_boolean (&res);
8202 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8203 QtDemuxStream * stream)
8207 GstElement *element = GST_ELEMENT (qtdemux);
8209 gchar **filtered_sys_ids;
8210 GValue event_list = G_VALUE_INIT;
8213 /* 1. Check if we already have the context. */
8214 if (qtdemux->preferred_protection_system_id != NULL) {
8215 GST_LOG_OBJECT (element,
8216 "already have the protection context, no need to request it again");
8220 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8221 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8222 (const gchar **) qtdemux->protection_system_ids->pdata);
8224 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8225 qtdemux->protection_system_ids->len - 1);
8226 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8227 "decryptors for %u of them, running context request",
8228 qtdemux->protection_system_ids->len,
8229 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8232 if (stream->protection_scheme_event_queue.length) {
8233 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8234 stream->protection_scheme_event_queue.length);
8235 walk = stream->protection_scheme_event_queue.tail;
8237 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8238 qtdemux->protection_event_queue.length);
8239 walk = qtdemux->protection_event_queue.tail;
8242 g_value_init (&event_list, GST_TYPE_LIST);
8243 for (; walk; walk = g_list_previous (walk)) {
8244 GValue *event_value = g_new0 (GValue, 1);
8245 g_value_init (event_value, GST_TYPE_EVENT);
8246 g_value_set_boxed (event_value, walk->data);
8247 gst_value_list_append_and_take_value (&event_list, event_value);
8250 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8251 * check if downstream already has a context of the specific type
8252 * 2b) Query upstream as above.
8254 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8255 st = gst_query_writable_structure (query);
8256 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8257 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8259 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8260 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8261 gst_query_parse_context (query, &ctxt);
8262 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8263 gst_element_set_context (element, ctxt);
8264 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8265 gst_query_parse_context (query, &ctxt);
8266 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8267 gst_element_set_context (element, ctxt);
8269 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8270 * the required context type and afterwards check if a
8271 * usable context was set now as in 1). The message could
8272 * be handled by the parent bins of the element and the
8277 GST_INFO_OBJECT (element, "posting need context message");
8278 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8279 "drm-preferred-decryption-system-id");
8280 st = (GstStructure *) gst_message_get_structure (msg);
8281 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8282 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8285 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8286 gst_element_post_message (element, msg);
8289 g_strfreev (filtered_sys_ids);
8290 g_value_unset (&event_list);
8291 gst_query_unref (query);
8295 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8296 QtDemuxStream * stream)
8299 const gchar *selected_system = NULL;
8301 g_return_val_if_fail (qtdemux != NULL, FALSE);
8302 g_return_val_if_fail (stream != NULL, FALSE);
8303 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8306 if (stream->protection_scheme_type == FOURCC_aavd) {
8307 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8308 if (!gst_structure_has_name (s, "application/x-aavd")) {
8309 gst_structure_set (s,
8310 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8312 gst_structure_set_name (s, "application/x-aavd");
8317 if (stream->protection_scheme_type != FOURCC_cenc) {
8318 GST_ERROR_OBJECT (qtdemux,
8319 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8320 GST_FOURCC_ARGS (stream->protection_scheme_type));
8324 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8325 if (!gst_structure_has_name (s, "application/x-cenc")) {
8326 gst_structure_set (s,
8327 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
8328 gst_structure_set_name (s, "application/x-cenc");
8331 if (qtdemux->protection_system_ids == NULL) {
8332 GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
8333 "cenc protection system information has been found, not setting a "
8334 "protection system UUID");
8338 gst_qtdemux_request_protection_context (qtdemux, stream);
8339 if (qtdemux->preferred_protection_system_id != NULL) {
8340 const gchar *preferred_system_array[] =
8341 { qtdemux->preferred_protection_system_id, NULL };
8343 selected_system = gst_protection_select_system (preferred_system_array);
8345 if (selected_system) {
8346 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8347 qtdemux->preferred_protection_system_id);
8349 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8350 "because there is no available decryptor",
8351 qtdemux->preferred_protection_system_id);
8355 if (!selected_system) {
8356 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8357 selected_system = gst_protection_select_system ((const gchar **)
8358 qtdemux->protection_system_ids->pdata);
8359 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8360 qtdemux->protection_system_ids->len - 1);
8363 if (!selected_system) {
8364 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8365 "suitable decryptor element has been found");
8369 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8372 gst_structure_set (s,
8373 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8380 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8382 /* fps is calculated base on the duration of the average framerate since
8383 * qt does not have a fixed framerate. */
8384 gboolean fps_available = TRUE;
8385 guint32 first_duration = 0;
8387 if (stream->n_samples > 0)
8388 first_duration = stream->samples[0].duration;
8390 if ((stream->n_samples == 1 && first_duration == 0)
8391 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8393 CUR_STREAM (stream)->fps_n = 0;
8394 CUR_STREAM (stream)->fps_d = 1;
8396 if (stream->duration == 0 || stream->n_samples < 2) {
8397 CUR_STREAM (stream)->fps_n = stream->timescale;
8398 CUR_STREAM (stream)->fps_d = 1;
8399 fps_available = FALSE;
8401 GstClockTime avg_duration;
8405 /* duration and n_samples can be updated for fragmented format
8406 * so, framerate of fragmented format is calculated using data in a moof */
8407 if (qtdemux->fragmented && stream->n_samples_moof > 0
8408 && stream->duration_moof > 0) {
8409 n_samples = stream->n_samples_moof;
8410 duration = stream->duration_moof;
8412 n_samples = stream->n_samples;
8413 duration = stream->duration;
8416 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8417 /* stream->duration is guint64, timescale, n_samples are guint32 */
8419 gst_util_uint64_scale_round (duration -
8420 first_duration, GST_SECOND,
8421 (guint64) (stream->timescale) * (n_samples - 1));
8423 GST_LOG_OBJECT (qtdemux,
8424 "Calculating avg sample duration based on stream (or moof) duration %"
8426 " minus first sample %u, leaving %d samples gives %"
8427 GST_TIME_FORMAT, duration, first_duration,
8428 n_samples - 1, GST_TIME_ARGS (avg_duration));
8431 gst_video_guess_framerate (avg_duration,
8432 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
8434 GST_DEBUG_OBJECT (qtdemux,
8435 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8436 stream->timescale, CUR_STREAM (stream)->fps_n,
8437 CUR_STREAM (stream)->fps_d);
8441 return fps_available;
8445 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8447 if (stream->subtype == FOURCC_vide) {
8448 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8450 if (CUR_STREAM (stream)->caps) {
8451 CUR_STREAM (stream)->caps =
8452 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8454 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8455 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8456 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8457 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8459 /* set framerate if calculated framerate is reliable */
8460 if (fps_available) {
8461 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8462 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8463 CUR_STREAM (stream)->fps_d, NULL);
8466 /* calculate pixel-aspect-ratio using display width and height */
8467 GST_DEBUG_OBJECT (qtdemux,
8468 "video size %dx%d, target display size %dx%d",
8469 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8470 stream->display_width, stream->display_height);
8471 /* qt file might have pasp atom */
8472 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8473 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8474 CUR_STREAM (stream)->par_h);
8475 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8476 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8477 CUR_STREAM (stream)->par_h, NULL);
8478 } else if (stream->display_width > 0 && stream->display_height > 0
8479 && CUR_STREAM (stream)->width > 0
8480 && CUR_STREAM (stream)->height > 0) {
8483 /* calculate the pixel aspect ratio using the display and pixel w/h */
8484 n = stream->display_width * CUR_STREAM (stream)->height;
8485 d = stream->display_height * CUR_STREAM (stream)->width;
8488 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8489 CUR_STREAM (stream)->par_w = n;
8490 CUR_STREAM (stream)->par_h = d;
8491 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8492 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8493 CUR_STREAM (stream)->par_h, NULL);
8496 if (CUR_STREAM (stream)->interlace_mode > 0) {
8497 if (CUR_STREAM (stream)->interlace_mode == 1) {
8498 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8499 G_TYPE_STRING, "progressive", NULL);
8500 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8501 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8502 G_TYPE_STRING, "interleaved", NULL);
8503 if (CUR_STREAM (stream)->field_order == 9) {
8504 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8505 G_TYPE_STRING, "top-field-first", NULL);
8506 } else if (CUR_STREAM (stream)->field_order == 14) {
8507 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8508 G_TYPE_STRING, "bottom-field-first", NULL);
8513 /* Create incomplete colorimetry here if needed */
8514 if (CUR_STREAM (stream)->colorimetry.range ||
8515 CUR_STREAM (stream)->colorimetry.matrix ||
8516 CUR_STREAM (stream)->colorimetry.transfer
8517 || CUR_STREAM (stream)->colorimetry.primaries) {
8518 gchar *colorimetry =
8519 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8520 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8521 G_TYPE_STRING, colorimetry, NULL);
8522 g_free (colorimetry);
8525 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8526 guint par_w = 1, par_h = 1;
8528 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8529 par_w = CUR_STREAM (stream)->par_w;
8530 par_h = CUR_STREAM (stream)->par_h;
8533 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8534 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8536 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8539 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8540 "multiview-mode", G_TYPE_STRING,
8541 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8542 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8543 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8548 else if (stream->subtype == FOURCC_soun) {
8549 if (CUR_STREAM (stream)->caps) {
8550 CUR_STREAM (stream)->caps =
8551 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8552 if (CUR_STREAM (stream)->rate > 0)
8553 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8554 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8555 if (CUR_STREAM (stream)->n_channels > 0)
8556 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8557 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8558 if (CUR_STREAM (stream)->n_channels > 2) {
8559 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8560 * correctly; this is just the minimum we can do - assume
8561 * we don't actually have any channel positions. */
8562 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8563 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8568 else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
8569 const GstStructure *s;
8570 QtDemuxStream *fps_stream = NULL;
8571 gboolean fps_available = FALSE;
8573 /* CEA608 closed caption tracks are a bit special in that each sample
8574 * can contain CCs for multiple frames, and CCs can be omitted and have to
8575 * be inferred from the duration of the sample then.
8577 * As such we take the framerate from the (first) video track here for
8578 * CEA608 as there must be one CC byte pair for every video frame
8579 * according to the spec.
8581 * For CEA708 all is fine and there is one sample per frame.
8584 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8585 if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
8588 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
8589 QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
8591 if (tmp->subtype == FOURCC_vide) {
8598 fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
8599 CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
8600 CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
8603 fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8604 fps_stream = stream;
8607 CUR_STREAM (stream)->caps =
8608 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8610 /* set framerate if calculated framerate is reliable */
8611 if (fps_available) {
8612 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8613 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8614 CUR_STREAM (stream)->fps_d, NULL);
8619 GstCaps *prev_caps = NULL;
8621 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8622 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8623 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8624 gst_pad_set_active (stream->pad, TRUE);
8626 gst_pad_use_fixed_caps (stream->pad);
8628 if (stream->protected) {
8629 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8630 GST_ERROR_OBJECT (qtdemux,
8631 "Failed to configure protected stream caps.");
8636 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8637 CUR_STREAM (stream)->caps);
8638 if (stream->new_stream) {
8640 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8643 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8646 gst_event_parse_stream_flags (event, &stream_flags);
8647 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8648 qtdemux->have_group_id = TRUE;
8650 qtdemux->have_group_id = FALSE;
8651 gst_event_unref (event);
8652 } else if (!qtdemux->have_group_id) {
8653 qtdemux->have_group_id = TRUE;
8654 qtdemux->group_id = gst_util_group_id_next ();
8657 stream->new_stream = FALSE;
8658 event = gst_event_new_stream_start (stream->stream_id);
8659 if (qtdemux->have_group_id)
8660 gst_event_set_group_id (event, qtdemux->group_id);
8661 if (stream->disabled)
8662 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8663 if (CUR_STREAM (stream)->sparse) {
8664 stream_flags |= GST_STREAM_FLAG_SPARSE;
8666 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8668 gst_event_set_stream_flags (event, stream_flags);
8669 gst_pad_push_event (stream->pad, event);
8672 prev_caps = gst_pad_get_current_caps (stream->pad);
8674 if (CUR_STREAM (stream)->caps) {
8676 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8677 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8678 CUR_STREAM (stream)->caps);
8679 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8681 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8684 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8688 gst_caps_unref (prev_caps);
8689 stream->new_caps = FALSE;
8695 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8696 QtDemuxStream * stream)
8698 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8701 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8702 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8703 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8704 stream->stsd_entries_length)) {
8705 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8706 (_("This file is invalid and cannot be played.")),
8707 ("New sample description id is out of bounds (%d >= %d)",
8708 stream->stsd_sample_description_id, stream->stsd_entries_length));
8710 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8711 stream->new_caps = TRUE;
8716 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8717 QtDemuxStream * stream, GstTagList * list)
8719 gboolean ret = TRUE;
8721 if (stream->subtype == FOURCC_vide) {
8722 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8725 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8728 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8729 gst_object_unref (stream->pad);
8735 qtdemux->n_video_streams++;
8736 } else if (stream->subtype == FOURCC_soun) {
8737 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8740 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8742 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8743 gst_object_unref (stream->pad);
8748 qtdemux->n_audio_streams++;
8749 } else if (stream->subtype == FOURCC_strm) {
8750 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8751 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8752 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8753 || stream->subtype == FOURCC_clcp) {
8754 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8757 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8759 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8760 gst_object_unref (stream->pad);
8765 qtdemux->n_sub_streams++;
8766 } else if (CUR_STREAM (stream)->caps) {
8767 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8770 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8772 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8773 gst_object_unref (stream->pad);
8778 qtdemux->n_video_streams++;
8780 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8787 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8788 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8789 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8790 GST_OBJECT_LOCK (qtdemux);
8791 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8792 GST_OBJECT_UNLOCK (qtdemux);
8794 if (stream->stream_tags)
8795 gst_tag_list_unref (stream->stream_tags);
8796 stream->stream_tags = list;
8798 /* global tags go on each pad anyway */
8799 stream->send_global_tags = TRUE;
8800 /* send upstream GST_EVENT_PROTECTION events that were received before
8801 this source pad was created */
8802 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8803 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8807 gst_tag_list_unref (list);
8811 /* find next atom with @fourcc starting at @offset */
8812 static GstFlowReturn
8813 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8814 guint64 * length, guint32 fourcc)
8820 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8821 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8827 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8828 if (G_UNLIKELY (ret != GST_FLOW_OK))
8830 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8833 gst_buffer_unref (buf);
8836 gst_buffer_map (buf, &map, GST_MAP_READ);
8837 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8838 gst_buffer_unmap (buf, &map);
8839 gst_buffer_unref (buf);
8841 if (G_UNLIKELY (*length == 0)) {
8842 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8843 ret = GST_FLOW_ERROR;
8847 if (lfourcc == fourcc) {
8848 GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
8849 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8852 GST_LOG_OBJECT (qtdemux,
8853 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8854 GST_FOURCC_ARGS (lfourcc), *offset);
8855 if (*offset == G_MAXUINT64)
8865 /* might simply have had last one */
8866 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8871 /* should only do something in pull mode */
8872 /* call with OBJECT lock */
8873 static GstFlowReturn
8874 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8876 guint64 length, offset;
8877 GstBuffer *buf = NULL;
8878 GstFlowReturn ret = GST_FLOW_OK;
8879 GstFlowReturn res = GST_FLOW_OK;
8882 offset = qtdemux->moof_offset;
8883 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8886 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8887 return GST_FLOW_EOS;
8890 /* best not do pull etc with lock held */
8891 GST_OBJECT_UNLOCK (qtdemux);
8893 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8894 if (ret != GST_FLOW_OK)
8897 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8898 if (G_UNLIKELY (ret != GST_FLOW_OK))
8900 gst_buffer_map (buf, &map, GST_MAP_READ);
8901 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8902 gst_buffer_unmap (buf, &map);
8903 gst_buffer_unref (buf);
8908 gst_buffer_unmap (buf, &map);
8909 gst_buffer_unref (buf);
8913 /* look for next moof */
8914 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8915 if (G_UNLIKELY (ret != GST_FLOW_OK))
8919 GST_OBJECT_LOCK (qtdemux);
8921 qtdemux->moof_offset = offset;
8927 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8929 res = GST_FLOW_ERROR;
8934 /* maybe upstream temporarily flushing */
8935 if (ret != GST_FLOW_FLUSHING) {
8936 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8939 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8940 /* resume at current position next time */
8948 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
8952 gint32 stts_duration;
8953 GstByteWriter stsc, stts, stsz;
8955 /* Each sample has a different size, which we don't support for merging */
8956 if (stream->sample_size == 0) {
8957 GST_DEBUG_OBJECT (qtdemux,
8958 "Not all samples have the same size, not merging");
8962 /* The stream has a ctts table, we don't support that */
8963 if (stream->ctts_present) {
8964 GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
8968 /* If there's a sync sample table also ignore this stream */
8969 if (stream->stps_present || stream->stss_present) {
8970 GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
8974 /* If chunks are considered samples already ignore this stream */
8975 if (stream->chunks_are_samples) {
8976 GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
8980 /* Require that all samples have the same duration */
8981 if (stream->n_sample_times > 1) {
8982 GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
8986 /* Parse the stts to get the sample duration and number of samples */
8987 gst_byte_reader_skip_unchecked (&stream->stts, 4);
8988 stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8990 /* Parse the number of chunks from the stco manually because the
8991 * reader is already behind that */
8992 num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
8994 GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
8997 /* Now parse stsc, convert chunks into single samples and generate a
8998 * new stsc, stts and stsz from this information */
8999 gst_byte_writer_init (&stsc);
9000 gst_byte_writer_init (&stts);
9001 gst_byte_writer_init (&stsz);
9003 /* Note: we skip fourccs, size, version, flags and other fields of the new
9004 * atoms as the byte readers with them are already behind that position
9005 * anyway and only update the values of those inside the stream directly.
9007 stream->n_sample_times = 0;
9008 stream->n_samples = 0;
9009 for (i = 0; i < stream->n_samples_per_chunk; i++) {
9011 guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
9013 first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9014 samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9015 sample_description_id =
9016 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9018 if (i == stream->n_samples_per_chunk - 1) {
9019 /* +1 because first_chunk is 1-based */
9020 last_chunk = num_chunks + 1;
9022 last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9025 GST_DEBUG_OBJECT (qtdemux,
9026 "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
9027 first_chunk, last_chunk, samples_per_chunk, sample_description_id);
9029 gst_byte_writer_put_uint32_be (&stsc, first_chunk);
9030 /* One sample in this chunk */
9031 gst_byte_writer_put_uint32_be (&stsc, 1);
9032 gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
9034 /* For each chunk write a stts and stsz entry now */
9035 gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
9036 gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
9037 for (j = first_chunk; j < last_chunk; j++) {
9038 gst_byte_writer_put_uint32_be (&stsz,
9039 stream->sample_size * samples_per_chunk);
9042 stream->n_sample_times += 1;
9043 stream->n_samples += last_chunk - first_chunk;
9046 g_assert_cmpint (stream->n_samples, ==, num_chunks);
9048 GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
9049 stream->n_samples, stream->n_sample_times);
9051 /* We don't have a fixed sample size anymore */
9052 stream->sample_size = 0;
9054 /* Free old data for the atoms */
9055 g_free ((gpointer) stream->stsz.data);
9056 stream->stsz.data = NULL;
9057 g_free ((gpointer) stream->stsc.data);
9058 stream->stsc.data = NULL;
9059 g_free ((gpointer) stream->stts.data);
9060 stream->stts.data = NULL;
9062 /* Store new data and replace byte readers */
9063 stream->stsz.size = gst_byte_writer_get_size (&stsz);
9064 stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
9065 gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
9066 stream->stts.size = gst_byte_writer_get_size (&stts);
9067 stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
9068 gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
9069 stream->stsc.size = gst_byte_writer_get_size (&stsc);
9070 stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
9071 gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
9074 /* initialise bytereaders for stbl sub-atoms */
9076 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9078 stream->stbl_index = -1; /* no samples have yet been parsed */
9079 stream->sample_index = -1;
9081 /* time-to-sample atom */
9082 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9085 /* copy atom data into a new buffer for later use */
9086 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
9088 /* skip version + flags */
9089 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9090 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9092 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9094 /* make sure there's enough data */
9095 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9096 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9097 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9098 stream->n_sample_times);
9099 if (!stream->n_sample_times)
9103 /* sync sample atom */
9104 stream->stps_present = FALSE;
9105 if ((stream->stss_present =
9106 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9107 &stream->stss) ? TRUE : FALSE) == TRUE) {
9108 /* copy atom data into a new buffer for later use */
9109 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
9111 /* skip version + flags */
9112 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9113 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9116 if (stream->n_sample_syncs) {
9117 /* make sure there's enough data */
9118 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9122 /* partial sync sample atom */
9123 if ((stream->stps_present =
9124 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9125 &stream->stps) ? TRUE : FALSE) == TRUE) {
9126 /* copy atom data into a new buffer for later use */
9127 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
9129 /* skip version + flags */
9130 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9131 !gst_byte_reader_get_uint32_be (&stream->stps,
9132 &stream->n_sample_partial_syncs))
9135 /* if there are no entries, the stss table contains the real
9137 if (stream->n_sample_partial_syncs) {
9138 /* make sure there's enough data */
9139 if (!qt_atom_parser_has_chunks (&stream->stps,
9140 stream->n_sample_partial_syncs, 4))
9147 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9150 /* copy atom data into a new buffer for later use */
9151 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
9153 /* skip version + flags */
9154 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9155 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9158 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9161 if (!stream->n_samples)
9164 /* sample-to-chunk atom */
9165 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9168 /* copy atom data into a new buffer for later use */
9169 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
9171 /* skip version + flags */
9172 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9173 !gst_byte_reader_get_uint32_be (&stream->stsc,
9174 &stream->n_samples_per_chunk))
9177 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9178 stream->n_samples_per_chunk);
9180 /* make sure there's enough data */
9181 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9187 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9188 stream->co_size = sizeof (guint32);
9189 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9191 stream->co_size = sizeof (guint64);
9195 /* copy atom data into a new buffer for later use */
9196 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
9198 /* skip version + flags */
9199 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9202 /* chunks_are_samples == TRUE means treat chunks as samples */
9203 stream->chunks_are_samples = stream->sample_size
9204 && !CUR_STREAM (stream)->sampled;
9205 if (stream->chunks_are_samples) {
9206 /* treat chunks as samples */
9207 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9210 /* skip number of entries */
9211 if (!gst_byte_reader_skip (&stream->stco, 4))
9214 /* make sure there are enough data in the stsz atom */
9215 if (!stream->sample_size) {
9216 /* different sizes for each sample */
9217 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9222 /* composition time-to-sample */
9223 if ((stream->ctts_present =
9224 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9225 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9226 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9228 /* copy atom data into a new buffer for later use */
9229 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
9231 /* skip version + flags */
9232 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9233 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9234 &stream->n_composition_times))
9237 /* make sure there's enough data */
9238 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9242 /* This is optional, if missing we iterate the ctts */
9243 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9244 if (!gst_byte_reader_skip (&cslg, 1 + 3)
9245 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9246 g_free ((gpointer) cslg.data);
9250 gint32 cslg_least = 0;
9251 guint num_entries, pos;
9254 pos = gst_byte_reader_get_pos (&stream->ctts);
9255 num_entries = stream->n_composition_times;
9257 stream->cslg_shift = 0;
9259 for (i = 0; i < num_entries; i++) {
9262 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9263 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9264 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9265 * slightly inaccurate PTS could be more usable than corrupted one */
9266 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9267 GST_WARNING_OBJECT (qtdemux,
9268 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9269 " larger than duration %" G_GUINT64_FORMAT,
9270 offset, stream->duration);
9272 stream->cslg_shift = 0;
9273 stream->ctts_present = FALSE;
9277 if (offset < cslg_least)
9278 cslg_least = offset;
9282 stream->cslg_shift = ABS (cslg_least);
9284 stream->cslg_shift = 0;
9286 /* reset the reader so we can generate sample table */
9287 gst_byte_reader_set_pos (&stream->ctts, pos);
9290 /* Ensure the cslg_shift value is consistent so we can use it
9291 * unconditionally to produce TS and Segment */
9292 stream->cslg_shift = 0;
9295 /* For raw audio streams especially we might want to merge the samples
9296 * to not output one audio sample per buffer. We're doing this here
9297 * before allocating the sample tables so that from this point onwards
9298 * the number of container samples are static */
9299 if (stream->min_buffer_size > 0) {
9300 qtdemux_merge_sample_table (qtdemux, stream);
9304 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9305 stream->n_samples, (guint) sizeof (QtDemuxSample),
9306 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9308 if (stream->n_samples >=
9309 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9310 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9311 "be larger than %uMB (broken file?)", stream->n_samples,
9312 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9316 g_assert (stream->samples == NULL);
9317 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9318 if (!stream->samples) {
9319 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9328 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9329 (_("This file is corrupt and cannot be played.")), (NULL));
9334 gst_qtdemux_stbl_free (stream);
9335 if (!qtdemux->fragmented) {
9336 /* not quite good */
9337 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9340 /* may pick up samples elsewhere */
9346 /* collect samples from the next sample to be parsed up to sample @n for @stream
9347 * by reading the info from @stbl
9349 * This code can be executed from both the streaming thread and the seeking
9350 * thread so it takes the object lock to protect itself
9353 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9356 QtDemuxSample *samples, *first, *cur, *last;
9357 guint32 n_samples_per_chunk;
9360 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9361 GST_FOURCC_FORMAT ", pad %s",
9362 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9363 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9365 n_samples = stream->n_samples;
9368 goto out_of_samples;
9370 GST_OBJECT_LOCK (qtdemux);
9371 if (n <= stream->stbl_index)
9372 goto already_parsed;
9374 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9376 if (!stream->stsz.data) {
9377 /* so we already parsed and passed all the moov samples;
9378 * onto fragmented ones */
9379 g_assert (qtdemux->fragmented);
9383 /* pointer to the sample table */
9384 samples = stream->samples;
9386 /* starts from -1, moves to the next sample index to parse */
9387 stream->stbl_index++;
9389 /* keep track of the first and last sample to fill */
9390 first = &samples[stream->stbl_index];
9393 if (!stream->chunks_are_samples) {
9394 /* set the sample sizes */
9395 if (stream->sample_size == 0) {
9396 /* different sizes for each sample */
9397 for (cur = first; cur <= last; cur++) {
9398 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9399 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9400 (guint) (cur - samples), cur->size);
9403 /* samples have the same size */
9404 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9405 for (cur = first; cur <= last; cur++)
9406 cur->size = stream->sample_size;
9410 n_samples_per_chunk = stream->n_samples_per_chunk;
9413 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9416 if (stream->stsc_chunk_index >= stream->last_chunk
9417 || stream->stsc_chunk_index < stream->first_chunk) {
9418 stream->first_chunk =
9419 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9420 stream->samples_per_chunk =
9421 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9423 stream->stsd_sample_description_id =
9424 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9426 /* chunk numbers are counted from 1 it seems */
9427 if (G_UNLIKELY (stream->first_chunk == 0))
9430 --stream->first_chunk;
9432 /* the last chunk of each entry is calculated by taking the first chunk
9433 * of the next entry; except if there is no next, where we fake it with
9435 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9436 stream->last_chunk = G_MAXUINT32;
9438 stream->last_chunk =
9439 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9440 if (G_UNLIKELY (stream->last_chunk == 0))
9443 --stream->last_chunk;
9446 GST_LOG_OBJECT (qtdemux,
9447 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9448 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9449 stream->samples_per_chunk, stream->stsd_sample_description_id);
9451 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9454 if (stream->last_chunk != G_MAXUINT32) {
9455 if (!qt_atom_parser_peek_sub (&stream->stco,
9456 stream->first_chunk * stream->co_size,
9457 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9462 stream->co_chunk = stream->stco;
9463 if (!gst_byte_reader_skip (&stream->co_chunk,
9464 stream->first_chunk * stream->co_size))
9468 stream->stsc_chunk_index = stream->first_chunk;
9471 last_chunk = stream->last_chunk;
9473 if (stream->chunks_are_samples) {
9474 cur = &samples[stream->stsc_chunk_index];
9476 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9479 stream->stsc_chunk_index = j;
9484 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9487 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9488 "%" G_GUINT64_FORMAT, j, cur->offset);
9490 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9491 CUR_STREAM (stream)->bytes_per_frame > 0) {
9493 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9494 CUR_STREAM (stream)->samples_per_frame *
9495 CUR_STREAM (stream)->bytes_per_frame;
9497 cur->size = stream->samples_per_chunk;
9500 GST_DEBUG_OBJECT (qtdemux,
9501 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9502 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9503 stream->stco_sample_index)), cur->size);
9505 cur->timestamp = stream->stco_sample_index;
9506 cur->duration = stream->samples_per_chunk;
9507 cur->keyframe = TRUE;
9510 stream->stco_sample_index += stream->samples_per_chunk;
9512 stream->stsc_chunk_index = j;
9514 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9515 guint32 samples_per_chunk;
9516 guint64 chunk_offset;
9518 if (!stream->stsc_sample_index
9519 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9520 &stream->chunk_offset))
9523 samples_per_chunk = stream->samples_per_chunk;
9524 chunk_offset = stream->chunk_offset;
9526 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9527 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9528 G_GUINT64_FORMAT " and size %d",
9529 (guint) (cur - samples), chunk_offset, cur->size);
9531 cur->offset = chunk_offset;
9532 chunk_offset += cur->size;
9535 if (G_UNLIKELY (cur > last)) {
9537 stream->stsc_sample_index = k + 1;
9538 stream->chunk_offset = chunk_offset;
9539 stream->stsc_chunk_index = j;
9543 stream->stsc_sample_index = 0;
9545 stream->stsc_chunk_index = j;
9547 stream->stsc_index++;
9550 if (stream->chunks_are_samples)
9554 guint32 n_sample_times;
9556 n_sample_times = stream->n_sample_times;
9559 for (i = stream->stts_index; i < n_sample_times; i++) {
9560 guint32 stts_samples;
9561 gint32 stts_duration;
9564 if (stream->stts_sample_index >= stream->stts_samples
9565 || !stream->stts_sample_index) {
9567 stream->stts_samples =
9568 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9569 stream->stts_duration =
9570 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9572 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9573 i, stream->stts_samples, stream->stts_duration);
9575 stream->stts_sample_index = 0;
9578 stts_samples = stream->stts_samples;
9579 stts_duration = stream->stts_duration;
9580 stts_time = stream->stts_time;
9582 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9583 GST_DEBUG_OBJECT (qtdemux,
9584 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9585 (guint) (cur - samples), j,
9586 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9588 cur->timestamp = stts_time;
9589 cur->duration = stts_duration;
9591 /* avoid 32-bit wrap-around,
9592 * but still mind possible 'negative' duration */
9593 stts_time += (gint64) stts_duration;
9596 if (G_UNLIKELY (cur > last)) {
9598 stream->stts_time = stts_time;
9599 stream->stts_sample_index = j + 1;
9600 if (stream->stts_sample_index >= stream->stts_samples)
9601 stream->stts_index++;
9605 stream->stts_sample_index = 0;
9606 stream->stts_time = stts_time;
9607 stream->stts_index++;
9609 /* fill up empty timestamps with the last timestamp, this can happen when
9610 * the last samples do not decode and so we don't have timestamps for them.
9611 * We however look at the last timestamp to estimate the track length so we
9612 * need something in here. */
9613 for (; cur < last; cur++) {
9614 GST_DEBUG_OBJECT (qtdemux,
9615 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9616 (guint) (cur - samples),
9617 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9618 cur->timestamp = stream->stts_time;
9624 /* sample sync, can be NULL */
9625 if (stream->stss_present == TRUE) {
9626 guint32 n_sample_syncs;
9628 n_sample_syncs = stream->n_sample_syncs;
9630 if (!n_sample_syncs) {
9631 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9632 stream->all_keyframe = TRUE;
9634 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9635 /* note that the first sample is index 1, not 0 */
9638 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9640 if (G_LIKELY (index > 0 && index <= n_samples)) {
9642 samples[index].keyframe = TRUE;
9643 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9644 /* and exit if we have enough samples */
9645 if (G_UNLIKELY (index >= n)) {
9652 stream->stss_index = i;
9655 /* stps marks partial sync frames like open GOP I-Frames */
9656 if (stream->stps_present == TRUE) {
9657 guint32 n_sample_partial_syncs;
9659 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9661 /* if there are no entries, the stss table contains the real
9663 if (n_sample_partial_syncs) {
9664 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9665 /* note that the first sample is index 1, not 0 */
9668 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9670 if (G_LIKELY (index > 0 && index <= n_samples)) {
9672 samples[index].keyframe = TRUE;
9673 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9674 /* and exit if we have enough samples */
9675 if (G_UNLIKELY (index >= n)) {
9682 stream->stps_index = i;
9686 /* no stss, all samples are keyframes */
9687 stream->all_keyframe = TRUE;
9688 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9693 /* composition time to sample */
9694 if (stream->ctts_present == TRUE) {
9695 guint32 n_composition_times;
9697 gint32 ctts_soffset;
9699 /* Fill in the pts_offsets */
9701 n_composition_times = stream->n_composition_times;
9703 for (i = stream->ctts_index; i < n_composition_times; i++) {
9704 if (stream->ctts_sample_index >= stream->ctts_count
9705 || !stream->ctts_sample_index) {
9706 stream->ctts_count =
9707 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9708 stream->ctts_soffset =
9709 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9710 stream->ctts_sample_index = 0;
9713 ctts_count = stream->ctts_count;
9714 ctts_soffset = stream->ctts_soffset;
9716 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9717 cur->pts_offset = ctts_soffset;
9720 if (G_UNLIKELY (cur > last)) {
9722 stream->ctts_sample_index = j + 1;
9726 stream->ctts_sample_index = 0;
9727 stream->ctts_index++;
9731 stream->stbl_index = n;
9732 /* if index has been completely parsed, free data that is no-longer needed */
9733 if (n + 1 == stream->n_samples) {
9734 gst_qtdemux_stbl_free (stream);
9735 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9736 if (qtdemux->pullbased) {
9737 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9738 while (n + 1 == stream->n_samples)
9739 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9743 GST_OBJECT_UNLOCK (qtdemux);
9750 GST_LOG_OBJECT (qtdemux,
9751 "Tried to parse up to sample %u but this sample has already been parsed",
9753 /* if fragmented, there may be more */
9754 if (qtdemux->fragmented && n == stream->stbl_index)
9756 GST_OBJECT_UNLOCK (qtdemux);
9762 GST_LOG_OBJECT (qtdemux,
9763 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9765 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9766 (_("This file is corrupt and cannot be played.")), (NULL));
9771 GST_OBJECT_UNLOCK (qtdemux);
9772 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9773 (_("This file is corrupt and cannot be played.")), (NULL));
9778 /* collect all segment info for @stream.
9781 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9785 /* accept edts if they contain gaps at start and there is only
9786 * one media segment */
9787 gboolean allow_pushbased_edts = TRUE;
9788 gint media_segments_count = 0;
9790 /* parse and prepare segment info from the edit list */
9791 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9792 stream->n_segments = 0;
9793 stream->segments = NULL;
9794 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9797 gint segment_number, entry_size;
9800 const guint8 *buffer;
9804 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9805 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9808 buffer = elst->data;
9810 size = QT_UINT32 (buffer);
9811 /* version, flags, n_segments */
9813 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9816 version = QT_UINT8 (buffer + 8);
9817 entry_size = (version == 1) ? 20 : 12;
9819 n_segments = QT_UINT32 (buffer + 12);
9821 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9822 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9826 /* we might allocate a bit too much, at least allocate 1 segment */
9827 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9829 /* segments always start from 0 */
9833 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9836 gboolean empty_edit = FALSE;
9837 QtDemuxSegment *segment;
9839 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9842 media_time = QT_UINT64 (buffer + 8);
9843 duration = QT_UINT64 (buffer);
9844 if (media_time == G_MAXUINT64)
9847 media_time = QT_UINT32 (buffer + 4);
9848 duration = QT_UINT32 (buffer);
9849 if (media_time == G_MAXUINT32)
9854 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9856 segment = &stream->segments[segment_number];
9858 /* time and duration expressed in global timescale */
9859 segment->time = stime;
9860 if (duration != 0 || empty_edit) {
9861 /* edge case: empty edits with duration=zero are treated here.
9862 * (files should not have these anyway). */
9864 /* add non scaled values so we don't cause roundoff errors */
9866 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9867 segment->duration = stime - segment->time;
9869 /* zero duration does not imply media_start == media_stop
9870 * but, only specify media_start. The edit ends with the track. */
9871 stime = segment->duration = GST_CLOCK_TIME_NONE;
9872 /* Don't allow more edits after this one. */
9873 n_segments = segment_number + 1;
9875 segment->stop_time = stime;
9877 segment->trak_media_start = media_time;
9878 /* media_time expressed in stream timescale */
9880 segment->media_start = media_start;
9881 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9882 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9883 media_segments_count++;
9885 segment->media_start = GST_CLOCK_TIME_NONE;
9886 segment->media_stop = GST_CLOCK_TIME_NONE;
9888 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9890 if (rate_int <= 1) {
9891 /* 0 is not allowed, some programs write 1 instead of the floating point
9893 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9897 segment->rate = rate_int / 65536.0;
9900 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9901 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9902 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9903 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9904 segment_number, GST_TIME_ARGS (segment->time),
9905 GST_TIME_ARGS (segment->duration),
9906 GST_TIME_ARGS (segment->media_start), media_time,
9907 GST_TIME_ARGS (segment->media_stop),
9908 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9910 if (segment->stop_time > qtdemux->segment.stop &&
9911 !qtdemux->upstream_format_is_time) {
9912 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9913 " extends to %" GST_TIME_FORMAT
9914 " past the end of the declared movie duration %" GST_TIME_FORMAT
9915 " movie segment will be extended", segment_number,
9916 GST_TIME_ARGS (segment->stop_time),
9917 GST_TIME_ARGS (qtdemux->segment.stop));
9918 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9921 buffer += entry_size;
9923 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9924 stream->n_segments = n_segments;
9925 if (media_segments_count != 1)
9926 allow_pushbased_edts = FALSE;
9930 /* push based does not handle segments, so act accordingly here,
9931 * and warn if applicable */
9932 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9933 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9934 /* remove and use default one below, we stream like it anyway */
9935 g_free (stream->segments);
9936 stream->segments = NULL;
9937 stream->n_segments = 0;
9940 /* no segments, create one to play the complete trak */
9941 if (stream->n_segments == 0) {
9942 GstClockTime stream_duration =
9943 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9945 if (stream->segments == NULL)
9946 stream->segments = g_new (QtDemuxSegment, 1);
9948 /* represent unknown our way */
9949 if (stream_duration == 0)
9950 stream_duration = GST_CLOCK_TIME_NONE;
9952 stream->segments[0].time = 0;
9953 stream->segments[0].stop_time = stream_duration;
9954 stream->segments[0].duration = stream_duration;
9955 stream->segments[0].media_start = 0;
9956 stream->segments[0].media_stop = stream_duration;
9957 stream->segments[0].rate = 1.0;
9958 stream->segments[0].trak_media_start = 0;
9960 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9961 GST_TIME_ARGS (stream_duration));
9962 stream->n_segments = 1;
9963 stream->dummy_segment = TRUE;
9965 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9971 * Parses the stsd atom of a svq3 trak looking for
9972 * the SMI and gama atoms.
9975 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9976 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9978 const guint8 *_gamma = NULL;
9979 GstBuffer *_seqh = NULL;
9980 const guint8 *stsd_data = stsd_entry_data;
9981 guint32 length = QT_UINT32 (stsd_data);
9985 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9991 version = QT_UINT16 (stsd_data);
9996 while (length > 8) {
9997 guint32 fourcc, size;
9999 size = QT_UINT32 (stsd_data);
10000 fourcc = QT_FOURCC (stsd_data + 4);
10001 data = stsd_data + 8;
10004 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10005 "svq3 atom parsing");
10014 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10015 " for gama atom, expected 12", size);
10020 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10022 if (_seqh != NULL) {
10023 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10024 " found, ignoring");
10026 seqh_size = QT_UINT32 (data + 4);
10027 if (seqh_size > 0) {
10028 _seqh = gst_buffer_new_and_alloc (seqh_size);
10029 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10036 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10037 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10041 if (size <= length) {
10047 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10050 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10051 G_GUINT16_FORMAT, version);
10061 } else if (_seqh) {
10062 gst_buffer_unref (_seqh);
10067 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10070 GstByteReader dref;
10074 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10075 * atom that might contain a 'data' atom with the rtsp uri.
10076 * This case was reported in bug #597497, some info about
10077 * the hndl atom can be found in TN1195
10079 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10080 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10083 guint32 dref_num_entries = 0;
10084 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10085 gst_byte_reader_skip (&dref, 4) &&
10086 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10089 /* search dref entries for hndl atom */
10090 for (i = 0; i < dref_num_entries; i++) {
10091 guint32 size = 0, type;
10092 guint8 string_len = 0;
10093 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10094 qt_atom_parser_get_fourcc (&dref, &type)) {
10095 if (type == FOURCC_hndl) {
10096 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10098 /* skip data reference handle bytes and the
10099 * following pascal string and some extra 4
10100 * bytes I have no idea what are */
10101 if (!gst_byte_reader_skip (&dref, 4) ||
10102 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10103 !gst_byte_reader_skip (&dref, string_len + 4)) {
10104 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10108 /* iterate over the atoms to find the data atom */
10109 while (gst_byte_reader_get_remaining (&dref) >= 8) {
10113 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10114 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10115 if (atom_type == FOURCC_data) {
10116 const guint8 *uri_aux = NULL;
10118 /* found the data atom that might contain the rtsp uri */
10119 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10120 "hndl atom, interpreting it as an URI");
10121 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10123 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10124 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10126 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10127 "didn't contain a rtsp address");
10129 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10134 /* skipping to the next entry */
10135 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10138 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10145 /* skip to the next entry */
10146 if (!gst_byte_reader_skip (&dref, size - 8))
10149 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10152 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10158 #define AMR_NB_ALL_MODES 0x81ff
10159 #define AMR_WB_ALL_MODES 0x83ff
10161 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10163 /* The 'damr' atom is of the form:
10165 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10166 * 32 b 8 b 16 b 8 b 8 b
10168 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10169 * represents the highest mode used in the stream (and thus the maximum
10170 * bitrate), with a couple of special cases as seen below.
10173 /* Map of frame type ID -> bitrate */
10174 static const guint nb_bitrates[] = {
10175 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10177 static const guint wb_bitrates[] = {
10178 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10184 gst_buffer_map (buf, &map, GST_MAP_READ);
10186 if (map.size != 0x11) {
10187 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10191 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10192 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10193 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10197 mode_set = QT_UINT16 (map.data + 13);
10199 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10200 max_mode = 7 + (wb ? 1 : 0);
10202 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10203 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10205 if (max_mode == -1) {
10206 GST_DEBUG ("No mode indication was found (mode set) = %x",
10211 gst_buffer_unmap (buf, &map);
10212 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10215 gst_buffer_unmap (buf, &map);
10220 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10221 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10224 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10230 if (gst_byte_reader_get_remaining (reader) < 36)
10233 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10234 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10235 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10236 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10237 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10238 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10239 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10240 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10241 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10243 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10244 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10245 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10247 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10248 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10250 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10251 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10258 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10259 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10266 * This macro will only compare value abdegh, it expects cfi to have already
10269 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10270 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10272 /* only handle the cases where the last column has standard values */
10273 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10274 const gchar *rotation_tag = NULL;
10276 /* no rotation needed */
10277 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10279 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10280 rotation_tag = "rotate-90";
10281 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10282 rotation_tag = "rotate-180";
10283 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10284 rotation_tag = "rotate-270";
10286 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10289 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10290 GST_STR_NULL (rotation_tag));
10291 if (rotation_tag != NULL) {
10292 if (*taglist == NULL)
10293 *taglist = gst_tag_list_new_empty ();
10294 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10295 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10298 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10303 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
10304 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10308 GstBuffer *adrm_buf = NULL;
10309 QtDemuxAavdEncryptionInfo *info;
10311 adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
10312 if (G_UNLIKELY (!adrm)) {
10313 GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
10316 adrm_size = QT_UINT32 (adrm->data);
10318 gst_buffer_new_wrapped (g_memdup (adrm->data, adrm_size), adrm_size);
10320 stream->protection_scheme_type = FOURCC_aavd;
10322 if (!stream->protection_scheme_info)
10323 stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
10325 info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
10327 if (info->default_properties)
10328 gst_structure_free (info->default_properties);
10329 info->default_properties = gst_structure_new ("application/x-aavd",
10330 "encrypted", G_TYPE_BOOLEAN, TRUE,
10331 "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
10332 gst_buffer_unref (adrm_buf);
10334 *original_fmt = FOURCC_mp4a;
10338 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10339 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10340 * Common Encryption (cenc), the function will also parse the tenc box (defined
10341 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10342 * (typically an enc[v|a|t|s] sample entry); the function will set
10343 * @original_fmt to the fourcc of the original unencrypted stream format.
10344 * Returns TRUE if successful; FALSE otherwise. */
10346 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10347 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10353 QtDemuxCencSampleSetInfo *info;
10355 const guint8 *tenc_data;
10357 g_return_val_if_fail (qtdemux != NULL, FALSE);
10358 g_return_val_if_fail (stream != NULL, FALSE);
10359 g_return_val_if_fail (container != NULL, FALSE);
10360 g_return_val_if_fail (original_fmt != NULL, FALSE);
10362 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10363 if (G_UNLIKELY (!sinf)) {
10364 if (stream->protection_scheme_type == FOURCC_cenc) {
10365 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10366 "mandatory for Common Encryption");
10372 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10373 if (G_UNLIKELY (!frma)) {
10374 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10378 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10379 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10380 GST_FOURCC_ARGS (*original_fmt));
10382 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10384 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10387 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10388 stream->protection_scheme_version =
10389 QT_UINT32 ((const guint8 *) schm->data + 16);
10391 GST_DEBUG_OBJECT (qtdemux,
10392 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10393 "protection_scheme_version: %#010x",
10394 GST_FOURCC_ARGS (stream->protection_scheme_type),
10395 stream->protection_scheme_version);
10397 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10399 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10402 if (stream->protection_scheme_type != FOURCC_cenc &&
10403 stream->protection_scheme_type != FOURCC_piff) {
10404 GST_ERROR_OBJECT (qtdemux,
10405 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10406 GST_FOURCC_ARGS (stream->protection_scheme_type));
10410 if (G_UNLIKELY (!stream->protection_scheme_info))
10411 stream->protection_scheme_info =
10412 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10414 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10416 if (stream->protection_scheme_type == FOURCC_cenc) {
10417 guint32 is_encrypted;
10419 const guint8 *default_kid;
10421 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10423 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10424 "which is mandatory for Common Encryption");
10427 tenc_data = (const guint8 *) tenc->data + 12;
10428 is_encrypted = QT_UINT24 (tenc_data);
10429 iv_size = QT_UINT8 (tenc_data + 3);
10430 default_kid = (tenc_data + 4);
10431 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10432 is_encrypted, iv_size, default_kid);
10433 } else if (stream->protection_scheme_type == FOURCC_piff) {
10435 static const guint8 piff_track_encryption_uuid[] = {
10436 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10437 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10440 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10442 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10443 "which is mandatory for Common Encryption");
10447 tenc_data = (const guint8 *) tenc->data + 8;
10448 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10449 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10450 GST_ERROR_OBJECT (qtdemux,
10451 "Unsupported track encryption box with uuid: %s", box_uuid);
10455 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10456 gst_byte_reader_init (&br, tenc_data, 20);
10457 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10458 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10461 stream->protection_scheme_type = FOURCC_cenc;
10468 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10469 QtDemuxStream ** stream2)
10471 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10475 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
10480 /*parse svmi header if existing */
10481 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10483 guint len = QT_UINT32 ((guint8 *) svmi->data);
10484 guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10486 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10487 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10488 guint8 frame_type, frame_layout;
10489 guint32 stereo_mono_change_count;
10494 /* MPEG-A stereo video */
10495 if (qtdemux->major_brand == FOURCC_ss02)
10496 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10498 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10499 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10500 stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
10502 switch (frame_type) {
10504 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10507 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10510 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10513 /* mode 3 is primary/secondary view sequence, ie
10514 * left/right views in separate tracks. See section 7.2
10515 * of ISO/IEC 23000-11:2009 */
10516 /* In the future this might be supported using related
10517 * streams, like an enhancement track - if files like this
10519 GST_FIXME_OBJECT (qtdemux,
10520 "Implement stereo video in separate streams");
10523 if ((frame_layout & 0x1) == 0)
10524 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10526 GST_LOG_OBJECT (qtdemux,
10527 "StereoVideo: composition type: %u, is_left_first: %u",
10528 frame_type, frame_layout);
10530 if (stereo_mono_change_count > 1) {
10531 GST_FIXME_OBJECT (qtdemux,
10532 "Mixed-mono flags are not yet supported in qtdemux.");
10535 stream->multiview_mode = mode;
10536 stream->multiview_flags = flags;
10543 /* parse the traks.
10544 * With each track we associate a new QtDemuxStream that contains all the info
10546 * traks that do not decode to something (like strm traks) will not have a pad.
10549 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10551 GstByteReader tkhd;
10565 QtDemuxStream *stream = NULL;
10566 const guint8 *stsd_data;
10567 const guint8 *stsd_entry_data;
10568 guint remaining_stsd_len;
10569 guint stsd_entry_count;
10571 guint16 lang_code; /* quicktime lang code or packed iso code */
10573 guint32 tkhd_flags = 0;
10574 guint8 tkhd_version = 0;
10575 guint32 w = 0, h = 0;
10576 guint value_size, stsd_len, len;
10580 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10582 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10583 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10584 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10587 /* pick between 64 or 32 bits */
10588 value_size = tkhd_version == 1 ? 8 : 4;
10589 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10590 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10593 /* Check if current moov has duplicated track_id */
10594 if (qtdemux_find_stream (qtdemux, track_id))
10595 goto existing_stream;
10597 stream = _create_stream (qtdemux, track_id);
10598 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10600 /* need defaults for fragments */
10601 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10603 if ((tkhd_flags & 1) == 0)
10604 stream->disabled = TRUE;
10606 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10607 tkhd_version, tkhd_flags, stream->track_id);
10609 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10612 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10613 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10614 if (qtdemux->major_brand != FOURCC_mjp2 ||
10615 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10619 len = QT_UINT32 ((guint8 *) mdhd->data);
10620 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10621 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10622 if (version == 0x01000000) {
10625 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10626 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10627 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
10631 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10632 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10633 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10636 if (lang_code < 0x400) {
10637 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10638 } else if (lang_code == 0x7fff) {
10639 stream->lang_id[0] = 0; /* unspecified */
10641 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10642 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10643 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10644 stream->lang_id[3] = 0;
10647 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10648 stream->timescale);
10649 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10651 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10652 lang_code, stream->lang_id);
10654 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10657 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10658 /* chapters track reference */
10659 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10661 gsize length = GST_READ_UINT32_BE (chap->data);
10662 if (qtdemux->chapters_track_id)
10663 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10665 if (length >= 12) {
10666 qtdemux->chapters_track_id =
10667 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10672 /* fragmented files may have bogus duration in moov */
10673 if (!qtdemux->fragmented &&
10674 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10675 guint64 tdur1, tdur2;
10677 /* don't overflow */
10678 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10679 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10682 * some of those trailers, nowadays, have prologue images that are
10683 * themselves video tracks as well. I haven't really found a way to
10684 * identify those yet, except for just looking at their duration. */
10685 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10686 GST_WARNING_OBJECT (qtdemux,
10687 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10688 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10689 "found, assuming preview image or something; skipping track",
10690 stream->duration, stream->timescale, qtdemux->duration,
10691 qtdemux->timescale);
10692 gst_qtdemux_stream_unref (stream);
10697 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10700 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10701 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10703 len = QT_UINT32 ((guint8 *) hdlr->data);
10705 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10706 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10707 GST_FOURCC_ARGS (stream->subtype));
10709 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10712 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10715 /* Parse out svmi (and later st3d/sv3d) atoms */
10716 if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
10719 /* parse rest of tkhd */
10720 if (stream->subtype == FOURCC_vide) {
10723 /* version 1 uses some 64-bit ints */
10724 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10727 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10730 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10731 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10734 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10735 &stream->stream_tags);
10739 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10741 stsd_data = (const guint8 *) stsd->data;
10743 /* stsd should at least have one entry */
10744 stsd_len = QT_UINT32 (stsd_data);
10745 if (stsd_len < 24) {
10746 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10747 if (stream->subtype == FOURCC_vivo) {
10748 gst_qtdemux_stream_unref (stream);
10755 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10756 /* each stsd entry must contain at least 8 bytes */
10757 if (stream->stsd_entries_length == 0
10758 || stream->stsd_entries_length > stsd_len / 8) {
10759 stream->stsd_entries_length = 0;
10762 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10763 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10764 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10766 stsd_entry_data = stsd_data + 16;
10767 remaining_stsd_len = stsd_len - 16;
10768 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10770 gchar *codec = NULL;
10771 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10773 /* and that entry should fit within stsd */
10774 len = QT_UINT32 (stsd_entry_data);
10775 if (len > remaining_stsd_len)
10778 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10779 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10780 GST_FOURCC_ARGS (entry->fourcc));
10781 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10783 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10784 goto error_encrypted;
10786 if (fourcc == FOURCC_aavd) {
10787 if (stream->subtype != FOURCC_soun) {
10788 GST_ERROR_OBJECT (qtdemux,
10789 "Unexpeced stsd type 'aavd' outside 'soun' track");
10791 /* encrypted audio with sound sample description v0 */
10792 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10793 stream->protected = TRUE;
10794 if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
10795 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10799 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10800 /* FIXME this looks wrong, there might be multiple children
10801 * with the same type */
10802 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10803 stream->protected = TRUE;
10804 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10805 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10808 if (stream->subtype == FOURCC_vide) {
10813 gint depth, palette_size, palette_count;
10814 guint32 *palette_data = NULL;
10816 entry->sampled = TRUE;
10818 stream->display_width = w >> 16;
10819 stream->display_height = h >> 16;
10822 if (len < 86) /* TODO verify */
10825 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10826 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10827 entry->fps_n = 0; /* this is filled in later */
10828 entry->fps_d = 0; /* this is filled in later */
10829 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10830 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10832 /* if color_table_id is 0, ctab atom must follow; however some files
10833 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10834 * if color table is not present we'll correct the value */
10835 if (entry->color_table_id == 0 &&
10837 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10838 entry->color_table_id = -1;
10841 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10842 entry->width, entry->height, entry->bits_per_sample,
10843 entry->color_table_id);
10845 depth = entry->bits_per_sample;
10847 /* more than 32 bits means grayscale */
10848 gray = (depth > 32);
10849 /* low 32 bits specify the depth */
10852 /* different number of palette entries is determined by depth. */
10854 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10855 palette_count = (1 << depth);
10856 palette_size = palette_count * 4;
10858 if (entry->color_table_id) {
10859 switch (palette_count) {
10863 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10866 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10871 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10873 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10878 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10880 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10883 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10884 (_("The video in this file might not play correctly.")),
10885 ("unsupported palette depth %d", depth));
10889 gint i, j, start, end;
10895 start = QT_UINT32 (stsd_entry_data + offset + 70);
10896 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10897 end = QT_UINT16 (stsd_entry_data + offset + 76);
10899 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10900 start, end, palette_count);
10907 if (len < 94 + (end - start) * 8)
10910 /* palette is always the same size */
10911 palette_data = g_malloc0 (256 * 4);
10912 palette_size = 256 * 4;
10914 for (j = 0, i = start; i <= end; j++, i++) {
10915 guint32 a, r, g, b;
10917 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10918 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10919 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10920 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10922 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10923 (g & 0xff00) | (b >> 8);
10928 gst_caps_unref (entry->caps);
10931 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10933 if (G_UNLIKELY (!entry->caps)) {
10934 g_free (palette_data);
10935 goto unknown_stream;
10939 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10940 GST_TAG_VIDEO_CODEC, codec, NULL);
10945 if (palette_data) {
10948 if (entry->rgb8_palette)
10949 gst_memory_unref (entry->rgb8_palette);
10950 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10951 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10953 s = gst_caps_get_structure (entry->caps, 0);
10955 /* non-raw video has a palette_data property. raw video has the palette as
10956 * an extra plane that we append to the output buffers before we push
10958 if (!gst_structure_has_name (s, "video/x-raw")) {
10959 GstBuffer *palette;
10961 palette = gst_buffer_new ();
10962 gst_buffer_append_memory (palette, entry->rgb8_palette);
10963 entry->rgb8_palette = NULL;
10965 gst_caps_set_simple (entry->caps, "palette_data",
10966 GST_TYPE_BUFFER, palette, NULL);
10967 gst_buffer_unref (palette);
10969 } else if (palette_count != 0) {
10970 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10971 (NULL), ("Unsupported palette depth %d", depth));
10974 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10975 QT_UINT16 (stsd_entry_data + offset + 32));
10981 /* pick 'the' stsd child */
10982 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10983 // We should skip parsing the stsd for non-protected streams if
10984 // the entry doesn't match the fourcc, since they don't change
10985 // format. However, for protected streams we can have partial
10986 // encryption, where parts of the stream are encrypted and parts
10987 // not. For both parts of such streams, we should ensure the
10988 // esds overrides are parsed for both from the stsd.
10989 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10990 if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
10992 else if (!stream->protected)
10997 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10998 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10999 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11000 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11004 const guint8 *pasp_data = (const guint8 *) pasp->data;
11005 gint len = QT_UINT32 (pasp_data);
11008 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11009 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11011 CUR_STREAM (stream)->par_w = 0;
11012 CUR_STREAM (stream)->par_h = 0;
11015 CUR_STREAM (stream)->par_w = 0;
11016 CUR_STREAM (stream)->par_h = 0;
11020 const guint8 *fiel_data = (const guint8 *) fiel->data;
11021 gint len = QT_UINT32 (fiel_data);
11024 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11025 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11030 const guint8 *colr_data = (const guint8 *) colr->data;
11031 gint len = QT_UINT32 (colr_data);
11033 if (len == 19 || len == 18) {
11034 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11036 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11037 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11038 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11039 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11040 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11042 CUR_STREAM (stream)->colorimetry.primaries =
11043 gst_video_color_primaries_from_iso (primaries);
11044 CUR_STREAM (stream)->colorimetry.transfer =
11045 gst_video_transfer_function_from_iso (transfer_function);
11046 CUR_STREAM (stream)->colorimetry.matrix =
11047 gst_video_color_matrix_from_iso (matrix);
11048 CUR_STREAM (stream)->colorimetry.range =
11049 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11050 GST_VIDEO_COLOR_RANGE_16_235;
11052 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11055 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11060 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11061 stream->stream_tags);
11068 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11069 const guint8 *avc_data = stsd_entry_data + 0x56;
11072 while (len >= 0x8) {
11075 if (QT_UINT32 (avc_data) <= len)
11076 size = QT_UINT32 (avc_data) - 0x8;
11081 /* No real data, so break out */
11084 switch (QT_FOURCC (avc_data + 0x4)) {
11087 /* parse, if found */
11090 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11092 /* First 4 bytes are the length of the atom, the next 4 bytes
11093 * are the fourcc, the next 1 byte is the version, and the
11094 * subsequent bytes are profile_tier_level structure like data. */
11095 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11096 avc_data + 8 + 1, size - 1);
11097 buf = gst_buffer_new_and_alloc (size);
11098 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11099 gst_caps_set_simple (entry->caps,
11100 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11101 gst_buffer_unref (buf);
11109 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11111 /* First 4 bytes are the length of the atom, the next 4 bytes
11112 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11113 * next 1 byte is the version, and the
11114 * subsequent bytes are sequence parameter set like data. */
11116 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
11118 gst_codec_utils_h264_caps_set_level_and_profile
11119 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11121 buf = gst_buffer_new_and_alloc (size);
11122 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11123 gst_caps_set_simple (entry->caps,
11124 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11125 gst_buffer_unref (buf);
11131 guint avg_bitrate, max_bitrate;
11133 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11137 max_bitrate = QT_UINT32 (avc_data + 0xc);
11138 avg_bitrate = QT_UINT32 (avc_data + 0x10);
11140 if (!max_bitrate && !avg_bitrate)
11143 /* Some muxers seem to swap the average and maximum bitrates
11144 * (I'm looking at you, YouTube), so we swap for sanity. */
11145 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11146 guint temp = avg_bitrate;
11148 avg_bitrate = max_bitrate;
11149 max_bitrate = temp;
11152 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11153 gst_tag_list_add (stream->stream_tags,
11154 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11155 max_bitrate, NULL);
11157 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11158 gst_tag_list_add (stream->stream_tags,
11159 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11171 avc_data += size + 8;
11182 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11183 const guint8 *hevc_data = stsd_entry_data + 0x56;
11186 while (len >= 0x8) {
11189 if (QT_UINT32 (hevc_data) <= len)
11190 size = QT_UINT32 (hevc_data) - 0x8;
11195 /* No real data, so break out */
11198 switch (QT_FOURCC (hevc_data + 0x4)) {
11201 /* parse, if found */
11204 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11206 /* First 4 bytes are the length of the atom, the next 4 bytes
11207 * are the fourcc, the next 1 byte is the version, and the
11208 * subsequent bytes are sequence parameter set like data. */
11209 gst_codec_utils_h265_caps_set_level_tier_and_profile
11210 (entry->caps, hevc_data + 8 + 1, size - 1);
11212 buf = gst_buffer_new_and_alloc (size);
11213 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11214 gst_caps_set_simple (entry->caps,
11215 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11216 gst_buffer_unref (buf);
11223 hevc_data += size + 8;
11236 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11237 GST_FOURCC_ARGS (fourcc));
11239 /* codec data might be in glbl extension atom */
11241 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11247 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11249 len = QT_UINT32 (data);
11252 buf = gst_buffer_new_and_alloc (len);
11253 gst_buffer_fill (buf, 0, data + 8, len);
11254 gst_caps_set_simple (entry->caps,
11255 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11256 gst_buffer_unref (buf);
11263 /* see annex I of the jpeg2000 spec */
11264 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11265 const guint8 *data;
11266 const gchar *colorspace = NULL;
11268 guint32 ncomp_map = 0;
11269 gint32 *comp_map = NULL;
11270 guint32 nchan_def = 0;
11271 gint32 *chan_def = NULL;
11273 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11274 /* some required atoms */
11275 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11278 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11282 /* number of components; redundant with info in codestream, but useful
11284 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11285 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11287 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11289 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11292 GST_DEBUG_OBJECT (qtdemux, "found colr");
11293 /* extract colour space info */
11294 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11295 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11297 colorspace = "sRGB";
11300 colorspace = "GRAY";
11303 colorspace = "sYUV";
11311 /* colr is required, and only values 16, 17, and 18 are specified,
11312 so error if we have no colorspace */
11315 /* extract component mapping */
11316 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11318 guint32 cmap_len = 0;
11320 cmap_len = QT_UINT32 (cmap->data);
11321 if (cmap_len >= 8) {
11322 /* normal box, subtract off header */
11324 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11325 if (cmap_len % 4 == 0) {
11326 ncomp_map = (cmap_len / 4);
11327 comp_map = g_new0 (gint32, ncomp_map);
11328 for (i = 0; i < ncomp_map; i++) {
11331 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11332 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11333 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11334 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11339 /* extract channel definitions */
11340 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11342 guint32 cdef_len = 0;
11344 cdef_len = QT_UINT32 (cdef->data);
11345 if (cdef_len >= 10) {
11346 /* normal box, subtract off header and len */
11348 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11349 if (cdef_len % 6 == 0) {
11350 nchan_def = (cdef_len / 6);
11351 chan_def = g_new0 (gint32, nchan_def);
11352 for (i = 0; i < nchan_def; i++)
11354 for (i = 0; i < nchan_def; i++) {
11355 guint16 cn, typ, asoc;
11356 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11357 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11358 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11359 if (cn < nchan_def) {
11362 chan_def[cn] = asoc;
11365 chan_def[cn] = 0; /* alpha */
11368 chan_def[cn] = -typ;
11376 gst_caps_set_simple (entry->caps,
11377 "num-components", G_TYPE_INT, ncomp, NULL);
11378 gst_caps_set_simple (entry->caps,
11379 "colorspace", G_TYPE_STRING, colorspace, NULL);
11382 GValue arr = { 0, };
11383 GValue elt = { 0, };
11385 g_value_init (&arr, GST_TYPE_ARRAY);
11386 g_value_init (&elt, G_TYPE_INT);
11387 for (i = 0; i < ncomp_map; i++) {
11388 g_value_set_int (&elt, comp_map[i]);
11389 gst_value_array_append_value (&arr, &elt);
11391 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11392 "component-map", &arr);
11393 g_value_unset (&elt);
11394 g_value_unset (&arr);
11399 GValue arr = { 0, };
11400 GValue elt = { 0, };
11402 g_value_init (&arr, GST_TYPE_ARRAY);
11403 g_value_init (&elt, G_TYPE_INT);
11404 for (i = 0; i < nchan_def; i++) {
11405 g_value_set_int (&elt, chan_def[i]);
11406 gst_value_array_append_value (&arr, &elt);
11408 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11409 "channel-definitions", &arr);
11410 g_value_unset (&elt);
11411 g_value_unset (&arr);
11415 /* some optional atoms */
11416 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11417 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11419 /* indicate possible fields in caps */
11421 data = (guint8 *) field->data + 8;
11423 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11424 (gint) * data, NULL);
11426 /* add codec_data if provided */
11431 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11432 data = prefix->data;
11433 len = QT_UINT32 (data);
11436 buf = gst_buffer_new_and_alloc (len);
11437 gst_buffer_fill (buf, 0, data + 8, len);
11438 gst_caps_set_simple (entry->caps,
11439 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11440 gst_buffer_unref (buf);
11449 GstBuffer *seqh = NULL;
11450 const guint8 *gamma_data = NULL;
11451 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11453 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11456 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11457 QT_FP32 (gamma_data), NULL);
11460 /* sorry for the bad name, but we don't know what this is, other
11461 * than its own fourcc */
11462 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11464 gst_buffer_unref (seqh);
11467 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11468 buf = gst_buffer_new_and_alloc (len);
11469 gst_buffer_fill (buf, 0, stsd_data, len);
11470 gst_caps_set_simple (entry->caps,
11471 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11472 gst_buffer_unref (buf);
11477 /* https://developer.apple.com/standards/qtff-2001.pdf,
11478 * page 92, "Video Sample Description", under table 3.1 */
11481 const gint compressor_offset =
11482 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11483 const gint min_size = compressor_offset + 32 + 2 + 2;
11486 guint16 color_table_id = 0;
11489 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11491 /* recover information on interlaced/progressive */
11492 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11496 len = QT_UINT32 (jpeg->data);
11497 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11499 if (len >= min_size) {
11500 gst_byte_reader_init (&br, jpeg->data, len);
11502 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11503 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11504 if (color_table_id != 0) {
11505 /* the spec says there can be concatenated chunks in the data, and we want
11506 * to find one called field. Walk through them. */
11507 gint offset = min_size;
11508 while (offset + 8 < len) {
11509 guint32 size = 0, tag;
11510 ok = gst_byte_reader_get_uint32_le (&br, &size);
11511 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11512 if (!ok || size < 8) {
11513 GST_WARNING_OBJECT (qtdemux,
11514 "Failed to walk optional chunk list");
11517 GST_DEBUG_OBJECT (qtdemux,
11518 "Found optional %4.4s chunk, size %u",
11519 (const char *) &tag, size);
11520 if (tag == FOURCC_fiel) {
11521 guint8 n_fields = 0, ordering = 0;
11522 gst_byte_reader_get_uint8 (&br, &n_fields);
11523 gst_byte_reader_get_uint8 (&br, &ordering);
11524 if (n_fields == 1 || n_fields == 2) {
11525 GST_DEBUG_OBJECT (qtdemux,
11526 "Found fiel tag with %u fields, ordering %u",
11527 n_fields, ordering);
11529 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11530 "interlace-mode", G_TYPE_STRING, "interleaved",
11533 GST_WARNING_OBJECT (qtdemux,
11534 "Found fiel tag with invalid fields (%u)", n_fields);
11540 GST_DEBUG_OBJECT (qtdemux,
11541 "Color table ID is 0, not trying to get interlacedness");
11544 GST_WARNING_OBJECT (qtdemux,
11545 "Length of jpeg chunk is too small, not trying to get interlacedness");
11553 gst_caps_set_simple (entry->caps,
11554 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11560 GNode *xith, *xdxt;
11562 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11563 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11567 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11571 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11572 /* collect the headers and store them in a stream list so that we can
11573 * send them out first */
11574 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11584 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11585 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11588 ovc1_data = ovc1->data;
11589 ovc1_len = QT_UINT32 (ovc1_data);
11590 if (ovc1_len <= 198) {
11591 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11594 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11595 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11596 gst_caps_set_simple (entry->caps,
11597 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11598 gst_buffer_unref (buf);
11603 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11604 const guint8 *vc1_data = stsd_entry_data + 0x56;
11610 if (QT_UINT32 (vc1_data) <= len)
11611 size = QT_UINT32 (vc1_data) - 8;
11616 /* No real data, so break out */
11619 switch (QT_FOURCC (vc1_data + 0x4)) {
11620 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11624 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11625 buf = gst_buffer_new_and_alloc (size);
11626 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11627 gst_caps_set_simple (entry->caps,
11628 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11629 gst_buffer_unref (buf);
11636 vc1_data += size + 8;
11642 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11643 const guint8 *av1_data = stsd_entry_data + 0x56;
11646 while (len >= 0x8) {
11649 if (QT_UINT32 (av1_data) <= len)
11650 size = QT_UINT32 (av1_data) - 0x8;
11655 /* No real data, so break out */
11658 switch (QT_FOURCC (av1_data + 0x4)) {
11661 /* parse, if found */
11663 guint8 pres_delay_field;
11665 GST_DEBUG_OBJECT (qtdemux,
11666 "found av1C codec_data in stsd of size %d", size);
11668 /* not enough data, just ignore and hope for the best */
11673 * 4 bytes: atom length
11678 * 1 bits: initial_presentation_delay_present
11679 * 4 bits: initial_presentation_delay (if present else reserved
11683 if (av1_data[9] != 0) {
11684 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11688 /* We skip initial_presentation_delay* for now */
11689 pres_delay_field = *(av1_data + 12);
11690 if (pres_delay_field & (1 << 5)) {
11691 gst_caps_set_simple (entry->caps,
11692 "presentation-delay", G_TYPE_INT,
11693 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11696 buf = gst_buffer_new_and_alloc (size - 5);
11697 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11698 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11699 gst_caps_set_simple (entry->caps,
11700 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11701 gst_buffer_unref (buf);
11710 av1_data += size + 8;
11716 /* TODO: Need to parse vpcC for VP8 codec too.
11717 * Note that VPCodecConfigurationBox (vpcC) is defined for
11718 * vp08, vp09, and vp10 fourcc. */
11721 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11722 const guint8 *vpcc_data = stsd_entry_data + 0x56;
11725 while (len >= 0x8) {
11728 if (QT_UINT32 (vpcc_data) <= len)
11729 size = QT_UINT32 (vpcc_data) - 0x8;
11734 /* No real data, so break out */
11737 switch (QT_FOURCC (vpcc_data + 0x4)) {
11740 const gchar *profile_str = NULL;
11741 const gchar *chroma_format_str = NULL;
11744 guint8 chroma_format;
11745 GstVideoColorimetry cinfo;
11747 /* parse, if found */
11748 GST_DEBUG_OBJECT (qtdemux,
11749 "found vp codec_data in stsd of size %d", size);
11751 /* the meaning of "size" is length of the atom body, excluding
11752 * atom length and fourcc fields */
11757 * 4 bytes: atom length
11764 * 3 bits: chromaSubsampling
11765 * 1 bit: videoFullRangeFlag
11766 * 1 byte: colourPrimaries
11767 * 1 byte: transferCharacteristics
11768 * 1 byte: matrixCoefficients
11769 * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
11770 * rest: codecIntializationData (not used for vp8 and vp9)
11773 if (vpcc_data[8] != 1) {
11774 GST_WARNING_OBJECT (qtdemux,
11775 "unknown vpcC version %d", vpcc_data[8]);
11779 profile = vpcc_data[12];
11798 gst_caps_set_simple (entry->caps,
11799 "profile", G_TYPE_STRING, profile_str, NULL);
11802 /* skip level, the VP9 spec v0.6 defines only one level atm,
11803 * but webm spec define various ones. Add level to caps
11804 * if we really need it then */
11806 bitdepth = (vpcc_data[14] & 0xf0) >> 4;
11807 if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
11808 gst_caps_set_simple (entry->caps,
11809 "bit-depth-luma", G_TYPE_UINT, bitdepth,
11810 "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
11813 chroma_format = (vpcc_data[14] & 0xe) >> 1;
11814 switch (chroma_format) {
11817 chroma_format_str = "4:2:0";
11820 chroma_format_str = "4:2:2";
11823 chroma_format_str = "4:4:4";
11829 if (chroma_format_str) {
11830 gst_caps_set_simple (entry->caps,
11831 "chroma-format", G_TYPE_STRING, chroma_format_str,
11835 if ((vpcc_data[14] & 0x1) != 0)
11836 cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
11838 cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
11840 gst_video_color_primaries_from_iso (vpcc_data[15]);
11842 gst_video_transfer_function_from_iso (vpcc_data[16]);
11844 gst_video_color_matrix_from_iso (vpcc_data[17]);
11846 if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
11847 cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
11848 cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
11849 /* set this only if all values are known, otherwise this
11850 * might overwrite valid ones parsed from other color box */
11851 CUR_STREAM (stream)->colorimetry = cinfo;
11860 vpcc_data += size + 8;
11870 GST_INFO_OBJECT (qtdemux,
11871 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11872 GST_FOURCC_ARGS (fourcc), entry->caps);
11874 } else if (stream->subtype == FOURCC_soun) {
11876 int version, samplesize;
11877 guint16 compression_id;
11878 gboolean amrwb = FALSE;
11881 /* sample description entry (16) + sound sample description v0 (20) */
11885 version = QT_UINT32 (stsd_entry_data + offset);
11886 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11887 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11888 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11889 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11891 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11892 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11893 QT_UINT32 (stsd_entry_data + offset + 4));
11894 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11895 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11896 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11897 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11898 QT_UINT16 (stsd_entry_data + offset + 14));
11899 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11901 if (compression_id == 0xfffe)
11902 entry->sampled = TRUE;
11904 /* first assume uncompressed audio */
11905 entry->bytes_per_sample = samplesize / 8;
11906 entry->samples_per_frame = entry->n_channels;
11907 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11908 entry->samples_per_packet = entry->samples_per_frame;
11909 entry->bytes_per_packet = entry->bytes_per_sample;
11913 if (version == 0x00010000) {
11914 /* sample description entry (16) + sound sample description v1 (20+16) */
11918 /* take information from here over the normal sample description */
11919 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11920 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11921 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11922 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11924 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
11925 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11926 entry->samples_per_packet);
11927 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11928 entry->bytes_per_packet);
11929 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11930 entry->bytes_per_frame);
11931 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11932 entry->bytes_per_sample);
11934 if (!entry->sampled && entry->bytes_per_packet) {
11935 entry->samples_per_frame = (entry->bytes_per_frame /
11936 entry->bytes_per_packet) * entry->samples_per_packet;
11937 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11938 entry->samples_per_frame);
11940 } else if (version == 0x00020000) {
11941 /* sample description entry (16) + sound sample description v2 (56) */
11945 /* take information from here over the normal sample description */
11946 entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
11947 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11948 entry->samples_per_frame = entry->n_channels;
11949 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
11950 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
11951 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
11952 entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
11954 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11955 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11956 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11957 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11958 entry->bytes_per_sample * 8);
11959 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11960 QT_UINT32 (stsd_entry_data + offset + 24));
11961 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11962 entry->bytes_per_packet);
11963 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11964 entry->samples_per_packet);
11965 } else if (version != 0x00000) {
11966 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11971 /* Yes, these have to be hard-coded */
11974 entry->samples_per_packet = 6;
11975 entry->bytes_per_packet = 1;
11976 entry->bytes_per_frame = 1 * entry->n_channels;
11977 entry->bytes_per_sample = 1;
11978 entry->samples_per_frame = 6 * entry->n_channels;
11983 entry->samples_per_packet = 3;
11984 entry->bytes_per_packet = 1;
11985 entry->bytes_per_frame = 1 * entry->n_channels;
11986 entry->bytes_per_sample = 1;
11987 entry->samples_per_frame = 3 * entry->n_channels;
11992 entry->samples_per_packet = 64;
11993 entry->bytes_per_packet = 34;
11994 entry->bytes_per_frame = 34 * entry->n_channels;
11995 entry->bytes_per_sample = 2;
11996 entry->samples_per_frame = 64 * entry->n_channels;
12002 entry->samples_per_packet = 1;
12003 entry->bytes_per_packet = 1;
12004 entry->bytes_per_frame = 1 * entry->n_channels;
12005 entry->bytes_per_sample = 1;
12006 entry->samples_per_frame = 1 * entry->n_channels;
12011 entry->samples_per_packet = 160;
12012 entry->bytes_per_packet = 33;
12013 entry->bytes_per_frame = 33 * entry->n_channels;
12014 entry->bytes_per_sample = 2;
12015 entry->samples_per_frame = 160 * entry->n_channels;
12018 /* fix up any invalid header information from above */
12023 /* Sometimes these are set to 0 in the sound sample descriptions so
12024 * let's try to infer useful values from the other information we
12025 * have available */
12026 if (entry->bytes_per_sample == 0)
12027 entry->bytes_per_sample =
12028 entry->bytes_per_frame / entry->n_channels;
12029 if (entry->bytes_per_sample == 0)
12030 entry->bytes_per_sample = samplesize / 8;
12032 if (entry->bytes_per_frame == 0)
12033 entry->bytes_per_frame =
12034 entry->bytes_per_sample * entry->n_channels;
12036 if (entry->bytes_per_packet == 0)
12037 entry->bytes_per_packet = entry->bytes_per_sample;
12039 if (entry->samples_per_frame == 0)
12040 entry->samples_per_frame = entry->n_channels;
12042 if (entry->samples_per_packet == 0)
12043 entry->samples_per_packet = entry->samples_per_frame;
12053 entry->bytes_per_sample = 3;
12057 entry->bytes_per_sample = 4;
12060 entry->bytes_per_sample = 8;
12063 entry->bytes_per_sample = 2;
12066 g_assert_not_reached ();
12069 entry->samples_per_frame = entry->n_channels;
12070 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12071 entry->samples_per_packet = entry->samples_per_frame;
12072 entry->bytes_per_packet = entry->bytes_per_sample;
12080 gst_caps_unref (entry->caps);
12082 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12083 stsd_entry_data + 32, len - 16, &codec);
12094 fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
12096 enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
12098 wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
12100 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12103 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12104 const gchar *format_str;
12108 format_str = (enda_value) ? "S24LE" : "S24BE";
12111 format_str = (enda_value) ? "S32LE" : "S32BE";
12114 format_str = (enda_value) ? "F32LE" : "F32BE";
12117 format_str = (enda_value) ? "F64LE" : "F64BE";
12120 g_assert_not_reached ();
12123 gst_caps_set_simple (entry->caps,
12124 "format", G_TYPE_STRING, format_str, NULL);
12130 const guint8 *owma_data;
12131 const gchar *codec_name = NULL;
12135 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12136 /* FIXME this should also be gst_riff_strf_auds,
12137 * but the latter one is actually missing bits-per-sample :( */
12142 gint32 nSamplesPerSec;
12143 gint32 nAvgBytesPerSec;
12144 gint16 nBlockAlign;
12145 gint16 wBitsPerSample;
12148 WAVEFORMATEX *wfex;
12150 GST_DEBUG_OBJECT (qtdemux, "parse owma");
12151 owma_data = stsd_entry_data;
12152 owma_len = QT_UINT32 (owma_data);
12153 if (owma_len <= 54) {
12154 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12157 wfex = (WAVEFORMATEX *) (owma_data + 36);
12158 buf = gst_buffer_new_and_alloc (owma_len - 54);
12159 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12160 if (wfex->wFormatTag == 0x0161) {
12161 codec_name = "Windows Media Audio";
12163 } else if (wfex->wFormatTag == 0x0162) {
12164 codec_name = "Windows Media Audio 9 Pro";
12166 } else if (wfex->wFormatTag == 0x0163) {
12167 codec_name = "Windows Media Audio 9 Lossless";
12168 /* is that correct? gstffmpegcodecmap.c is missing it, but
12169 * fluendo codec seems to support it */
12173 gst_caps_set_simple (entry->caps,
12174 "codec_data", GST_TYPE_BUFFER, buf,
12175 "wmaversion", G_TYPE_INT, version,
12176 "block_align", G_TYPE_INT,
12177 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12178 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12179 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12180 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12181 gst_buffer_unref (buf);
12185 codec = g_strdup (codec_name);
12191 gint len = QT_UINT32 (stsd_entry_data) - offset;
12192 const guint8 *wfex_data = stsd_entry_data + offset;
12193 const gchar *codec_name = NULL;
12195 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12196 /* FIXME this should also be gst_riff_strf_auds,
12197 * but the latter one is actually missing bits-per-sample :( */
12202 gint32 nSamplesPerSec;
12203 gint32 nAvgBytesPerSec;
12204 gint16 nBlockAlign;
12205 gint16 wBitsPerSample;
12210 /* FIXME: unify with similar wavformatex parsing code above */
12211 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12217 if (QT_UINT32 (wfex_data) <= len)
12218 size = QT_UINT32 (wfex_data) - 8;
12223 /* No real data, so break out */
12226 switch (QT_FOURCC (wfex_data + 4)) {
12227 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12229 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12234 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12235 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12236 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12237 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12238 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12239 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12240 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12242 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12243 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12244 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12245 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12246 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12247 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12249 if (wfex.wFormatTag == 0x0161) {
12250 codec_name = "Windows Media Audio";
12252 } else if (wfex.wFormatTag == 0x0162) {
12253 codec_name = "Windows Media Audio 9 Pro";
12255 } else if (wfex.wFormatTag == 0x0163) {
12256 codec_name = "Windows Media Audio 9 Lossless";
12257 /* is that correct? gstffmpegcodecmap.c is missing it, but
12258 * fluendo codec seems to support it */
12262 gst_caps_set_simple (entry->caps,
12263 "wmaversion", G_TYPE_INT, version,
12264 "block_align", G_TYPE_INT, wfex.nBlockAlign,
12265 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12266 "width", G_TYPE_INT, wfex.wBitsPerSample,
12267 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12269 if (size > wfex.cbSize) {
12272 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12273 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12274 size - wfex.cbSize);
12275 gst_caps_set_simple (entry->caps,
12276 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12277 gst_buffer_unref (buf);
12279 GST_WARNING_OBJECT (qtdemux, "no codec data");
12284 codec = g_strdup (codec_name);
12292 wfex_data += size + 8;
12298 const guint8 *opus_data;
12299 guint8 *channel_mapping = NULL;
12302 guint8 channel_mapping_family;
12303 guint8 stream_count;
12304 guint8 coupled_count;
12307 opus_data = stsd_entry_data;
12309 channels = GST_READ_UINT8 (opus_data + 45);
12310 rate = GST_READ_UINT32_LE (opus_data + 48);
12311 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12312 stream_count = GST_READ_UINT8 (opus_data + 55);
12313 coupled_count = GST_READ_UINT8 (opus_data + 56);
12315 if (channels > 0) {
12316 channel_mapping = g_malloc (channels * sizeof (guint8));
12317 for (i = 0; i < channels; i++)
12318 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12321 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12322 channel_mapping_family, stream_count, coupled_count,
12334 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12335 GST_TAG_AUDIO_CODEC, codec, NULL);
12339 /* some bitrate info may have ended up in caps */
12340 s = gst_caps_get_structure (entry->caps, 0);
12341 gst_structure_get_int (s, "bitrate", &bitrate);
12343 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12344 GST_TAG_BITRATE, bitrate, NULL);
12348 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12349 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12350 if (stream->protected) {
12351 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
12352 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12354 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
12364 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12366 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12368 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12372 /* If the fourcc's bottom 16 bits gives 'sm', then the top
12373 16 bits is a byte-swapped wave-style codec identifier,
12374 and we can find a WAVE header internally to a 'wave' atom here.
12375 This can more clearly be thought of as 'ms' as the top 16 bits, and a
12376 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12379 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12380 if (len < offset + 20) {
12381 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12383 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12384 const guint8 *data = stsd_entry_data + offset + 16;
12386 GNode *waveheadernode;
12388 wavenode = g_node_new ((guint8 *) data);
12389 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12390 const guint8 *waveheader;
12393 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12394 if (waveheadernode) {
12395 waveheader = (const guint8 *) waveheadernode->data;
12396 headerlen = QT_UINT32 (waveheader);
12398 if (headerlen > 8) {
12399 gst_riff_strf_auds *header = NULL;
12400 GstBuffer *headerbuf;
12406 headerbuf = gst_buffer_new_and_alloc (headerlen);
12407 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12409 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12410 headerbuf, &header, &extra)) {
12411 gst_caps_unref (entry->caps);
12412 /* FIXME: Need to do something with the channel reorder map */
12414 gst_riff_create_audio_caps (header->format, NULL, header,
12415 extra, NULL, NULL, NULL);
12418 gst_buffer_unref (extra);
12423 GST_DEBUG ("Didn't find waveheadernode for this codec");
12425 g_node_destroy (wavenode);
12428 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12429 stream->stream_tags);
12433 /* FIXME: what is in the chunk? */
12436 gint len = QT_UINT32 (stsd_data);
12438 /* seems to be always = 116 = 0x74 */
12444 gint len = QT_UINT32 (stsd_entry_data);
12447 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12449 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12450 gst_caps_set_simple (entry->caps,
12451 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12452 gst_buffer_unref (buf);
12454 gst_caps_set_simple (entry->caps,
12455 "samplesize", G_TYPE_INT, samplesize, NULL);
12460 GNode *alac, *wave = NULL;
12462 /* apparently, m4a has this atom appended directly in the stsd entry,
12463 * while mov has it in a wave atom */
12464 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12466 /* alac now refers to stsd entry atom */
12467 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12469 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12471 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12474 const guint8 *alac_data = alac->data;
12475 gint len = QT_UINT32 (alac->data);
12479 GST_DEBUG_OBJECT (qtdemux,
12480 "discarding alac atom with unexpected len %d", len);
12482 /* codec-data contains alac atom size and prefix,
12483 * ffmpeg likes it that way, not quite gst-ish though ...*/
12484 buf = gst_buffer_new_and_alloc (len);
12485 gst_buffer_fill (buf, 0, alac->data, len);
12486 gst_caps_set_simple (entry->caps,
12487 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12488 gst_buffer_unref (buf);
12490 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12491 entry->n_channels = QT_UINT8 (alac_data + 21);
12492 entry->rate = QT_UINT32 (alac_data + 32);
12493 samplesize = QT_UINT8 (alac_data + 16 + 1);
12496 gst_caps_set_simple (entry->caps,
12497 "samplesize", G_TYPE_INT, samplesize, NULL);
12502 /* The codingname of the sample entry is 'fLaC' */
12503 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12506 /* The 'dfLa' box is added to the sample entry to convey
12507 initializing information for the decoder. */
12508 const GNode *dfla =
12509 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12512 const guint32 len = QT_UINT32 (dfla->data);
12514 /* Must contain at least dfLa box header (12),
12515 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12517 GST_DEBUG_OBJECT (qtdemux,
12518 "discarding dfla atom with unexpected len %d", len);
12520 /* skip dfLa header to get the METADATA_BLOCKs */
12521 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12522 const guint32 metadata_blocks_len = len - 12;
12524 gchar *stream_marker = g_strdup ("fLaC");
12525 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12526 strlen (stream_marker));
12529 guint32 remainder = 0;
12530 guint32 block_size = 0;
12531 gboolean is_last = FALSE;
12533 GValue array = G_VALUE_INIT;
12534 GValue value = G_VALUE_INIT;
12536 g_value_init (&array, GST_TYPE_ARRAY);
12537 g_value_init (&value, GST_TYPE_BUFFER);
12539 gst_value_set_buffer (&value, block);
12540 gst_value_array_append_value (&array, &value);
12541 g_value_reset (&value);
12543 gst_buffer_unref (block);
12545 /* check there's at least one METADATA_BLOCK_HEADER's worth
12546 * of data, and we haven't already finished parsing */
12547 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12548 remainder = metadata_blocks_len - index;
12550 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12552 (metadata_blocks[index + 1] << 16) +
12553 (metadata_blocks[index + 2] << 8) +
12554 metadata_blocks[index + 3];
12556 /* be careful not to read off end of box */
12557 if (block_size > remainder) {
12561 is_last = metadata_blocks[index] >> 7;
12563 block = gst_buffer_new_and_alloc (block_size);
12565 gst_buffer_fill (block, 0, &metadata_blocks[index],
12568 gst_value_set_buffer (&value, block);
12569 gst_value_array_append_value (&array, &value);
12570 g_value_reset (&value);
12572 gst_buffer_unref (block);
12574 index += block_size;
12577 /* only append the metadata if we successfully read all of it */
12579 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12580 (stream)->caps, 0), "streamheader", &array);
12582 GST_WARNING_OBJECT (qtdemux,
12583 "discarding all METADATA_BLOCKs due to invalid "
12584 "block_size %d at idx %d, rem %d", block_size, index,
12588 g_value_unset (&value);
12589 g_value_unset (&array);
12591 /* The sample rate obtained from the stsd may not be accurate
12592 * since it cannot represent rates greater than 65535Hz, so
12593 * override that value with the sample rate from the
12594 * METADATA_BLOCK_STREAMINFO block */
12595 CUR_STREAM (stream)->rate =
12596 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12607 gint len = QT_UINT32 (stsd_entry_data);
12610 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12613 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12615 /* If we have enough data, let's try to get the 'damr' atom. See
12616 * the 3GPP container spec (26.244) for more details. */
12617 if ((len - 0x34) > 8 &&
12618 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12619 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12620 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12623 gst_caps_set_simple (entry->caps,
12624 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12625 gst_buffer_unref (buf);
12631 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12632 gint len = QT_UINT32 (stsd_entry_data);
12635 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12637 if (sound_version == 1) {
12638 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12639 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12640 guint8 codec_data[2];
12642 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12644 gint sample_rate_index =
12645 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12647 /* build AAC codec data */
12648 codec_data[0] = profile << 3;
12649 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12650 codec_data[1] = (sample_rate_index & 0x01) << 7;
12651 codec_data[1] |= (channels & 0xF) << 3;
12653 buf = gst_buffer_new_and_alloc (2);
12654 gst_buffer_fill (buf, 0, codec_data, 2);
12655 gst_caps_set_simple (entry->caps,
12656 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12657 gst_buffer_unref (buf);
12668 /* Fully handled elsewhere */
12671 GST_INFO_OBJECT (qtdemux,
12672 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12676 GST_INFO_OBJECT (qtdemux,
12677 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12678 GST_FOURCC_ARGS (fourcc), entry->caps);
12680 } else if (stream->subtype == FOURCC_strm) {
12681 if (fourcc == FOURCC_rtsp) {
12682 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12684 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12685 GST_FOURCC_ARGS (fourcc));
12686 goto unknown_stream;
12688 entry->sampled = TRUE;
12689 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12690 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12691 || stream->subtype == FOURCC_clcp) {
12693 entry->sampled = TRUE;
12694 entry->sparse = TRUE;
12697 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12700 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12701 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12706 /* hunt for sort-of codec data */
12710 GNode *mp4s = NULL;
12711 GNode *esds = NULL;
12713 /* look for palette in a stsd->mp4s->esds sub-atom */
12714 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12716 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12717 if (esds == NULL) {
12719 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12723 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12724 stream->stream_tags);
12728 GST_INFO_OBJECT (qtdemux,
12729 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12732 GST_INFO_OBJECT (qtdemux,
12733 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12734 GST_FOURCC_ARGS (fourcc), entry->caps);
12736 /* everything in 1 sample */
12737 entry->sampled = TRUE;
12740 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12743 if (entry->caps == NULL)
12744 goto unknown_stream;
12747 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12748 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12754 /* promote to sampled format */
12755 if (entry->fourcc == FOURCC_samr) {
12756 /* force mono 8000 Hz for AMR */
12757 entry->sampled = TRUE;
12758 entry->n_channels = 1;
12759 entry->rate = 8000;
12760 } else if (entry->fourcc == FOURCC_sawb) {
12761 /* force mono 16000 Hz for AMR-WB */
12762 entry->sampled = TRUE;
12763 entry->n_channels = 1;
12764 entry->rate = 16000;
12765 } else if (entry->fourcc == FOURCC_mp4a) {
12766 entry->sampled = TRUE;
12770 stsd_entry_data += len;
12771 remaining_stsd_len -= len;
12775 /* collect sample information */
12776 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12777 goto samples_failed;
12779 if (qtdemux->fragmented) {
12782 /* need all moov samples as basis; probably not many if any at all */
12783 /* prevent moof parsing taking of at this time */
12784 offset = qtdemux->moof_offset;
12785 qtdemux->moof_offset = 0;
12786 if (stream->n_samples &&
12787 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12788 qtdemux->moof_offset = offset;
12789 goto samples_failed;
12791 qtdemux->moof_offset = offset;
12792 /* movie duration more reliable in this case (e.g. mehd) */
12793 if (qtdemux->segment.duration &&
12794 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12796 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12799 /* configure segments */
12800 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12801 goto segments_failed;
12803 /* add some language tag, if useful */
12804 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12805 strcmp (stream->lang_id, "und")) {
12806 const gchar *lang_code;
12808 /* convert ISO 639-2 code to ISO 639-1 */
12809 lang_code = gst_tag_get_language_code (stream->lang_id);
12810 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12811 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12814 /* Check for UDTA tags */
12815 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12816 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12819 /* Insert and sort new stream in track-id order.
12820 * This will help in comparing old/new streams during stream update check */
12821 g_ptr_array_add (qtdemux->active_streams, stream);
12822 g_ptr_array_sort (qtdemux->active_streams,
12823 (GCompareFunc) qtdemux_track_id_compare_func);
12824 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
12825 QTDEMUX_N_STREAMS (qtdemux));
12832 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12833 (_("This file is corrupt and cannot be played.")), (NULL));
12835 gst_qtdemux_stream_unref (stream);
12840 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12841 gst_qtdemux_stream_unref (stream);
12847 /* we posted an error already */
12848 /* free stbl sub-atoms */
12849 gst_qtdemux_stbl_free (stream);
12850 gst_qtdemux_stream_unref (stream);
12855 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12861 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12862 GST_FOURCC_ARGS (stream->subtype));
12863 gst_qtdemux_stream_unref (stream);
12868 /* If we can estimate the overall bitrate, and don't have information about the
12869 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12870 * the overall bitrate minus the sum of the bitrates of all other streams. This
12871 * should be useful for the common case where we have one audio and one video
12872 * stream and can estimate the bitrate of one, but not the other. */
12874 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12876 QtDemuxStream *stream = NULL;
12877 gint64 size, sys_bitrate, sum_bitrate = 0;
12878 GstClockTime duration;
12882 if (qtdemux->fragmented)
12885 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12887 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12889 GST_DEBUG_OBJECT (qtdemux,
12890 "Size in bytes of the stream not known - bailing");
12894 /* Subtract the header size */
12895 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12896 size, qtdemux->header_size);
12898 if (size < qtdemux->header_size)
12901 size = size - qtdemux->header_size;
12903 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12904 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12908 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12909 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
12910 switch (str->subtype) {
12913 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12914 CUR_STREAM (str)->caps);
12915 /* retrieve bitrate, prefer avg then max */
12917 if (str->stream_tags) {
12918 if (gst_tag_list_get_uint (str->stream_tags,
12919 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12920 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12921 if (gst_tag_list_get_uint (str->stream_tags,
12922 GST_TAG_NOMINAL_BITRATE, &bitrate))
12923 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12924 if (gst_tag_list_get_uint (str->stream_tags,
12925 GST_TAG_BITRATE, &bitrate))
12926 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12929 sum_bitrate += bitrate;
12932 GST_DEBUG_OBJECT (qtdemux,
12933 ">1 stream with unknown bitrate - bailing");
12940 /* For other subtypes, we assume no significant impact on bitrate */
12946 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12950 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12952 if (sys_bitrate < sum_bitrate) {
12953 /* This can happen, since sum_bitrate might be derived from maximum
12954 * bitrates and not average bitrates */
12955 GST_DEBUG_OBJECT (qtdemux,
12956 "System bitrate less than sum bitrate - bailing");
12960 bitrate = sys_bitrate - sum_bitrate;
12961 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12962 ", Stream bitrate = %u", sys_bitrate, bitrate);
12964 if (!stream->stream_tags)
12965 stream->stream_tags = gst_tag_list_new_empty ();
12967 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12969 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12970 GST_TAG_BITRATE, bitrate, NULL);
12973 static GstFlowReturn
12974 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12976 GstFlowReturn ret = GST_FLOW_OK;
12979 GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
12981 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12982 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12983 guint32 sample_num = 0;
12985 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12986 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12988 if (qtdemux->fragmented && qtdemux->pullbased) {
12989 /* need all moov samples first */
12990 GST_OBJECT_LOCK (qtdemux);
12991 while (stream->n_samples == 0)
12992 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12994 GST_OBJECT_UNLOCK (qtdemux);
12996 /* discard any stray moof */
12997 qtdemux->moof_offset = 0;
13000 /* prepare braking */
13001 if (ret != GST_FLOW_ERROR)
13004 /* in pull mode, we should have parsed some sample info by now;
13005 * and quite some code will not handle no samples.
13006 * in push mode, we'll just have to deal with it */
13007 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13008 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13009 g_ptr_array_remove_index (qtdemux->active_streams, i);
13012 } else if (stream->track_id == qtdemux->chapters_track_id &&
13013 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13014 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13015 so that it doesn't look like a subtitle track */
13016 g_ptr_array_remove_index (qtdemux->active_streams, i);
13021 /* parse the initial sample for use in setting the frame rate cap */
13022 while (sample_num == 0 && sample_num < stream->n_samples) {
13023 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13033 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13035 return g_strcmp0 (stream->stream_id, stream_id) == 0;
13039 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13043 /* Different length, updated */
13044 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13047 /* streams in list are sorted in track-id order */
13048 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13049 /* Different stream-id, updated */
13050 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13051 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13059 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13060 QtDemuxStream * oldstream, QtDemuxStream * newstream)
13062 /* Connect old stream's srcpad to new stream */
13063 newstream->pad = oldstream->pad;
13064 oldstream->pad = NULL;
13066 /* unset new_stream to prevent stream-start event */
13067 newstream->new_stream = FALSE;
13069 return gst_qtdemux_configure_stream (qtdemux, newstream);
13073 qtdemux_update_streams (GstQTDemux * qtdemux)
13076 g_assert (qtdemux->streams_aware);
13078 /* At below, figure out which stream in active_streams has identical stream-id
13079 * with that of in old_streams. If there is matching stream-id,
13080 * corresponding newstream will not be exposed again,
13081 * but demux will reuse srcpad of matched old stream
13083 * active_streams : newly created streams from the latest moov
13084 * old_streams : existing streams (belong to previous moov)
13087 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13088 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13089 QtDemuxStream *oldstream = NULL;
13092 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13093 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13095 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13096 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13097 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13099 /* null pad stream cannot be reused */
13100 if (oldstream->pad == NULL)
13105 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13107 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13110 /* we don't need to preserve order of old streams */
13111 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13115 /* now we have all info and can expose */
13116 list = stream->stream_tags;
13117 stream->stream_tags = NULL;
13118 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13126 /* Must be called with expose lock */
13127 static GstFlowReturn
13128 qtdemux_expose_streams (GstQTDemux * qtdemux)
13132 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13134 if (!qtdemux_is_streams_update (qtdemux)) {
13135 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13136 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13137 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13138 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13139 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13140 return GST_FLOW_ERROR;
13143 g_ptr_array_set_size (qtdemux->old_streams, 0);
13144 qtdemux->need_segment = TRUE;
13146 return GST_FLOW_OK;
13149 if (qtdemux->streams_aware) {
13150 if (!qtdemux_update_streams (qtdemux))
13151 return GST_FLOW_ERROR;
13153 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13154 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13157 /* now we have all info and can expose */
13158 list = stream->stream_tags;
13159 stream->stream_tags = NULL;
13160 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13161 return GST_FLOW_ERROR;
13166 gst_qtdemux_guess_bitrate (qtdemux);
13168 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13170 /* If we have still old_streams, it's no more used stream */
13171 for (i = 0; i < qtdemux->old_streams->len; i++) {
13172 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13177 event = gst_event_new_eos ();
13178 if (qtdemux->segment_seqnum)
13179 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13181 gst_pad_push_event (stream->pad, event);
13185 g_ptr_array_set_size (qtdemux->old_streams, 0);
13187 /* check if we should post a redirect in case there is a single trak
13188 * and it is a redirecting trak */
13189 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13190 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13193 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13194 "an external content");
13195 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13196 gst_structure_new ("redirect",
13197 "new-location", G_TYPE_STRING,
13198 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13199 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13200 g_free (qtdemux->redirect_location);
13201 qtdemux->redirect_location =
13202 g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
13205 g_ptr_array_foreach (qtdemux->active_streams,
13206 (GFunc) qtdemux_do_allocation, qtdemux);
13208 qtdemux->need_segment = TRUE;
13210 qtdemux->exposed = TRUE;
13211 return GST_FLOW_OK;
13216 GstStructure *structure; /* helper for sort function */
13218 guint min_req_bitrate;
13219 guint min_req_qt_version;
13223 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13225 GstQtReference *ref_a = (GstQtReference *) a;
13226 GstQtReference *ref_b = (GstQtReference *) b;
13228 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13229 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13231 /* known bitrates go before unknown; higher bitrates go first */
13232 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13235 /* sort the redirects and post a message for the application.
13238 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13240 GstQtReference *best;
13243 GValue list_val = { 0, };
13246 g_assert (references != NULL);
13248 references = g_list_sort (references, qtdemux_redirects_sort_func);
13250 best = (GstQtReference *) references->data;
13252 g_value_init (&list_val, GST_TYPE_LIST);
13254 for (l = references; l != NULL; l = l->next) {
13255 GstQtReference *ref = (GstQtReference *) l->data;
13256 GValue struct_val = { 0, };
13258 ref->structure = gst_structure_new ("redirect",
13259 "new-location", G_TYPE_STRING, ref->location, NULL);
13261 if (ref->min_req_bitrate > 0) {
13262 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13263 ref->min_req_bitrate, NULL);
13266 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13267 g_value_set_boxed (&struct_val, ref->structure);
13268 gst_value_list_append_value (&list_val, &struct_val);
13269 g_value_unset (&struct_val);
13270 /* don't free anything here yet, since we need best->structure below */
13273 g_assert (best != NULL);
13274 s = gst_structure_copy (best->structure);
13276 if (g_list_length (references) > 1) {
13277 gst_structure_set_value (s, "locations", &list_val);
13280 g_value_unset (&list_val);
13282 for (l = references; l != NULL; l = l->next) {
13283 GstQtReference *ref = (GstQtReference *) l->data;
13285 gst_structure_free (ref->structure);
13286 g_free (ref->location);
13289 g_list_free (references);
13291 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13292 g_free (qtdemux->redirect_location);
13293 qtdemux->redirect_location =
13294 g_strdup (gst_structure_get_string (s, "new-location"));
13295 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13296 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13299 /* look for redirect nodes, collect all redirect information and
13303 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13305 GNode *rmra, *rmda, *rdrf;
13307 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13309 GList *redirects = NULL;
13311 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13313 GstQtReference ref = { NULL, NULL, 0, 0 };
13314 GNode *rmdr, *rmvc;
13316 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13317 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13318 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13319 ref.min_req_bitrate);
13322 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13323 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13324 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13326 #ifndef GST_DISABLE_GST_DEBUG
13327 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13329 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13331 GST_LOG_OBJECT (qtdemux,
13332 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13333 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13334 bitmask, check_type);
13335 if (package == FOURCC_qtim && check_type == 0) {
13336 ref.min_req_qt_version = version;
13340 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13346 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13347 if (ref_len > 20) {
13348 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13349 ref_data = (guint8 *) rdrf->data + 20;
13350 if (ref_type == FOURCC_alis) {
13351 guint record_len, record_version, fn_len;
13353 if (ref_len > 70) {
13354 /* MacOSX alias record, google for alias-layout.txt */
13355 record_len = QT_UINT16 (ref_data + 4);
13356 record_version = QT_UINT16 (ref_data + 4 + 2);
13357 fn_len = QT_UINT8 (ref_data + 50);
13358 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13359 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13362 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13365 } else if (ref_type == FOURCC_url_) {
13366 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13368 GST_DEBUG_OBJECT (qtdemux,
13369 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13370 GST_FOURCC_ARGS (ref_type));
13372 if (ref.location != NULL) {
13373 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13375 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13377 GST_WARNING_OBJECT (qtdemux,
13378 "Failed to extract redirect location from rdrf atom");
13381 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13385 /* look for others */
13386 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13389 if (redirects != NULL) {
13390 qtdemux_process_redirects (qtdemux, redirects);
13396 static GstTagList *
13397 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13401 if (tags == NULL) {
13402 tags = gst_tag_list_new_empty ();
13403 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13406 if (qtdemux->major_brand == FOURCC_mjp2)
13407 fmt = "Motion JPEG 2000";
13408 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13410 else if (qtdemux->major_brand == FOURCC_qt__)
13412 else if (qtdemux->fragmented)
13415 fmt = "ISO MP4/M4A";
13417 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13418 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13420 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13426 /* we have read the complete moov node now.
13427 * This function parses all of the relevant info, creates the traks and
13428 * prepares all data structures for playback
13431 qtdemux_parse_tree (GstQTDemux * qtdemux)
13438 guint64 creation_time;
13439 GstDateTime *datetime = NULL;
13442 /* make sure we have a usable taglist */
13443 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13445 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13446 if (mvhd == NULL) {
13447 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13448 return qtdemux_parse_redirects (qtdemux);
13451 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13452 if (version == 1) {
13453 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13454 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13455 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13456 } else if (version == 0) {
13457 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13458 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13459 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13461 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13465 /* Moving qt creation time (secs since 1904) to unix time */
13466 if (creation_time != 0) {
13467 /* Try to use epoch first as it should be faster and more commonly found */
13468 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13471 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13472 /* some data cleansing sanity */
13473 now_s = g_get_real_time () / G_USEC_PER_SEC;
13474 if (now_s + 24 * 3600 < creation_time) {
13475 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13477 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13480 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13481 GDateTime *dt, *dt_local;
13483 dt = g_date_time_add_seconds (base_dt, creation_time);
13484 dt_local = g_date_time_to_local (dt);
13485 datetime = gst_date_time_new_from_g_date_time (dt_local);
13487 g_date_time_unref (base_dt);
13488 g_date_time_unref (dt);
13492 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13493 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13495 gst_date_time_unref (datetime);
13498 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13499 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13501 /* check for fragmented file and get some (default) data */
13502 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13505 GstByteReader mehd_data;
13507 /* let track parsing or anyone know weird stuff might happen ... */
13508 qtdemux->fragmented = TRUE;
13510 /* compensate for total duration */
13511 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13513 qtdemux_parse_mehd (qtdemux, &mehd_data);
13516 /* Update the movie segment duration, unless it was directly given to us
13517 * by upstream. Otherwise let it as is, as we don't want to mangle the
13518 * duration provided by upstream that may come e.g. from a MPD file. */
13519 if (!qtdemux->upstream_format_is_time) {
13520 GstClockTime duration;
13521 /* set duration in the segment info */
13522 gst_qtdemux_get_duration (qtdemux, &duration);
13523 qtdemux->segment.duration = duration;
13524 /* also do not exceed duration; stop is set that way post seek anyway,
13525 * and segment activation falls back to duration,
13526 * whereas loop only checks stop, so let's align this here as well */
13527 qtdemux->segment.stop = duration;
13530 /* parse all traks */
13531 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13533 qtdemux_parse_trak (qtdemux, trak);
13534 /* iterate all siblings */
13535 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13538 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13541 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13543 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13545 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13548 /* maybe also some tags in meta box */
13549 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13551 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13552 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13554 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13557 /* parse any protection system info */
13558 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13560 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13561 qtdemux_parse_pssh (qtdemux, pssh);
13562 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13565 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13570 /* taken from ffmpeg */
13572 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13584 len = (len << 7) | (c & 0x7f);
13593 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13594 gsize codec_data_size)
13596 GList *list = NULL;
13597 guint8 *p = codec_data;
13598 gint i, offset, num_packets;
13599 guint *length, last;
13601 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13603 if (codec_data == NULL || codec_data_size == 0)
13606 /* start of the stream and vorbis audio or theora video, need to
13607 * send the codec_priv data as first three packets */
13608 num_packets = p[0] + 1;
13609 GST_DEBUG_OBJECT (qtdemux,
13610 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13611 (guint) num_packets, codec_data_size);
13613 /* Let's put some limits, Don't think there even is a xiph codec
13614 * with more than 3-4 headers */
13615 if (G_UNLIKELY (num_packets > 16)) {
13616 GST_WARNING_OBJECT (qtdemux,
13617 "Unlikely number of xiph headers, most likely not valid");
13621 length = g_alloca (num_packets * sizeof (guint));
13625 /* first packets, read length values */
13626 for (i = 0; i < num_packets - 1; i++) {
13628 while (offset < codec_data_size) {
13629 length[i] += p[offset];
13630 if (p[offset++] != 0xff)
13635 if (offset + last > codec_data_size)
13638 /* last packet is the remaining size */
13639 length[i] = codec_data_size - offset - last;
13641 for (i = 0; i < num_packets; i++) {
13644 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13646 if (offset + length[i] > codec_data_size)
13649 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
13650 list = g_list_append (list, hdr);
13652 offset += length[i];
13661 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13667 /* this can change the codec originally present in @list */
13669 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13670 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13672 int len = QT_UINT32 (esds->data);
13673 guint8 *ptr = esds->data;
13674 guint8 *end = ptr + len;
13676 guint8 *data_ptr = NULL;
13678 guint8 object_type_id = 0;
13679 guint8 stream_type = 0;
13680 const char *codec_name = NULL;
13681 GstCaps *caps = NULL;
13683 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13685 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13687 while (ptr + 1 < end) {
13688 tag = QT_UINT8 (ptr);
13689 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13691 len = read_descr_size (ptr, end, &ptr);
13692 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13694 /* Check the stated amount of data is available for reading */
13695 if (len < 0 || ptr + len > end)
13699 case ES_DESCRIPTOR_TAG:
13700 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13701 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13704 case DECODER_CONFIG_DESC_TAG:{
13705 guint max_bitrate, avg_bitrate;
13707 object_type_id = QT_UINT8 (ptr);
13708 stream_type = QT_UINT8 (ptr + 1) >> 2;
13709 max_bitrate = QT_UINT32 (ptr + 5);
13710 avg_bitrate = QT_UINT32 (ptr + 9);
13711 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13712 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13713 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13714 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13715 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13716 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13717 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13718 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13720 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13721 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13722 avg_bitrate, NULL);
13727 case DECODER_SPECIFIC_INFO_TAG:
13728 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13729 if (object_type_id == 0xe0 && len == 0x40) {
13735 GST_DEBUG_OBJECT (qtdemux,
13736 "Have VOBSUB palette. Creating palette event");
13737 /* move to decConfigDescr data and read palette */
13739 for (i = 0; i < 16; i++) {
13740 clut[i] = QT_UINT32 (data);
13744 s = gst_structure_new ("application/x-gst-dvd", "event",
13745 G_TYPE_STRING, "dvd-spu-clut-change",
13746 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13747 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13748 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13749 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13750 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13751 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13752 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13753 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13756 /* store event and trigger custom processing */
13757 stream->pending_event =
13758 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13760 /* Generic codec_data handler puts it on the caps */
13767 case SL_CONFIG_DESC_TAG:
13768 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13772 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13774 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13780 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13781 * in use, and should also be used to override some other parameters for some
13783 switch (object_type_id) {
13784 case 0x20: /* MPEG-4 */
13785 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13786 * profile_and_level_indication */
13787 if (data_ptr != NULL && data_len >= 5 &&
13788 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13789 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13790 data_ptr + 4, data_len - 4);
13792 break; /* Nothing special needed here */
13793 case 0x21: /* H.264 */
13794 codec_name = "H.264 / AVC";
13795 caps = gst_caps_new_simple ("video/x-h264",
13796 "stream-format", G_TYPE_STRING, "avc",
13797 "alignment", G_TYPE_STRING, "au", NULL);
13799 case 0x40: /* AAC (any) */
13800 case 0x66: /* AAC Main */
13801 case 0x67: /* AAC LC */
13802 case 0x68: /* AAC SSR */
13803 /* Override channels and rate based on the codec_data, as it's often
13805 /* Only do so for basic setup without HE-AAC extension */
13806 if (data_ptr && data_len == 2) {
13807 guint channels, rate;
13809 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13811 entry->n_channels = channels;
13813 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13815 entry->rate = rate;
13818 /* Set level and profile if possible */
13819 if (data_ptr != NULL && data_len >= 2) {
13820 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13821 data_ptr, data_len);
13823 const gchar *profile_str = NULL;
13826 guint8 *codec_data;
13827 gint rate_idx, profile;
13829 /* No codec_data, let's invent something.
13830 * FIXME: This is wrong for SBR! */
13832 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13834 buffer = gst_buffer_new_and_alloc (2);
13835 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13836 codec_data = map.data;
13839 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13842 switch (object_type_id) {
13844 profile_str = "main";
13848 profile_str = "lc";
13852 profile_str = "ssr";
13860 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
13862 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
13864 gst_buffer_unmap (buffer, &map);
13865 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
13866 GST_TYPE_BUFFER, buffer, NULL);
13867 gst_buffer_unref (buffer);
13870 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
13871 G_TYPE_STRING, profile_str, NULL);
13875 case 0x60: /* MPEG-2, various profiles */
13881 codec_name = "MPEG-2 video";
13882 caps = gst_caps_new_simple ("video/mpeg",
13883 "mpegversion", G_TYPE_INT, 2,
13884 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13886 case 0x69: /* MPEG-2 BC audio */
13887 case 0x6B: /* MPEG-1 audio */
13888 caps = gst_caps_new_simple ("audio/mpeg",
13889 "mpegversion", G_TYPE_INT, 1, NULL);
13890 codec_name = "MPEG-1 audio";
13892 case 0x6A: /* MPEG-1 */
13893 codec_name = "MPEG-1 video";
13894 caps = gst_caps_new_simple ("video/mpeg",
13895 "mpegversion", G_TYPE_INT, 1,
13896 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13898 case 0x6C: /* MJPEG */
13900 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
13902 codec_name = "Motion-JPEG";
13904 case 0x6D: /* PNG */
13906 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
13908 codec_name = "PNG still images";
13910 case 0x6E: /* JPEG2000 */
13911 codec_name = "JPEG-2000";
13912 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
13914 case 0xA4: /* Dirac */
13915 codec_name = "Dirac";
13916 caps = gst_caps_new_empty_simple ("video/x-dirac");
13918 case 0xA5: /* AC3 */
13919 codec_name = "AC-3 audio";
13920 caps = gst_caps_new_simple ("audio/x-ac3",
13921 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13923 case 0xA9: /* AC3 */
13924 codec_name = "DTS audio";
13925 caps = gst_caps_new_simple ("audio/x-dts",
13926 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13929 if (stream_type == 0x05 && data_ptr) {
13931 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
13934 GValue arr_val = G_VALUE_INIT;
13935 GValue buf_val = G_VALUE_INIT;
13938 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
13939 codec_name = "Vorbis";
13940 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
13941 g_value_init (&arr_val, GST_TYPE_ARRAY);
13942 g_value_init (&buf_val, GST_TYPE_BUFFER);
13943 for (tmp = headers; tmp; tmp = tmp->next) {
13944 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
13945 gst_value_array_append_value (&arr_val, &buf_val);
13947 s = gst_caps_get_structure (caps, 0);
13948 gst_structure_take_value (s, "streamheader", &arr_val);
13949 g_value_unset (&buf_val);
13950 g_list_free (headers);
13957 case 0xE1: /* QCELP */
13958 /* QCELP, the codec_data is a riff tag (little endian) with
13959 * 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). */
13960 caps = gst_caps_new_empty_simple ("audio/qcelp");
13961 codec_name = "QCELP";
13967 /* If we have a replacement caps, then change our caps for this stream */
13969 gst_caps_unref (entry->caps);
13970 entry->caps = caps;
13973 if (codec_name && list)
13974 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13975 GST_TAG_AUDIO_CODEC, codec_name, NULL);
13977 /* Add the codec_data attribute to caps, if we have it */
13981 buffer = gst_buffer_new_and_alloc (data_len);
13982 gst_buffer_fill (buffer, 0, data_ptr, data_len);
13984 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
13985 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
13987 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
13989 gst_buffer_unref (buffer);
13994 static inline GstCaps *
13995 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
13999 char *s, fourstr[5];
14001 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14002 for (i = 0; i < 4; i++) {
14003 if (!g_ascii_isalnum (fourstr[i]))
14006 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14007 caps = gst_caps_new_empty_simple (s);
14012 #define _codec(name) \
14014 if (codec_name) { \
14015 *codec_name = g_strdup (name); \
14020 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14021 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14022 const guint8 * stsd_entry_data, gchar ** codec_name)
14024 GstCaps *caps = NULL;
14025 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14029 _codec ("PNG still images");
14030 caps = gst_caps_new_empty_simple ("image/png");
14033 _codec ("JPEG still images");
14035 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14038 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14039 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14040 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14041 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14042 _codec ("Motion-JPEG");
14044 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14047 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14048 _codec ("Motion-JPEG format B");
14049 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14052 _codec ("JPEG-2000");
14053 /* override to what it should be according to spec, avoid palette_data */
14054 entry->bits_per_sample = 24;
14055 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14058 _codec ("Sorensen video v.3");
14059 caps = gst_caps_new_simple ("video/x-svq",
14060 "svqversion", G_TYPE_INT, 3, NULL);
14062 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14063 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14064 _codec ("Sorensen video v.1");
14065 caps = gst_caps_new_simple ("video/x-svq",
14066 "svqversion", G_TYPE_INT, 1, NULL);
14068 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14069 caps = gst_caps_new_empty_simple ("video/x-raw");
14070 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14071 _codec ("Windows Raw RGB");
14072 stream->alignment = 32;
14078 bps = QT_UINT16 (stsd_entry_data + 82);
14081 format = GST_VIDEO_FORMAT_RGB15;
14084 format = GST_VIDEO_FORMAT_RGB16;
14087 format = GST_VIDEO_FORMAT_RGB;
14090 format = GST_VIDEO_FORMAT_ARGB;
14098 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14099 format = GST_VIDEO_FORMAT_I420;
14101 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14102 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14103 format = GST_VIDEO_FORMAT_I420;
14106 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14107 format = GST_VIDEO_FORMAT_UYVY;
14109 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14110 format = GST_VIDEO_FORMAT_v308;
14112 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14113 format = GST_VIDEO_FORMAT_v216;
14116 format = GST_VIDEO_FORMAT_v210;
14118 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14119 format = GST_VIDEO_FORMAT_r210;
14121 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14122 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14123 format = GST_VIDEO_FORMAT_v410;
14126 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14127 * but different order than AYUV
14128 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14129 format = GST_VIDEO_FORMAT_v408;
14132 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14133 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14134 _codec ("MPEG-1 video");
14135 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14136 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14138 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14139 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14140 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14141 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14142 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14143 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14144 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14145 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14146 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14147 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14148 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14149 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14150 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14151 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14152 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14153 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14154 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14155 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14156 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14157 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14158 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14159 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14160 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14161 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14162 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14163 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14164 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14165 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14166 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14167 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14168 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14169 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14170 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14171 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14172 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14173 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14174 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14175 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14176 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14177 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14178 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14179 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14180 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14181 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14182 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14183 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14184 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14185 _codec ("MPEG-2 video");
14186 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14187 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14189 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14190 _codec ("GIF still images");
14191 caps = gst_caps_new_empty_simple ("image/gif");
14194 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14196 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14198 /* ffmpeg uses the height/width props, don't know why */
14199 caps = gst_caps_new_simple ("video/x-h263",
14200 "variant", G_TYPE_STRING, "itu", NULL);
14204 _codec ("MPEG-4 video");
14205 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14206 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14208 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14209 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14210 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14211 caps = gst_caps_new_simple ("video/x-msmpeg",
14212 "msmpegversion", G_TYPE_INT, 43, NULL);
14214 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14216 caps = gst_caps_new_simple ("video/x-divx",
14217 "divxversion", G_TYPE_INT, 3, NULL);
14219 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14220 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14222 caps = gst_caps_new_simple ("video/x-divx",
14223 "divxversion", G_TYPE_INT, 4, NULL);
14225 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14227 caps = gst_caps_new_simple ("video/x-divx",
14228 "divxversion", G_TYPE_INT, 5, NULL);
14231 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14233 caps = gst_caps_new_simple ("video/x-ffv",
14234 "ffvversion", G_TYPE_INT, 1, NULL);
14237 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14238 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14243 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14244 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14245 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14249 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14250 _codec ("Cinepak");
14251 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14253 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14254 _codec ("Apple QuickDraw");
14255 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14257 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14258 _codec ("Apple video");
14259 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14264 _codec ("H.264 / AVC");
14265 caps = gst_caps_new_simple ("video/x-h264",
14266 "stream-format", G_TYPE_STRING, "avc",
14267 "alignment", G_TYPE_STRING, "au", NULL);
14271 _codec ("H.264 / AVC");
14272 caps = gst_caps_new_simple ("video/x-h264",
14273 "stream-format", G_TYPE_STRING, "avc3",
14274 "alignment", G_TYPE_STRING, "au", NULL);
14279 _codec ("H.265 / HEVC");
14280 caps = gst_caps_new_simple ("video/x-h265",
14281 "stream-format", G_TYPE_STRING, "hvc1",
14282 "alignment", G_TYPE_STRING, "au", NULL);
14286 _codec ("H.265 / HEVC");
14287 caps = gst_caps_new_simple ("video/x-h265",
14288 "stream-format", G_TYPE_STRING, "hev1",
14289 "alignment", G_TYPE_STRING, "au", NULL);
14292 _codec ("Run-length encoding");
14293 caps = gst_caps_new_simple ("video/x-rle",
14294 "layout", G_TYPE_STRING, "quicktime", NULL);
14297 _codec ("Run-length encoding");
14298 caps = gst_caps_new_simple ("video/x-rle",
14299 "layout", G_TYPE_STRING, "microsoft", NULL);
14301 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14302 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14303 _codec ("Indeo Video 3");
14304 caps = gst_caps_new_simple ("video/x-indeo",
14305 "indeoversion", G_TYPE_INT, 3, NULL);
14307 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14308 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14309 _codec ("Intel Video 4");
14310 caps = gst_caps_new_simple ("video/x-indeo",
14311 "indeoversion", G_TYPE_INT, 4, NULL);
14315 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14316 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14317 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14318 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14319 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14320 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14321 _codec ("DV Video");
14322 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14323 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14325 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14326 case FOURCC_dv5p: /* DVCPRO50 PAL */
14327 _codec ("DVCPro50 Video");
14328 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14329 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14331 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14332 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14333 _codec ("DVCProHD Video");
14334 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14335 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14337 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14338 _codec ("Apple Graphics (SMC)");
14339 caps = gst_caps_new_empty_simple ("video/x-smc");
14341 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14343 caps = gst_caps_new_empty_simple ("video/x-vp3");
14345 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14346 _codec ("VP6 Flash");
14347 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14351 caps = gst_caps_new_empty_simple ("video/x-theora");
14352 /* theora uses one byte of padding in the data stream because it does not
14353 * allow 0 sized packets while theora does */
14354 entry->padding = 1;
14358 caps = gst_caps_new_empty_simple ("video/x-dirac");
14360 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14361 _codec ("TIFF still images");
14362 caps = gst_caps_new_empty_simple ("image/tiff");
14364 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14365 _codec ("Apple Intermediate Codec");
14366 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14368 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14369 _codec ("AVID DNxHD");
14370 caps = gst_caps_from_string ("video/x-dnxhd");
14374 _codec ("On2 VP8");
14375 caps = gst_caps_from_string ("video/x-vp8");
14378 _codec ("Google VP9");
14379 caps = gst_caps_from_string ("video/x-vp9");
14382 _codec ("Apple ProRes LT");
14384 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14388 _codec ("Apple ProRes HQ");
14390 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14394 _codec ("Apple ProRes");
14396 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14400 _codec ("Apple ProRes Proxy");
14402 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14406 _codec ("Apple ProRes 4444");
14408 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14412 _codec ("Apple ProRes 4444 XQ");
14414 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14418 _codec ("GoPro CineForm");
14419 caps = gst_caps_from_string ("video/x-cineform");
14424 caps = gst_caps_new_simple ("video/x-wmv",
14425 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14429 caps = gst_caps_new_empty_simple ("video/x-av1");
14431 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14434 caps = _get_unknown_codec_name ("video", fourcc);
14439 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14442 gst_video_info_init (&info);
14443 gst_video_info_set_format (&info, format, entry->width, entry->height);
14445 caps = gst_video_info_to_caps (&info);
14446 *codec_name = gst_pb_utils_get_codec_description (caps);
14448 /* enable clipping for raw video streams */
14449 stream->need_clip = TRUE;
14450 stream->alignment = 32;
14457 round_up_pow2 (guint n)
14469 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14470 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14471 int len, gchar ** codec_name)
14474 const GstStructure *s;
14477 GstAudioFormat format = 0;
14480 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14482 depth = entry->bytes_per_packet * 8;
14485 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14487 /* 8-bit audio is unsigned */
14489 format = GST_AUDIO_FORMAT_U8;
14490 /* otherwise it's signed and big-endian just like 'twos' */
14492 endian = G_BIG_ENDIAN;
14499 endian = G_LITTLE_ENDIAN;
14502 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14504 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14508 caps = gst_caps_new_simple ("audio/x-raw",
14509 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14510 "layout", G_TYPE_STRING, "interleaved", NULL);
14511 stream->alignment = GST_ROUND_UP_8 (depth);
14512 stream->alignment = round_up_pow2 (stream->alignment);
14516 _codec ("Raw 64-bit floating-point audio");
14517 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14519 caps = gst_caps_new_simple ("audio/x-raw",
14520 "format", G_TYPE_STRING, "F64BE",
14521 "layout", G_TYPE_STRING, "interleaved", NULL);
14522 stream->alignment = 8;
14525 _codec ("Raw 32-bit floating-point audio");
14526 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14528 caps = gst_caps_new_simple ("audio/x-raw",
14529 "format", G_TYPE_STRING, "F32BE",
14530 "layout", G_TYPE_STRING, "interleaved", NULL);
14531 stream->alignment = 4;
14534 _codec ("Raw 24-bit PCM audio");
14535 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14537 caps = gst_caps_new_simple ("audio/x-raw",
14538 "format", G_TYPE_STRING, "S24BE",
14539 "layout", G_TYPE_STRING, "interleaved", NULL);
14540 stream->alignment = 4;
14543 _codec ("Raw 32-bit PCM audio");
14544 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14546 caps = gst_caps_new_simple ("audio/x-raw",
14547 "format", G_TYPE_STRING, "S32BE",
14548 "layout", G_TYPE_STRING, "interleaved", NULL);
14549 stream->alignment = 4;
14552 _codec ("Raw 16-bit PCM audio");
14553 caps = gst_caps_new_simple ("audio/x-raw",
14554 "format", G_TYPE_STRING, "S16LE",
14555 "layout", G_TYPE_STRING, "interleaved", NULL);
14556 stream->alignment = 2;
14559 _codec ("Mu-law audio");
14560 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14563 _codec ("A-law audio");
14564 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14568 _codec ("Microsoft ADPCM");
14569 /* Microsoft ADPCM-ACM code 2 */
14570 caps = gst_caps_new_simple ("audio/x-adpcm",
14571 "layout", G_TYPE_STRING, "microsoft", NULL);
14575 _codec ("DVI/IMA ADPCM");
14576 caps = gst_caps_new_simple ("audio/x-adpcm",
14577 "layout", G_TYPE_STRING, "dvi", NULL);
14581 _codec ("DVI/Intel IMA ADPCM");
14582 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14583 caps = gst_caps_new_simple ("audio/x-adpcm",
14584 "layout", G_TYPE_STRING, "quicktime", NULL);
14588 /* MPEG layer 3, CBR only (pre QT4.1) */
14591 _codec ("MPEG-1 layer 3");
14592 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14593 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14594 "mpegversion", G_TYPE_INT, 1, NULL);
14596 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14597 _codec ("MPEG-1 layer 2");
14599 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14600 "mpegversion", G_TYPE_INT, 1, NULL);
14603 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14604 _codec ("EAC-3 audio");
14605 caps = gst_caps_new_simple ("audio/x-eac3",
14606 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14607 entry->sampled = TRUE;
14609 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14611 _codec ("AC-3 audio");
14612 caps = gst_caps_new_simple ("audio/x-ac3",
14613 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14614 entry->sampled = TRUE;
14616 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14617 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14618 _codec ("DTS audio");
14619 caps = gst_caps_new_simple ("audio/x-dts",
14620 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14621 entry->sampled = TRUE;
14623 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14624 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14625 _codec ("DTS-HD audio");
14626 caps = gst_caps_new_simple ("audio/x-dts",
14627 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14628 entry->sampled = TRUE;
14632 caps = gst_caps_new_simple ("audio/x-mace",
14633 "maceversion", G_TYPE_INT, 3, NULL);
14637 caps = gst_caps_new_simple ("audio/x-mace",
14638 "maceversion", G_TYPE_INT, 6, NULL);
14640 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14642 caps = gst_caps_new_empty_simple ("application/ogg");
14644 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14645 _codec ("DV audio");
14646 caps = gst_caps_new_empty_simple ("audio/x-dv");
14649 _codec ("MPEG-4 AAC audio");
14650 caps = gst_caps_new_simple ("audio/mpeg",
14651 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14652 "stream-format", G_TYPE_STRING, "raw", NULL);
14654 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14655 _codec ("QDesign Music");
14656 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14659 _codec ("QDesign Music v.2");
14660 /* FIXME: QDesign music version 2 (no constant) */
14661 if (FALSE && data) {
14662 caps = gst_caps_new_simple ("audio/x-qdm2",
14663 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14664 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14665 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14667 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14671 _codec ("GSM audio");
14672 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14675 _codec ("AMR audio");
14676 caps = gst_caps_new_empty_simple ("audio/AMR");
14679 _codec ("AMR-WB audio");
14680 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14683 _codec ("Quicktime IMA ADPCM");
14684 caps = gst_caps_new_simple ("audio/x-adpcm",
14685 "layout", G_TYPE_STRING, "quicktime", NULL);
14688 _codec ("Apple lossless audio");
14689 caps = gst_caps_new_empty_simple ("audio/x-alac");
14692 _codec ("Free Lossless Audio Codec");
14693 caps = gst_caps_new_simple ("audio/x-flac",
14694 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14696 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14697 _codec ("QualComm PureVoice");
14698 caps = gst_caps_from_string ("audio/qcelp");
14703 caps = gst_caps_new_empty_simple ("audio/x-wma");
14707 caps = gst_caps_new_empty_simple ("audio/x-opus");
14714 GstAudioFormat format;
14717 FLAG_IS_FLOAT = 0x1,
14718 FLAG_IS_BIG_ENDIAN = 0x2,
14719 FLAG_IS_SIGNED = 0x4,
14720 FLAG_IS_PACKED = 0x8,
14721 FLAG_IS_ALIGNED_HIGH = 0x10,
14722 FLAG_IS_NON_INTERLEAVED = 0x20
14724 _codec ("Raw LPCM audio");
14726 if (data && len >= 36) {
14727 depth = QT_UINT32 (data + 24);
14728 flags = QT_UINT32 (data + 28);
14729 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14731 if ((flags & FLAG_IS_FLOAT) == 0) {
14736 if ((flags & FLAG_IS_ALIGNED_HIGH))
14739 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14740 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14741 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14742 caps = gst_caps_new_simple ("audio/x-raw",
14743 "format", G_TYPE_STRING,
14745 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14746 "UNKNOWN", "layout", G_TYPE_STRING,
14747 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14748 "interleaved", NULL);
14749 stream->alignment = GST_ROUND_UP_8 (depth);
14750 stream->alignment = round_up_pow2 (stream->alignment);
14755 if (flags & FLAG_IS_BIG_ENDIAN)
14756 format = GST_AUDIO_FORMAT_F64BE;
14758 format = GST_AUDIO_FORMAT_F64LE;
14760 if (flags & FLAG_IS_BIG_ENDIAN)
14761 format = GST_AUDIO_FORMAT_F32BE;
14763 format = GST_AUDIO_FORMAT_F32LE;
14765 caps = gst_caps_new_simple ("audio/x-raw",
14766 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14767 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14768 "non-interleaved" : "interleaved", NULL);
14769 stream->alignment = width / 8;
14773 case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
14776 caps = gst_caps_new_empty_simple ("audio/x-ac4");
14779 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14783 caps = _get_unknown_codec_name ("audio", fourcc);
14789 GstCaps *templ_caps =
14790 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14791 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14792 gst_caps_unref (caps);
14793 gst_caps_unref (templ_caps);
14794 caps = intersection;
14797 /* enable clipping for raw audio streams */
14798 s = gst_caps_get_structure (caps, 0);
14799 name = gst_structure_get_name (s);
14800 if (g_str_has_prefix (name, "audio/x-raw")) {
14801 stream->need_clip = TRUE;
14802 stream->min_buffer_size = 1024 * entry->bytes_per_frame;
14803 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14804 GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
14805 stream->max_buffer_size);
14811 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14812 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14813 const guint8 * stsd_entry_data, gchar ** codec_name)
14817 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14821 _codec ("DVD subtitle");
14822 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14823 stream->need_process = TRUE;
14826 _codec ("Quicktime timed text");
14829 _codec ("3GPP timed text");
14831 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14833 /* actual text piece needs to be extracted */
14834 stream->need_process = TRUE;
14837 _codec ("XML subtitles");
14838 caps = gst_caps_new_empty_simple ("application/ttml+xml");
14841 _codec ("CEA 608 Closed Caption");
14843 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
14844 G_TYPE_STRING, "s334-1a", NULL);
14845 stream->need_process = TRUE;
14846 stream->need_split = TRUE;
14849 _codec ("CEA 708 Closed Caption");
14851 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
14852 G_TYPE_STRING, "cdp", NULL);
14853 stream->need_process = TRUE;
14858 caps = _get_unknown_codec_name ("text", fourcc);
14866 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14867 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14868 const guint8 * stsd_entry_data, gchar ** codec_name)
14874 _codec ("MPEG 1 video");
14875 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14876 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14886 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14887 const gchar * system_id)
14891 if (!qtdemux->protection_system_ids)
14892 qtdemux->protection_system_ids =
14893 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14894 /* Check whether we already have an entry for this system ID. */
14895 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14896 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14897 if (g_ascii_strcasecmp (system_id, id) == 0) {
14901 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14902 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,