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
33 * Demuxes a .mov file into raw or compressed audio and/or video streams.
35 * This element supports both push and pull-based scheduling, depending on the
36 * capabilities of the upstream elements.
39 * <title>Example launch line</title>
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/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.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"
76 #include <gst/math-compat.h>
82 /* max. size considered 'sane' for non-mdat atoms */
83 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
85 /* if the sample index is larger than this, something is likely wrong */
86 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
88 /* For converting qt creation times to unix epoch times */
89 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
90 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
91 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
92 QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
94 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
96 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
98 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
100 #define QTDEMUX_FIRST_STREAM(demux) ((QtDemuxStream *)(demux)->active_streams \
101 ? (QtDemuxStream *)(demux)->active_streams->data : NULL)
102 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 GST_DEBUG_CATEGORY (qtdemux_debug);
105 #define GST_CAT_DEFAULT qtdemux_debug
107 typedef struct _QtDemuxSegment QtDemuxSegment;
108 typedef struct _QtDemuxSample QtDemuxSample;
110 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
112 struct _QtDemuxSample
115 gint32 pts_offset; /* Add this value to timestamp to get the pts */
117 guint64 timestamp; /* DTS In mov time */
118 guint32 duration; /* In mov time */
119 gboolean keyframe; /* TRUE when this packet is a keyframe */
122 /* Macros for converting to/from timescale */
123 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
124 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
126 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
127 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
129 /* timestamp is the DTS */
130 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
131 /* timestamp + offset + cslg_shift is the outgoing PTS */
132 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
133 /* timestamp + offset is the PTS used for internal seek calcuations */
134 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
135 /* timestamp + duration - dts is the duration */
136 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
138 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
140 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
141 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
142 GST_TRACE("Locking from thread %p", g_thread_self()); \
143 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
144 GST_TRACE("Locked from thread %p", g_thread_self()); \
147 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
148 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
149 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
153 * Quicktime has tracks and segments. A track is a continuous piece of
154 * multimedia content. The track is not always played from start to finish but
155 * instead, pieces of the track are 'cut out' and played in sequence. This is
156 * what the segments do.
158 * Inside the track we have keyframes (K) and delta frames. The track has its
159 * own timing, which starts from 0 and extends to end. The position in the track
160 * is called the media_time.
162 * The segments now describe the pieces that should be played from this track
163 * and are basically tuples of media_time/duration/rate entries. We can have
164 * multiple segments and they are all played after one another. An example:
166 * segment 1: media_time: 1 second, duration: 1 second, rate 1
167 * segment 2: media_time: 3 second, duration: 2 second, rate 2
169 * To correctly play back this track, one must play: 1 second of media starting
170 * from media_time 1 followed by 2 seconds of media starting from media_time 3
173 * Each of the segments will be played at a specific time, the first segment at
174 * time 0, the second one after the duration of the first one, etc.. Note that
175 * the time in resulting playback is not identical to the media_time of the
178 * Visually, assuming the track has 4 second of media_time:
181 * .-----------------------------------------------------------.
182 * track: | K.....K.........K........K.......K.......K...........K... |
183 * '-----------------------------------------------------------'
185 * .------------^ ^ .----------^ ^
186 * / .-------------' / .------------------'
188 * .--------------. .--------------.
189 * | segment 1 | | segment 2 |
190 * '--------------' '--------------'
192 * The challenge here is to cut out the right pieces of the track for each of
193 * the playback segments. This fortunately can easily be done with the SEGMENT
194 * events of GStreamer.
196 * For playback of segment 1, we need to provide the decoder with the keyframe
197 * (a), in the above figure, but we must instruct it only to output the decoded
198 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
199 * position set to the time of the segment: 0.
201 * We then proceed to push data from keyframe (a) to frame (b). The decoder
202 * decodes but clips all before media_time 1.
204 * After finishing a segment, we push out a new SEGMENT event with the clipping
205 * boundaries of the new data.
207 * This is a good usecase for the GStreamer accumulated SEGMENT events.
210 struct _QtDemuxSegment
212 /* global time and duration, all gst time */
214 GstClockTime stop_time;
215 GstClockTime duration;
216 /* media time of trak, all gst time */
217 GstClockTime media_start;
218 GstClockTime media_stop;
220 /* Media start time in trak timescale units */
221 guint32 trak_media_start;
224 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
226 /* Used with fragmented MP4 files (mfra atom) */
231 } QtDemuxRandomAccessEntry;
233 typedef struct _QtDemuxStreamStsdEntry
244 /* Numerator/denominator framerate */
247 GstVideoColorimetry colorimetry;
248 guint16 bits_per_sample;
249 guint16 color_table_id;
250 GstMemory *rgb8_palette;
251 guint interlace_mode;
257 guint samples_per_packet;
258 guint samples_per_frame;
259 guint bytes_per_packet;
260 guint bytes_per_sample;
261 guint bytes_per_frame;
264 /* if we use chunks or samples */
268 } QtDemuxStreamStsdEntry;
270 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
272 struct _QtDemuxStream
279 QtDemuxStreamStsdEntry *stsd_entries;
280 guint stsd_entries_length;
281 guint cur_stsd_entry_index;
286 gboolean new_caps; /* If TRUE, caps need to be generated (by
287 * calling _configure_stream()) This happens
288 * for MSS and fragmented streams */
290 gboolean new_stream; /* signals that a stream_start is required */
291 gboolean on_keyframe; /* if this stream last pushed buffer was a
292 * keyframe. This is important to identify
293 * where to stop pushing buffers after a
294 * segment stop time */
296 /* if the stream has a redirect URI in its headers, we store it here */
303 guint64 duration; /* in timescale units */
307 gchar lang_id[4]; /* ISO 639-2T language code */
311 QtDemuxSample *samples;
312 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
313 guint32 n_samples_moof; /* sample count in a moof */
314 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
315 * the framerate of fragmented format stream */
316 guint64 duration_last_moof;
318 guint32 offset_in_sample; /* Offset in the current sample, used for
319 * streams which have got exceedingly big
320 * sample size (such as 24s of raw audio).
321 * Only used when max_buffer_size is non-NULL */
322 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
323 * Currently only set for raw audio streams*/
331 gboolean use_allocator;
332 GstAllocator *allocator;
333 GstAllocationParams params;
337 /* when a discontinuity is pending */
340 /* list of buffers to push first */
343 /* if we need to clip this buffer. This is only needed for uncompressed
347 /* buffer needs some custom processing, e.g. subtitles */
348 gboolean need_process;
350 /* current position */
351 guint32 segment_index;
352 guint32 sample_index;
353 GstClockTime time_position; /* in gst time */
354 guint64 accumulated_base;
356 /* the Gst segment we are processing out, used for clipping */
359 /* quicktime segments */
361 QtDemuxSegment *segments;
362 gboolean dummy_segment;
367 GstTagList *stream_tags;
368 gboolean send_global_tags;
370 GstEvent *pending_event;
380 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
384 GstByteReader co_chunk;
386 guint32 current_chunk;
388 guint32 samples_per_chunk;
389 guint32 stsd_sample_description_id;
390 guint32 stco_sample_index;
392 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
395 guint32 n_samples_per_chunk;
396 guint32 stsc_chunk_index;
397 guint32 stsc_sample_index;
398 guint64 chunk_offset;
401 guint32 stts_samples;
402 guint32 n_sample_times;
403 guint32 stts_sample_index;
405 guint32 stts_duration;
407 gboolean stss_present;
408 guint32 n_sample_syncs;
411 gboolean stps_present;
412 guint32 n_sample_partial_syncs;
414 QtDemuxRandomAccessEntry *ra_entries;
417 const QtDemuxRandomAccessEntry *pending_seek;
420 gboolean ctts_present;
421 guint32 n_composition_times;
423 guint32 ctts_sample_index;
431 gboolean parsed_trex;
432 guint32 def_sample_description_index; /* index is 1-based */
433 guint32 def_sample_duration;
434 guint32 def_sample_size;
435 guint32 def_sample_flags;
439 /* stereoscopic video streams */
440 GstVideoMultiviewMode multiview_mode;
441 GstVideoMultiviewFlags multiview_flags;
443 /* protected streams */
445 guint32 protection_scheme_type;
446 guint32 protection_scheme_version;
447 gpointer protection_scheme_info; /* specific to the protection scheme */
448 GQueue protection_scheme_event_queue;
451 /* Contains properties and cryptographic info for a set of samples from a
452 * track protected using Common Encryption (cenc) */
453 struct _QtDemuxCencSampleSetInfo
455 GstStructure *default_properties;
457 /* @crypto_info holds one GstStructure per sample */
458 GPtrArray *crypto_info;
462 qt_demux_state_string (enum QtDemuxState state)
465 case QTDEMUX_STATE_INITIAL:
467 case QTDEMUX_STATE_HEADER:
469 case QTDEMUX_STATE_MOVIE:
471 case QTDEMUX_STATE_BUFFER_MDAT:
472 return "<BUFFER_MDAT>";
478 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
479 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
480 guint32 fourcc, GstByteReader * parser);
481 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
482 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
483 guint32 fourcc, GstByteReader * parser);
485 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
487 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
489 static GstStaticPadTemplate gst_qtdemux_sink_template =
490 GST_STATIC_PAD_TEMPLATE ("sink",
493 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
497 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
498 GST_STATIC_PAD_TEMPLATE ("video_%u",
501 GST_STATIC_CAPS_ANY);
503 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
504 GST_STATIC_PAD_TEMPLATE ("audio_%u",
507 GST_STATIC_CAPS_ANY);
509 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
510 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
513 GST_STATIC_CAPS_ANY);
515 #define gst_qtdemux_parent_class parent_class
516 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
518 static void gst_qtdemux_dispose (GObject * object);
521 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
522 GstClockTime media_time);
524 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
525 QtDemuxStream * str, gint64 media_offset);
528 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
529 static GstIndex *gst_qtdemux_get_index (GstElement * element);
531 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
532 GstStateChange transition);
533 static void gst_qtdemux_set_context (GstElement * element,
534 GstContext * context);
535 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
536 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
537 GstObject * parent, GstPadMode mode, gboolean active);
539 static void gst_qtdemux_loop (GstPad * pad);
540 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
542 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
544 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
545 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
546 QtDemuxStream * stream);
547 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
548 QtDemuxStream * stream);
549 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
552 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
553 const guint8 * buffer, guint length);
554 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
555 const guint8 * buffer, guint length);
556 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
557 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
560 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
561 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
563 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
564 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
565 const guint8 * stsd_entry_data, gchar ** codec_name);
566 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
567 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
568 const guint8 * data, int len, gchar ** codec_name);
569 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
570 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
571 gchar ** codec_name);
572 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
573 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
574 const guint8 * stsd_entry_data, gchar ** codec_name);
576 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
577 QtDemuxStream * stream, guint32 n);
578 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
579 static void gst_qtdemux_stream_free (QtDemuxStream * stream);
580 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
581 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux,
582 QtDemuxStream * stream);
583 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
584 static void qtdemux_do_allocation (QtDemuxStream * stream,
585 GstQTDemux * qtdemux);
586 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
587 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
588 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
589 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
590 GstClockTime * _start, GstClockTime * _stop);
591 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
592 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
594 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
595 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
597 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
599 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
600 QtDemuxStream * stream, guint sample_index);
601 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
603 static void qtdemux_gst_structure_free (GstStructure * gststructure);
604 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
607 gst_qtdemux_class_init (GstQTDemuxClass * klass)
609 GObjectClass *gobject_class;
610 GstElementClass *gstelement_class;
612 gobject_class = (GObjectClass *) klass;
613 gstelement_class = (GstElementClass *) klass;
615 parent_class = g_type_class_peek_parent (klass);
617 gobject_class->dispose = gst_qtdemux_dispose;
619 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
621 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
622 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
624 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
626 gst_tag_register_musicbrainz_tags ();
628 gst_element_class_add_static_pad_template (gstelement_class,
629 &gst_qtdemux_sink_template);
630 gst_element_class_add_static_pad_template (gstelement_class,
631 &gst_qtdemux_videosrc_template);
632 gst_element_class_add_static_pad_template (gstelement_class,
633 &gst_qtdemux_audiosrc_template);
634 gst_element_class_add_static_pad_template (gstelement_class,
635 &gst_qtdemux_subsrc_template);
636 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
638 "Demultiplex a QuickTime file into audio and video streams",
639 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
641 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
646 gst_qtdemux_init (GstQTDemux * qtdemux)
649 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
650 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
651 gst_pad_set_activatemode_function (qtdemux->sinkpad,
652 qtdemux_sink_activate_mode);
653 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
654 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
655 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
657 qtdemux->adapter = gst_adapter_new ();
658 g_queue_init (&qtdemux->protection_event_queue);
659 qtdemux->flowcombiner = gst_flow_combiner_new ();
660 g_mutex_init (&qtdemux->expose_lock);
662 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
664 gst_qtdemux_reset (qtdemux, TRUE);
668 gst_qtdemux_dispose (GObject * object)
670 GstQTDemux *qtdemux = GST_QTDEMUX (object);
672 if (qtdemux->adapter) {
673 g_object_unref (G_OBJECT (qtdemux->adapter));
674 qtdemux->adapter = NULL;
676 gst_tag_list_unref (qtdemux->tag_list);
677 gst_flow_combiner_free (qtdemux->flowcombiner);
678 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
680 g_queue_clear (&qtdemux->protection_event_queue);
682 g_free (qtdemux->cenc_aux_info_sizes);
683 qtdemux->cenc_aux_info_sizes = NULL;
684 g_mutex_clear (&qtdemux->expose_lock);
686 G_OBJECT_CLASS (parent_class)->dispose (object);
690 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
692 if (qtdemux->posted_redirect) {
693 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
694 (_("This file contains no playable streams.")),
695 ("no known streams found, a redirect message has been posted"));
697 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
698 (_("This file contains no playable streams.")),
699 ("no known streams found"));
704 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
706 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
707 mem, size, 0, size, mem, free_func);
711 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
718 if (G_UNLIKELY (size == 0)) {
720 GstBuffer *tmp = NULL;
722 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
723 if (ret != GST_FLOW_OK)
726 gst_buffer_map (tmp, &map, GST_MAP_READ);
727 size = QT_UINT32 (map.data);
728 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
730 gst_buffer_unmap (tmp, &map);
731 gst_buffer_unref (tmp);
734 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
735 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
736 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
737 /* we're pulling header but already got most interesting bits,
738 * so never mind the rest (e.g. tags) (that much) */
739 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
743 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
744 (_("This file is invalid and cannot be played.")),
745 ("atom has bogus size %" G_GUINT64_FORMAT, size));
746 return GST_FLOW_ERROR;
750 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
752 if (G_UNLIKELY (flow != GST_FLOW_OK))
755 bsize = gst_buffer_get_size (*buf);
756 /* Catch short reads - we don't want any partial atoms */
757 if (G_UNLIKELY (bsize < size)) {
758 GST_WARNING_OBJECT (qtdemux,
759 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
760 gst_buffer_unref (*buf);
770 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
771 GstFormat src_format, gint64 src_value, GstFormat dest_format,
775 QtDemuxStream *stream = gst_pad_get_element_private (pad);
778 if (stream->subtype != FOURCC_vide) {
783 switch (src_format) {
784 case GST_FORMAT_TIME:
785 switch (dest_format) {
786 case GST_FORMAT_BYTES:{
787 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
793 *dest_value = stream->samples[index].offset;
795 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
796 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
797 GST_TIME_ARGS (src_value), *dest_value);
805 case GST_FORMAT_BYTES:
806 switch (dest_format) {
807 case GST_FORMAT_TIME:{
809 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
818 QTSTREAMTIME_TO_GSTTIME (stream,
819 stream->samples[index].timestamp);
820 GST_DEBUG_OBJECT (qtdemux,
821 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
822 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
841 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
843 gboolean res = FALSE;
845 *duration = GST_CLOCK_TIME_NONE;
847 if (qtdemux->duration != 0 &&
848 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
849 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
852 *duration = GST_CLOCK_TIME_NONE;
859 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
862 gboolean res = FALSE;
863 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
865 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
867 switch (GST_QUERY_TYPE (query)) {
868 case GST_QUERY_POSITION:{
871 gst_query_parse_position (query, &fmt, NULL);
872 if (fmt == GST_FORMAT_TIME
873 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
874 gst_query_set_position (query, GST_FORMAT_TIME,
875 qtdemux->segment.position);
880 case GST_QUERY_DURATION:{
883 gst_query_parse_duration (query, &fmt, NULL);
884 if (fmt == GST_FORMAT_TIME) {
885 /* First try to query upstream */
886 res = gst_pad_query_default (pad, parent, query);
888 GstClockTime duration;
889 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
890 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
897 case GST_QUERY_CONVERT:{
898 GstFormat src_fmt, dest_fmt;
899 gint64 src_value, dest_value = 0;
901 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
903 res = gst_qtdemux_src_convert (qtdemux, pad,
904 src_fmt, src_value, dest_fmt, &dest_value);
906 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
910 case GST_QUERY_FORMATS:
911 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
914 case GST_QUERY_SEEKING:{
918 /* try upstream first */
919 res = gst_pad_query_default (pad, parent, query);
922 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
923 if (fmt == GST_FORMAT_TIME) {
924 GstClockTime duration;
926 gst_qtdemux_get_duration (qtdemux, &duration);
928 if (!qtdemux->pullbased) {
931 /* we might be able with help from upstream */
933 q = gst_query_new_seeking (GST_FORMAT_BYTES);
934 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
935 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
936 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
940 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
946 case GST_QUERY_SEGMENT:
951 format = qtdemux->segment.format;
954 gst_segment_to_stream_time (&qtdemux->segment, format,
955 qtdemux->segment.start);
956 if ((stop = qtdemux->segment.stop) == -1)
957 stop = qtdemux->segment.duration;
959 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
961 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
966 res = gst_pad_query_default (pad, parent, query);
974 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
976 if (G_LIKELY (stream->pad)) {
977 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
978 GST_DEBUG_PAD_NAME (stream->pad));
980 if (!gst_tag_list_is_empty (stream->stream_tags)) {
981 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
982 stream->stream_tags);
983 gst_pad_push_event (stream->pad,
984 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
987 if (G_UNLIKELY (stream->send_global_tags)) {
988 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
990 gst_pad_push_event (stream->pad,
991 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
992 stream->send_global_tags = FALSE;
997 /* push event on all source pads; takes ownership of the event */
999 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1001 gboolean has_valid_stream = FALSE;
1002 GstEventType etype = GST_EVENT_TYPE (event);
1005 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1006 GST_EVENT_TYPE_NAME (event));
1008 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1010 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1011 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1013 if ((pad = stream->pad)) {
1014 has_valid_stream = TRUE;
1016 if (etype == GST_EVENT_EOS) {
1017 /* let's not send twice */
1018 if (stream->sent_eos)
1020 stream->sent_eos = TRUE;
1023 gst_pad_push_event (pad, gst_event_ref (event));
1027 gst_event_unref (event);
1029 /* if it is EOS and there are no pads, post an error */
1030 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1031 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1041 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1043 if ((gint64) s1->timestamp > *media_time)
1045 if ((gint64) s1->timestamp == *media_time)
1051 /* find the index of the sample that includes the data for @media_time using a
1052 * binary search. Only to be called in optimized cases of linear search below.
1054 * Returns the index of the sample with the corresponding *DTS*.
1057 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1060 QtDemuxSample *result;
1063 /* convert media_time to mov format */
1065 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1067 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1068 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1069 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1071 if (G_LIKELY (result))
1072 index = result - str->samples;
1081 /* find the index of the sample that includes the data for @media_offset using a
1084 * Returns the index of the sample.
1087 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1088 QtDemuxStream * str, gint64 media_offset)
1090 QtDemuxSample *result = str->samples;
1093 if (result == NULL || str->n_samples == 0)
1096 if (media_offset == result->offset)
1100 while (index < str->n_samples - 1) {
1101 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1104 if (media_offset < result->offset)
1115 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1120 /* find the index of the sample that includes the data for @media_time using a
1121 * linear search, and keeping in mind that not all samples may have been parsed
1122 * yet. If possible, it will delegate to binary search.
1124 * Returns the index of the sample.
1127 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1128 GstClockTime media_time)
1132 QtDemuxSample *sample;
1134 /* convert media_time to mov format */
1136 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1138 sample = str->samples;
1139 if (mov_time == sample->timestamp + sample->pts_offset)
1142 /* use faster search if requested time in already parsed range */
1143 sample = str->samples + str->stbl_index;
1144 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1145 index = gst_qtdemux_find_index (qtdemux, str, media_time);
1146 sample = str->samples + index;
1148 while (index < str->n_samples - 1) {
1149 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1152 sample = str->samples + index + 1;
1153 if (mov_time < sample->timestamp) {
1154 sample = str->samples + index;
1162 /* sample->timestamp is now <= media_time, need to find the corresponding
1163 * PTS now by looking backwards */
1164 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1166 sample = str->samples + index;
1174 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1179 /* find the index of the keyframe needed to decode the sample at @index
1180 * of stream @str, or of a subsequent keyframe (depending on @next)
1182 * Returns the index of the keyframe.
1185 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1186 guint32 index, gboolean next)
1188 guint32 new_index = index;
1190 if (index >= str->n_samples) {
1191 new_index = str->n_samples;
1195 /* all keyframes, return index */
1196 if (str->all_keyframe) {
1201 /* else search until we have a keyframe */
1202 while (new_index < str->n_samples) {
1203 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1206 if (str->samples[new_index].keyframe)
1218 if (new_index == str->n_samples) {
1219 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1224 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1225 "gave %u", next ? "after" : "before", index, new_index);
1232 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1237 /* find the segment for @time_position for @stream
1239 * Returns the index of the segment containing @time_position.
1240 * Returns the last segment and sets the @eos variable to TRUE
1241 * if the time is beyond the end. @eos may be NULL
1244 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1245 GstClockTime time_position)
1250 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1251 GST_TIME_ARGS (time_position));
1254 for (i = 0; i < stream->n_segments; i++) {
1255 QtDemuxSegment *segment = &stream->segments[i];
1257 GST_LOG_OBJECT (stream->pad,
1258 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1259 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1261 /* For the last segment we include stop_time in the last segment */
1262 if (i < stream->n_segments - 1) {
1263 if (segment->time <= time_position && time_position < segment->stop_time) {
1264 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1269 /* Last segment always matches */
1277 /* move the stream @str to the sample position @index.
1279 * Updates @str->sample_index and marks discontinuity if needed.
1282 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1285 /* no change needed */
1286 if (index == str->sample_index)
1289 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1292 /* position changed, we have a discont */
1293 str->sample_index = index;
1294 str->offset_in_sample = 0;
1295 /* Each time we move in the stream we store the position where we are
1297 str->from_sample = index;
1298 str->discont = TRUE;
1302 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1303 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1306 gint64 min_byte_offset = -1;
1309 min_offset = desired_time;
1311 /* for each stream, find the index of the sample in the segment
1312 * and move back to the previous keyframe. */
1313 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1315 guint32 index, kindex;
1317 GstClockTime media_start;
1318 GstClockTime media_time;
1319 GstClockTime seg_time;
1320 QtDemuxSegment *seg;
1321 gboolean empty_segment = FALSE;
1323 str = QTDEMUX_STREAM (iter->data);
1325 if (CUR_STREAM (str)->sparse && !use_sparse)
1328 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1329 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1331 /* get segment and time in the segment */
1332 seg = &str->segments[seg_idx];
1333 seg_time = (desired_time - seg->time) * seg->rate;
1335 while (QTSEGMENT_IS_EMPTY (seg)) {
1337 empty_segment = TRUE;
1338 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1341 if (seg_idx == str->n_segments)
1343 seg = &str->segments[seg_idx];
1346 if (seg_idx == str->n_segments) {
1347 /* FIXME track shouldn't have the last segment as empty, but if it
1348 * happens we better handle it */
1352 /* get the media time in the segment */
1353 media_start = seg->media_start + seg_time;
1355 /* get the index of the sample with media time */
1356 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1357 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1358 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1359 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1362 /* shift to next frame if we are looking for next keyframe */
1363 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1364 && index < str->stbl_index)
1367 if (!empty_segment) {
1368 /* find previous keyframe */
1369 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1371 /* we will settle for one before if none found after */
1372 if (next && kindex == -1)
1373 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1375 /* if the keyframe is at a different position, we need to update the
1376 * requested seek time */
1377 if (index != kindex) {
1380 /* get timestamp of keyframe */
1381 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1382 GST_DEBUG_OBJECT (qtdemux,
1383 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1384 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1385 str->samples[kindex].offset);
1387 /* keyframes in the segment get a chance to change the
1388 * desired_offset. keyframes out of the segment are
1390 if (media_time >= seg->media_start) {
1391 GstClockTime seg_time;
1393 /* this keyframe is inside the segment, convert back to
1395 seg_time = (media_time - seg->media_start) + seg->time;
1396 if ((!next && (seg_time < min_offset)) ||
1397 (next && (seg_time > min_offset)))
1398 min_offset = seg_time;
1403 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1404 min_byte_offset = str->samples[index].offset;
1408 *key_time = min_offset;
1410 *key_offset = min_byte_offset;
1414 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1415 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1419 g_return_val_if_fail (format != NULL, FALSE);
1420 g_return_val_if_fail (cur != NULL, FALSE);
1421 g_return_val_if_fail (stop != NULL, FALSE);
1423 if (*format == GST_FORMAT_TIME)
1427 if (cur_type != GST_SEEK_TYPE_NONE)
1428 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1429 if (res && stop_type != GST_SEEK_TYPE_NONE)
1430 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1433 *format = GST_FORMAT_TIME;
1438 /* perform seek in push based mode:
1439 find BYTE position to move to based on time and delegate to upstream
1442 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1447 GstSeekType cur_type, stop_type;
1448 gint64 cur, stop, key_cur;
1451 gint64 original_stop;
1454 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1456 gst_event_parse_seek (event, &rate, &format, &flags,
1457 &cur_type, &cur, &stop_type, &stop);
1458 seqnum = gst_event_get_seqnum (event);
1460 /* only forward streaming and seeking is possible */
1462 goto unsupported_seek;
1464 /* convert to TIME if needed and possible */
1465 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1469 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1470 * the original stop position to use when upstream pushes the new segment
1472 original_stop = stop;
1475 /* find reasonable corresponding BYTE position,
1476 * also try to mind about keyframes, since we can not go back a bit for them
1478 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1479 * mostly just work, but let's not yet boldly go there ... */
1480 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1485 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1486 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1489 GST_OBJECT_LOCK (qtdemux);
1490 qtdemux->seek_offset = byte_cur;
1491 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1492 qtdemux->push_seek_start = cur;
1494 qtdemux->push_seek_start = key_cur;
1497 if (stop_type == GST_SEEK_TYPE_NONE) {
1498 qtdemux->push_seek_stop = qtdemux->segment.stop;
1500 qtdemux->push_seek_stop = original_stop;
1502 GST_OBJECT_UNLOCK (qtdemux);
1504 qtdemux->segment_seqnum = seqnum;
1505 /* BYTE seek event */
1506 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1508 gst_event_set_seqnum (event, seqnum);
1509 res = gst_pad_push_event (qtdemux->sinkpad, event);
1516 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1522 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1527 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1532 /* perform the seek.
1534 * We set all segment_indexes in the streams to unknown and
1535 * adjust the time_position to the desired position. this is enough
1536 * to trigger a segment switch in the streaming thread to start
1537 * streaming from the desired position.
1539 * Keyframe seeking is a little more complicated when dealing with
1540 * segments. Ideally we want to move to the previous keyframe in
1541 * the segment but there might not be a keyframe in the segment. In
1542 * fact, none of the segments could contain a keyframe. We take a
1543 * practical approach: seek to the previous keyframe in the segment,
1544 * if there is none, seek to the beginning of the segment.
1546 * Called with STREAM_LOCK
1549 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1550 guint32 seqnum, GstSeekFlags flags)
1552 gint64 desired_offset;
1555 desired_offset = segment->position;
1557 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1558 GST_TIME_ARGS (desired_offset));
1560 /* may not have enough fragmented info to do this adjustment,
1561 * and we can't scan (and probably should not) at this time with
1562 * possibly flushing upstream */
1563 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1565 gboolean next, before, after;
1567 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1568 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1569 next = after && !before;
1570 if (segment->rate < 0)
1573 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1575 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1576 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1577 desired_offset = min_offset;
1580 /* and set all streams to the final position */
1581 gst_flow_combiner_reset (qtdemux->flowcombiner);
1582 qtdemux->segment_seqnum = seqnum;
1583 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1584 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1586 stream->time_position = desired_offset;
1587 stream->accumulated_base = 0;
1588 stream->sample_index = -1;
1589 stream->offset_in_sample = 0;
1590 stream->segment_index = -1;
1591 stream->sent_eos = FALSE;
1593 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1594 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1596 segment->position = desired_offset;
1597 segment->time = desired_offset;
1598 if (segment->rate >= 0) {
1599 segment->start = desired_offset;
1601 /* we stop at the end */
1602 if (segment->stop == -1)
1603 segment->stop = segment->duration;
1605 segment->stop = desired_offset;
1608 if (qtdemux->fragmented)
1609 qtdemux->fragmented_seek_pending = TRUE;
1614 /* do a seek in pull based mode */
1616 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1621 GstSeekType cur_type, stop_type;
1625 GstSegment seeksegment;
1626 guint32 seqnum = GST_SEQNUM_INVALID;
1627 GstEvent *flush_event;
1631 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1633 gst_event_parse_seek (event, &rate, &format, &flags,
1634 &cur_type, &cur, &stop_type, &stop);
1635 seqnum = gst_event_get_seqnum (event);
1637 /* we have to have a format as the segment format. Try to convert
1639 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1643 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1645 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1649 flush = flags & GST_SEEK_FLAG_FLUSH;
1651 /* stop streaming, either by flushing or by pausing the task */
1653 flush_event = gst_event_new_flush_start ();
1654 if (seqnum != GST_SEQNUM_INVALID)
1655 gst_event_set_seqnum (flush_event, seqnum);
1656 /* unlock upstream pull_range */
1657 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1658 /* make sure out loop function exits */
1659 gst_qtdemux_push_event (qtdemux, flush_event);
1661 /* non flushing seek, pause the task */
1662 gst_pad_pause_task (qtdemux->sinkpad);
1665 /* wait for streaming to finish */
1666 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1668 /* copy segment, we need this because we still need the old
1669 * segment when we close the current segment. */
1670 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1673 /* configure the segment with the seek variables */
1674 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1675 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1676 cur_type, cur, stop_type, stop, &update)) {
1678 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1680 /* now do the seek */
1681 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1684 /* now do the seek */
1685 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1688 /* prepare for streaming again */
1690 flush_event = gst_event_new_flush_stop (TRUE);
1691 if (seqnum != GST_SEQNUM_INVALID)
1692 gst_event_set_seqnum (flush_event, seqnum);
1694 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1695 gst_qtdemux_push_event (qtdemux, flush_event);
1698 /* commit the new segment */
1699 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1701 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1702 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1703 qtdemux->segment.format, qtdemux->segment.position);
1704 if (seqnum != GST_SEQNUM_INVALID)
1705 gst_message_set_seqnum (msg, seqnum);
1706 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1709 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1710 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1711 qtdemux->sinkpad, NULL);
1713 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1720 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1726 qtdemux_ensure_index (GstQTDemux * qtdemux)
1730 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1732 /* Build complete index */
1733 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1734 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1736 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1737 GST_LOG_OBJECT (qtdemux,
1738 "Building complete index of track-id %u for seeking failed!",
1748 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1751 gboolean res = TRUE;
1752 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1754 switch (GST_EVENT_TYPE (event)) {
1755 case GST_EVENT_SEEK:
1757 #ifndef GST_DISABLE_GST_DEBUG
1758 GstClockTime ts = gst_util_get_timestamp ();
1760 guint32 seqnum = gst_event_get_seqnum (event);
1762 qtdemux->received_seek = TRUE;
1764 if (seqnum == qtdemux->segment_seqnum) {
1765 GST_LOG_OBJECT (pad,
1766 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1767 gst_event_unref (event);
1771 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1772 /* seek should be handled by upstream, we might need to re-download fragments */
1773 GST_DEBUG_OBJECT (qtdemux,
1774 "let upstream handle seek for fragmented playback");
1778 /* Build complete index for seeking;
1779 * if not a fragmented file at least */
1780 if (!qtdemux->fragmented)
1781 if (!qtdemux_ensure_index (qtdemux))
1783 #ifndef GST_DISABLE_GST_DEBUG
1784 ts = gst_util_get_timestamp () - ts;
1785 GST_INFO_OBJECT (qtdemux,
1786 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1789 if (qtdemux->pullbased) {
1790 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1791 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1792 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1794 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1795 && !qtdemux->fragmented) {
1796 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1798 GST_DEBUG_OBJECT (qtdemux,
1799 "ignoring seek in push mode in current state");
1802 gst_event_unref (event);
1806 res = gst_pad_event_default (pad, parent, event);
1816 GST_ERROR_OBJECT (qtdemux, "Index failed");
1817 gst_event_unref (event);
1823 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1825 * If @fw is false, the coding order is explored backwards.
1827 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1828 * sample is found for that track.
1830 * The stream and sample index of the sample with the minimum offset in the direction explored
1831 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1833 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1834 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1835 * @_stream and @_index. */
1837 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1838 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1841 gint64 time, min_time;
1842 QtDemuxStream *stream;
1849 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1852 gboolean set_sample;
1854 str = QTDEMUX_STREAM (iter->data);
1861 i = str->n_samples - 1;
1865 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1866 if (str->samples[i].size == 0)
1869 if (fw && (str->samples[i].offset < byte_pos))
1872 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1875 /* move stream to first available sample */
1877 gst_qtdemux_move_stream (qtdemux, str, i);
1881 /* avoid index from sparse streams since they might be far away */
1882 if (!CUR_STREAM (str)->sparse) {
1883 /* determine min/max time */
1884 time = QTSAMPLE_PTS (str, &str->samples[i]);
1885 if (min_time == -1 || (!fw && time > min_time) ||
1886 (fw && time < min_time)) {
1890 /* determine stream with leading sample, to get its position */
1892 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1893 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1901 /* no sample for this stream, mark eos */
1903 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1914 /* Copied from mpegtsbase code */
1915 /* FIXME: replace this function when we add new util function for stream-id creation */
1917 _get_upstream_id (GstQTDemux * demux)
1919 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1922 /* Try to create one from the upstream URI, else use a randome number */
1926 /* Try to generate one from the URI query and
1927 * if it fails take a random number instead */
1928 query = gst_query_new_uri ();
1929 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1930 gst_query_parse_uri (query, &uri);
1936 /* And then generate an SHA256 sum of the URI */
1937 cs = g_checksum_new (G_CHECKSUM_SHA256);
1938 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1940 upstream_id = g_strdup (g_checksum_get_string (cs));
1941 g_checksum_free (cs);
1943 /* Just get some random number if the URI query fails */
1944 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1945 "implementing a deterministic way of creating a stream-id");
1947 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1948 g_random_int (), g_random_int ());
1951 gst_query_unref (query);
1956 static QtDemuxStream *
1957 _create_stream (GstQTDemux * demux, guint32 track_id)
1959 QtDemuxStream *stream;
1962 stream = g_new0 (QtDemuxStream, 1);
1963 stream->demux = demux;
1964 stream->track_id = track_id;
1965 upstream_id = _get_upstream_id (demux);
1966 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1967 g_free (upstream_id);
1968 /* new streams always need a discont */
1969 stream->discont = TRUE;
1970 /* we enable clipping for raw audio/video streams */
1971 stream->need_clip = FALSE;
1972 stream->need_process = FALSE;
1973 stream->segment_index = -1;
1974 stream->time_position = 0;
1975 stream->sample_index = -1;
1976 stream->offset_in_sample = 0;
1977 stream->new_stream = TRUE;
1978 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1979 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1980 stream->protected = FALSE;
1981 stream->protection_scheme_type = 0;
1982 stream->protection_scheme_version = 0;
1983 stream->protection_scheme_info = NULL;
1984 stream->n_samples_moof = 0;
1985 stream->duration_moof = 0;
1986 stream->duration_last_moof = 0;
1987 stream->alignment = 1;
1988 stream->stream_tags = gst_tag_list_new_empty ();
1989 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1990 g_queue_init (&stream->protection_scheme_event_queue);
1995 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1997 GstStructure *structure;
1998 const gchar *variant;
1999 const GstCaps *mediacaps = NULL;
2001 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2003 structure = gst_caps_get_structure (caps, 0);
2004 variant = gst_structure_get_string (structure, "variant");
2006 if (variant && strcmp (variant, "mss-fragmented") == 0) {
2007 QtDemuxStream *stream;
2008 const GValue *value;
2010 demux->fragmented = TRUE;
2011 demux->mss_mode = TRUE;
2013 if (demux->n_streams > 1) {
2014 /* can't do this, we can only renegotiate for another mss format */
2018 value = gst_structure_get_value (structure, "media-caps");
2021 const GValue *timescale_v;
2023 /* TODO update when stream changes during playback */
2025 if (demux->n_streams == 0) {
2026 stream = _create_stream (demux, 1);
2027 demux->active_streams = g_list_append (demux->active_streams, stream);
2028 demux->n_streams = 1;
2029 /* mss has no stsd/stsd entry, use id 0 as default */
2030 stream->stsd_entries_length = 1;
2031 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2032 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2034 stream = QTDEMUX_FIRST_STREAM (demux);
2037 timescale_v = gst_structure_get_value (structure, "timescale");
2039 stream->timescale = g_value_get_uint64 (timescale_v);
2041 /* default mss timescale */
2042 stream->timescale = 10000000;
2044 demux->timescale = stream->timescale;
2046 mediacaps = gst_value_get_caps (value);
2047 if (!CUR_STREAM (stream)->caps
2048 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2049 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2051 stream->new_caps = TRUE;
2053 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2054 structure = gst_caps_get_structure (mediacaps, 0);
2055 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2056 stream->subtype = FOURCC_vide;
2058 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2059 gst_structure_get_int (structure, "height",
2060 &CUR_STREAM (stream)->height);
2061 gst_structure_get_fraction (structure, "framerate",
2062 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2063 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2065 stream->subtype = FOURCC_soun;
2066 gst_structure_get_int (structure, "channels",
2067 &CUR_STREAM (stream)->n_channels);
2068 gst_structure_get_int (structure, "rate", &rate);
2069 CUR_STREAM (stream)->rate = rate;
2072 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2074 demux->mss_mode = FALSE;
2081 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2085 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2086 gst_pad_stop_task (qtdemux->sinkpad);
2088 if (hard || qtdemux->upstream_format_is_time) {
2089 qtdemux->state = QTDEMUX_STATE_INITIAL;
2090 qtdemux->neededbytes = 16;
2091 qtdemux->todrop = 0;
2092 qtdemux->pullbased = FALSE;
2093 qtdemux->posted_redirect = FALSE;
2094 qtdemux->first_mdat = -1;
2095 qtdemux->header_size = 0;
2096 qtdemux->mdatoffset = -1;
2097 qtdemux->restoredata_offset = -1;
2098 if (qtdemux->mdatbuffer)
2099 gst_buffer_unref (qtdemux->mdatbuffer);
2100 if (qtdemux->restoredata_buffer)
2101 gst_buffer_unref (qtdemux->restoredata_buffer);
2102 qtdemux->mdatbuffer = NULL;
2103 qtdemux->restoredata_buffer = NULL;
2104 qtdemux->mdatleft = 0;
2105 qtdemux->mdatsize = 0;
2106 if (qtdemux->comp_brands)
2107 gst_buffer_unref (qtdemux->comp_brands);
2108 qtdemux->comp_brands = NULL;
2109 qtdemux->last_moov_offset = -1;
2110 if (qtdemux->moov_node_compressed) {
2111 g_node_destroy (qtdemux->moov_node_compressed);
2112 if (qtdemux->moov_node)
2113 g_free (qtdemux->moov_node->data);
2115 qtdemux->moov_node_compressed = NULL;
2116 if (qtdemux->moov_node)
2117 g_node_destroy (qtdemux->moov_node);
2118 qtdemux->moov_node = NULL;
2119 if (qtdemux->tag_list)
2120 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2121 qtdemux->tag_list = gst_tag_list_new_empty ();
2122 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2124 if (qtdemux->element_index)
2125 gst_object_unref (qtdemux->element_index);
2126 qtdemux->element_index = NULL;
2128 qtdemux->major_brand = 0;
2129 qtdemux->upstream_format_is_time = FALSE;
2130 qtdemux->upstream_seekable = FALSE;
2131 qtdemux->upstream_size = 0;
2133 qtdemux->fragment_start = -1;
2134 qtdemux->fragment_start_offset = -1;
2135 qtdemux->duration = 0;
2136 qtdemux->moof_offset = 0;
2137 qtdemux->chapters_track_id = 0;
2138 qtdemux->have_group_id = FALSE;
2139 qtdemux->group_id = G_MAXUINT;
2141 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2143 g_queue_clear (&qtdemux->protection_event_queue);
2145 qtdemux->received_seek = FALSE;
2146 qtdemux->first_moof_already_parsed = FALSE;
2148 qtdemux->offset = 0;
2149 gst_adapter_clear (qtdemux->adapter);
2150 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2151 qtdemux->need_segment = TRUE;
2154 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2155 g_list_free_full (qtdemux->active_streams,
2156 (GDestroyNotify) gst_qtdemux_stream_free);
2157 g_list_free_full (qtdemux->old_streams,
2158 (GDestroyNotify) gst_qtdemux_stream_free);
2159 qtdemux->active_streams = NULL;
2160 qtdemux->old_streams = NULL;
2161 qtdemux->n_streams = 0;
2162 qtdemux->n_video_streams = 0;
2163 qtdemux->n_audio_streams = 0;
2164 qtdemux->n_sub_streams = 0;
2165 qtdemux->exposed = FALSE;
2166 qtdemux->fragmented = FALSE;
2167 qtdemux->mss_mode = FALSE;
2168 gst_caps_replace (&qtdemux->media_caps, NULL);
2169 qtdemux->timescale = 0;
2170 qtdemux->got_moov = FALSE;
2171 qtdemux->cenc_aux_info_offset = 0;
2172 qtdemux->cenc_aux_info_sizes = NULL;
2173 qtdemux->cenc_aux_sample_count = 0;
2174 if (qtdemux->protection_system_ids) {
2175 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2176 qtdemux->protection_system_ids = NULL;
2178 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2179 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2180 GST_BIN_FLAG_STREAMS_AWARE);
2182 if (qtdemux->preferred_protection_system_id) {
2183 g_free (qtdemux->preferred_protection_system_id);
2184 qtdemux->preferred_protection_system_id = NULL;
2186 } else if (qtdemux->mss_mode) {
2187 gst_flow_combiner_reset (qtdemux->flowcombiner);
2188 g_list_foreach (qtdemux->active_streams,
2189 (GFunc) gst_qtdemux_stream_clear, NULL);
2191 gst_flow_combiner_reset (qtdemux->flowcombiner);
2192 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2193 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2194 stream->sent_eos = FALSE;
2195 stream->time_position = 0;
2196 stream->accumulated_base = 0;
2202 /* Maps the @segment to the qt edts internal segments and pushes
2203 * the correspnding segment event.
2205 * If it ends up being at a empty segment, a gap will be pushed and the next
2206 * edts segment will be activated in sequence.
2208 * To be used in push-mode only */
2210 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2215 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2216 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2218 stream->time_position = segment->start;
2220 /* in push mode we should be guaranteed that we will have empty segments
2221 * at the beginning and then one segment after, other scenarios are not
2222 * supported and are discarded when parsing the edts */
2223 for (i = 0; i < stream->n_segments; i++) {
2224 if (stream->segments[i].stop_time > segment->start) {
2225 /* push the empty segment and move to the next one */
2226 gst_qtdemux_activate_segment (qtdemux, stream, i,
2227 stream->time_position);
2228 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2229 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2230 stream->time_position);
2232 /* accumulate previous segments */
2233 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2234 stream->accumulated_base +=
2235 (stream->segment.stop -
2236 stream->segment.start) / ABS (stream->segment.rate);
2240 g_assert (i == stream->n_segments - 1);
2247 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2250 GstQTDemux *demux = GST_QTDEMUX (parent);
2251 gboolean res = TRUE;
2253 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2255 switch (GST_EVENT_TYPE (event)) {
2256 case GST_EVENT_SEGMENT:
2259 QtDemuxStream *stream;
2263 /* some debug output */
2264 gst_event_copy_segment (event, &segment);
2265 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2268 if (segment.format == GST_FORMAT_TIME) {
2269 demux->upstream_format_is_time = TRUE;
2270 demux->segment_seqnum = gst_event_get_seqnum (event);
2272 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2273 "not in time format");
2275 /* chain will send initial newsegment after pads have been added */
2276 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2277 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2282 /* check if this matches a time seek we received previously
2283 * FIXME for backwards compatibility reasons we use the
2284 * seek_offset here to compare. In the future we might want to
2285 * change this to use the seqnum as it uniquely should identify
2286 * the segment that corresponds to the seek. */
2287 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2288 ", received segment offset %" G_GINT64_FORMAT,
2289 demux->seek_offset, segment.start);
2290 if (segment.format == GST_FORMAT_BYTES
2291 && demux->seek_offset == segment.start) {
2292 GST_OBJECT_LOCK (demux);
2293 offset = segment.start;
2295 segment.format = GST_FORMAT_TIME;
2296 segment.start = demux->push_seek_start;
2297 segment.stop = demux->push_seek_stop;
2298 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2299 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2300 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2301 GST_OBJECT_UNLOCK (demux);
2304 /* we only expect a BYTE segment, e.g. following a seek */
2305 if (segment.format == GST_FORMAT_BYTES) {
2306 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2307 offset = segment.start;
2309 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2310 NULL, (gint64 *) & segment.start);
2311 if ((gint64) segment.start < 0)
2314 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2315 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2316 NULL, (gint64 *) & segment.stop);
2317 /* keyframe seeking should already arrange for start >= stop,
2318 * but make sure in other rare cases */
2319 segment.stop = MAX (segment.stop, segment.start);
2321 } else if (segment.format == GST_FORMAT_TIME) {
2322 /* push all data on the adapter before starting this
2324 gst_qtdemux_process_adapter (demux, TRUE);
2326 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2330 /* We shouldn't modify upstream driven TIME FORMAT segment */
2331 if (!demux->upstream_format_is_time) {
2332 /* accept upstream's notion of segment and distribute along */
2333 segment.format = GST_FORMAT_TIME;
2334 segment.position = segment.time = segment.start;
2335 segment.duration = demux->segment.duration;
2336 segment.base = gst_segment_to_running_time (&demux->segment,
2337 GST_FORMAT_TIME, demux->segment.position);
2340 gst_segment_copy_into (&segment, &demux->segment);
2341 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2343 /* map segment to internal qt segments and push on each stream */
2344 if (demux->n_streams) {
2345 demux->need_segment = TRUE;
2346 gst_qtdemux_check_send_pending_segment (demux);
2349 /* clear leftover in current segment, if any */
2350 gst_adapter_clear (demux->adapter);
2352 /* set up streaming thread */
2353 demux->offset = offset;
2354 if (demux->upstream_format_is_time) {
2355 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2356 "set values to restart reading from a new atom");
2357 demux->neededbytes = 16;
2360 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2363 demux->todrop = stream->samples[idx].offset - offset;
2364 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2366 /* set up for EOS */
2367 demux->neededbytes = -1;
2372 gst_event_unref (event);
2376 case GST_EVENT_FLUSH_START:
2378 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2379 gst_event_unref (event);
2382 QTDEMUX_EXPOSE_LOCK (demux);
2383 res = gst_pad_event_default (demux->sinkpad, parent, event);
2384 QTDEMUX_EXPOSE_UNLOCK (demux);
2387 case GST_EVENT_FLUSH_STOP:
2391 dur = demux->segment.duration;
2392 gst_qtdemux_reset (demux, FALSE);
2393 demux->segment.duration = dur;
2395 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2396 gst_event_unref (event);
2402 /* If we are in push mode, and get an EOS before we've seen any streams,
2403 * then error out - we have nowhere to send the EOS */
2404 if (!demux->pullbased) {
2406 gboolean has_valid_stream = FALSE;
2407 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
2408 if (QTDEMUX_STREAM (iter->data)->pad != NULL) {
2409 has_valid_stream = TRUE;
2413 if (!has_valid_stream)
2414 gst_qtdemux_post_no_playable_stream_error (demux);
2416 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2417 (guint) gst_adapter_available (demux->adapter));
2418 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2424 case GST_EVENT_CAPS:{
2425 GstCaps *caps = NULL;
2427 gst_event_parse_caps (event, &caps);
2428 gst_qtdemux_setcaps (demux, caps);
2430 gst_event_unref (event);
2433 case GST_EVENT_PROTECTION:
2435 const gchar *system_id = NULL;
2437 gst_event_parse_protection (event, &system_id, NULL, NULL);
2438 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2440 gst_qtdemux_append_protection_system_id (demux, system_id);
2441 /* save the event for later, for source pads that have not been created */
2442 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2443 /* send it to all pads that already exist */
2444 gst_qtdemux_push_event (demux, event);
2448 case GST_EVENT_STREAM_START:
2451 gst_event_unref (event);
2453 /* Drain all the buffers */
2454 gst_qtdemux_process_adapter (demux, TRUE);
2455 gst_qtdemux_reset (demux, FALSE);
2456 /* We expect new moov box after new stream-start event */
2457 demux->old_streams =
2458 g_list_concat (demux->old_streams, demux->active_streams);
2459 demux->active_streams = NULL;
2467 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2475 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2477 GstQTDemux *demux = GST_QTDEMUX (element);
2479 GST_OBJECT_LOCK (demux);
2480 if (demux->element_index)
2481 gst_object_unref (demux->element_index);
2483 demux->element_index = gst_object_ref (index);
2485 demux->element_index = NULL;
2487 GST_OBJECT_UNLOCK (demux);
2488 /* object lock might be taken again */
2490 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2491 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2492 demux->element_index, demux->index_id);
2496 gst_qtdemux_get_index (GstElement * element)
2498 GstIndex *result = NULL;
2499 GstQTDemux *demux = GST_QTDEMUX (element);
2501 GST_OBJECT_LOCK (demux);
2502 if (demux->element_index)
2503 result = gst_object_ref (demux->element_index);
2504 GST_OBJECT_UNLOCK (demux);
2506 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2513 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2515 g_free ((gpointer) stream->stco.data);
2516 stream->stco.data = NULL;
2517 g_free ((gpointer) stream->stsz.data);
2518 stream->stsz.data = NULL;
2519 g_free ((gpointer) stream->stsc.data);
2520 stream->stsc.data = NULL;
2521 g_free ((gpointer) stream->stts.data);
2522 stream->stts.data = NULL;
2523 g_free ((gpointer) stream->stss.data);
2524 stream->stss.data = NULL;
2525 g_free ((gpointer) stream->stps.data);
2526 stream->stps.data = NULL;
2527 g_free ((gpointer) stream->ctts.data);
2528 stream->ctts.data = NULL;
2532 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2534 g_free (stream->segments);
2535 stream->segments = NULL;
2536 stream->segment_index = -1;
2537 stream->accumulated_base = 0;
2541 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2543 g_free (stream->samples);
2544 stream->samples = NULL;
2545 gst_qtdemux_stbl_free (stream);
2548 g_free (stream->ra_entries);
2549 stream->ra_entries = NULL;
2550 stream->n_ra_entries = 0;
2552 stream->sample_index = -1;
2553 stream->stbl_index = -1;
2554 stream->n_samples = 0;
2555 stream->time_position = 0;
2557 stream->n_samples_moof = 0;
2558 stream->duration_moof = 0;
2559 stream->duration_last_moof = 0;
2563 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2566 if (stream->allocator)
2567 gst_object_unref (stream->allocator);
2568 while (stream->buffers) {
2569 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2570 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2572 for (i = 0; i < stream->stsd_entries_length; i++) {
2573 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2574 if (entry->rgb8_palette) {
2575 gst_memory_unref (entry->rgb8_palette);
2576 entry->rgb8_palette = NULL;
2578 entry->sparse = FALSE;
2581 if (stream->stream_tags)
2582 gst_tag_list_unref (stream->stream_tags);
2584 stream->stream_tags = gst_tag_list_new_empty ();
2585 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2586 g_free (stream->redirect_uri);
2587 stream->redirect_uri = NULL;
2588 stream->sent_eos = FALSE;
2589 stream->protected = FALSE;
2590 if (stream->protection_scheme_info) {
2591 if (stream->protection_scheme_type == FOURCC_cenc) {
2592 QtDemuxCencSampleSetInfo *info =
2593 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2594 if (info->default_properties)
2595 gst_structure_free (info->default_properties);
2596 if (info->crypto_info)
2597 g_ptr_array_free (info->crypto_info, TRUE);
2599 g_free (stream->protection_scheme_info);
2600 stream->protection_scheme_info = NULL;
2602 stream->protection_scheme_type = 0;
2603 stream->protection_scheme_version = 0;
2604 g_queue_foreach (&stream->protection_scheme_event_queue,
2605 (GFunc) gst_event_unref, NULL);
2606 g_queue_clear (&stream->protection_scheme_event_queue);
2607 gst_qtdemux_stream_flush_segments_data (stream);
2608 gst_qtdemux_stream_flush_samples_data (stream);
2612 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2615 gst_qtdemux_stream_clear (stream);
2616 for (i = 0; i < stream->stsd_entries_length; i++) {
2617 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2619 gst_caps_unref (entry->caps);
2623 g_free (stream->stsd_entries);
2624 stream->stsd_entries = NULL;
2625 stream->stsd_entries_length = 0;
2630 gst_qtdemux_stream_free (QtDemuxStream * stream)
2632 gst_qtdemux_stream_reset (stream);
2633 gst_tag_list_unref (stream->stream_tags);
2635 GstQTDemux *demux = stream->demux;
2636 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2637 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2639 g_free (stream->stream_id);
2644 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
2646 qtdemux->active_streams = g_list_remove (qtdemux->active_streams, stream);
2647 gst_qtdemux_stream_free (stream);
2648 qtdemux->n_streams--;
2651 static GstStateChangeReturn
2652 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2654 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2655 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2657 switch (transition) {
2658 case GST_STATE_CHANGE_READY_TO_PAUSED:
2659 gst_qtdemux_reset (qtdemux, TRUE);
2665 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2667 switch (transition) {
2668 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2669 gst_qtdemux_reset (qtdemux, TRUE);
2680 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2682 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2684 g_return_if_fail (GST_IS_CONTEXT (context));
2686 if (gst_context_has_context_type (context,
2687 "drm-preferred-decryption-system-id")) {
2688 const GstStructure *s;
2690 s = gst_context_get_structure (context);
2691 g_free (qtdemux->preferred_protection_system_id);
2692 qtdemux->preferred_protection_system_id =
2693 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2694 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2695 qtdemux->preferred_protection_system_id);
2698 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2702 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2704 /* counts as header data */
2705 qtdemux->header_size += length;
2707 /* only consider at least a sufficiently complete ftyp atom */
2711 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2712 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2713 GST_FOURCC_ARGS (qtdemux->major_brand));
2714 if (qtdemux->comp_brands)
2715 gst_buffer_unref (qtdemux->comp_brands);
2716 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2717 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2722 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2723 GstTagList * xmptaglist)
2725 /* Strip out bogus fields */
2727 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2728 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2729 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2731 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2734 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2736 /* prioritize native tags using _KEEP mode */
2737 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2738 gst_tag_list_unref (xmptaglist);
2743 qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
2744 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
2747 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2748 gst_buffer_fill (kid_buf, 0, kid, 16);
2749 if (info->default_properties)
2750 gst_structure_free (info->default_properties);
2751 info->default_properties =
2752 gst_structure_new ("application/x-cenc",
2753 "iv_size", G_TYPE_UINT, iv_size,
2754 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2755 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2756 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2757 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2758 gst_buffer_unref (kid_buf);
2762 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2763 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2765 guint32 algorithm_id = 0;
2767 gboolean is_encrypted = TRUE;
2770 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2771 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2776 if (algorithm_id == 0) {
2777 is_encrypted = FALSE;
2778 } else if (algorithm_id == 1) {
2779 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2780 } else if (algorithm_id == 2) {
2781 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2784 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2787 if (!gst_byte_reader_get_data (br, 16, &kid))
2790 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
2791 is_encrypted, iv_size, kid);
2792 gst_structure_set (info->default_properties, "piff_algorithm_id",
2793 G_TYPE_UINT, algorithm_id, NULL);
2799 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2807 QtDemuxStream *stream;
2808 GstStructure *structure;
2809 QtDemuxCencSampleSetInfo *ss_info = NULL;
2810 const gchar *system_id;
2811 gboolean uses_sub_sample_encryption = FALSE;
2812 guint32 sample_count;
2814 stream = QTDEMUX_FIRST_STREAM (qtdemux);
2818 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2819 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2820 GST_WARNING_OBJECT (qtdemux,
2821 "Attempting PIFF box parsing on an unencrypted stream.");
2825 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2826 G_TYPE_STRING, &system_id, NULL);
2827 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2829 stream->protected = TRUE;
2830 stream->protection_scheme_type = FOURCC_cenc;
2832 if (!stream->protection_scheme_info)
2833 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2835 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2836 if (!ss_info->default_properties) {
2837 ss_info->default_properties =
2838 gst_structure_new ("application/x-cenc",
2839 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2844 if (ss_info->crypto_info) {
2845 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2846 g_ptr_array_free (ss_info->crypto_info, TRUE);
2847 ss_info->crypto_info = NULL;
2851 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2853 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2854 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2858 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2859 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2863 if ((flags & 0x000001)) {
2864 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2867 } else if ((flags & 0x000002)) {
2868 uses_sub_sample_encryption = TRUE;
2871 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2873 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2877 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2878 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2882 ss_info->crypto_info =
2883 g_ptr_array_new_full (sample_count,
2884 (GDestroyNotify) qtdemux_gst_structure_free);
2886 for (i = 0; i < sample_count; ++i) {
2887 GstStructure *properties;
2891 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2892 if (properties == NULL) {
2893 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2894 qtdemux->cenc_aux_sample_count = i;
2898 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2899 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2900 gst_structure_free (properties);
2901 qtdemux->cenc_aux_sample_count = i;
2904 buf = gst_buffer_new_wrapped (data, iv_size);
2905 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2906 gst_buffer_unref (buf);
2908 if (uses_sub_sample_encryption) {
2909 guint16 n_subsamples;
2910 const GValue *kid_buf_value;
2912 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2913 || n_subsamples == 0) {
2914 GST_ERROR_OBJECT (qtdemux,
2915 "failed to get subsample count for sample %u", i);
2916 gst_structure_free (properties);
2917 qtdemux->cenc_aux_sample_count = i;
2920 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2921 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2922 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2924 gst_structure_free (properties);
2925 qtdemux->cenc_aux_sample_count = i;
2928 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2931 gst_structure_get_value (ss_info->default_properties, "kid");
2933 gst_structure_set (properties,
2934 "subsample_count", G_TYPE_UINT, n_subsamples,
2935 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2936 gst_structure_set_value (properties, "kid", kid_buf_value);
2937 gst_buffer_unref (buf);
2939 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2942 g_ptr_array_add (ss_info->crypto_info, properties);
2945 qtdemux->cenc_aux_sample_count = sample_count;
2949 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2951 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2952 0x97, 0xA9, 0x42, 0xE8,
2953 0x9C, 0x71, 0x99, 0x94,
2954 0x91, 0xE3, 0xAF, 0xAC
2956 static const guint8 playready_uuid[] = {
2957 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2958 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2961 static const guint8 piff_sample_encryption_uuid[] = {
2962 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2963 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2968 /* counts as header data */
2969 qtdemux->header_size += length;
2971 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2973 if (length <= offset + 16) {
2974 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2978 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2980 GstTagList *taglist;
2982 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2983 length - offset - 16, NULL);
2984 taglist = gst_tag_list_from_xmp_buffer (buf);
2985 gst_buffer_unref (buf);
2987 /* make sure we have a usable taglist */
2988 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2990 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2992 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2994 const gunichar2 *s_utf16;
2997 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2998 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2999 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3000 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3004 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3005 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3007 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3008 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3010 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3011 GST_READ_UINT32_LE (buffer + offset),
3012 GST_READ_UINT32_LE (buffer + offset + 4),
3013 GST_READ_UINT32_LE (buffer + offset + 8),
3014 GST_READ_UINT32_LE (buffer + offset + 12));
3019 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3021 GstSidxParser sidx_parser;
3022 GstIsoffParserResult res;
3025 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3028 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3030 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3031 if (res == GST_ISOFF_QT_PARSER_DONE) {
3032 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3034 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3037 /* caller verifies at least 8 bytes in buf */
3039 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3040 guint64 * plength, guint32 * pfourcc)
3045 length = QT_UINT32 (data);
3046 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3047 fourcc = QT_FOURCC (data + 4);
3048 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3051 length = G_MAXUINT64;
3052 } else if (length == 1 && size >= 16) {
3053 /* this means we have an extended size, which is the 64 bit value of
3054 * the next 8 bytes */
3055 length = QT_UINT64 (data + 8);
3056 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3066 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3068 guint32 version = 0;
3069 GstClockTime duration = 0;
3071 if (!gst_byte_reader_get_uint32_be (br, &version))
3076 if (!gst_byte_reader_get_uint64_be (br, &duration))
3081 if (!gst_byte_reader_get_uint32_be (br, &dur))
3086 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3087 qtdemux->duration = duration;
3093 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3099 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3100 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3102 if (!stream->parsed_trex && qtdemux->moov_node) {
3104 GstByteReader trex_data;
3106 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3108 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3111 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3113 /* skip version/flags */
3114 if (!gst_byte_reader_skip (&trex_data, 4))
3116 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3118 if (id != stream->track_id)
3120 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3122 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3124 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3126 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3129 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3130 "duration %d, size %d, flags 0x%x", stream->track_id,
3133 stream->parsed_trex = TRUE;
3134 stream->def_sample_description_index = sdi;
3135 stream->def_sample_duration = dur;
3136 stream->def_sample_size = size;
3137 stream->def_sample_flags = flags;
3140 /* iterate all siblings */
3141 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3147 *ds_duration = stream->def_sample_duration;
3148 *ds_size = stream->def_sample_size;
3149 *ds_flags = stream->def_sample_flags;
3151 /* even then, above values are better than random ... */
3152 if (G_UNLIKELY (!stream->parsed_trex)) {
3153 GST_WARNING_OBJECT (qtdemux,
3154 "failed to find fragment defaults for stream %d", stream->track_id);
3161 /* This method should be called whenever a more accurate duration might
3162 * have been found. It will update all relevant variables if/where needed
3165 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3169 GstClockTime prevdur;
3172 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3174 if (movdur > qtdemux->duration) {
3175 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3176 GST_DEBUG_OBJECT (qtdemux,
3177 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3178 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3179 qtdemux->duration = movdur;
3180 GST_DEBUG_OBJECT (qtdemux,
3181 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3182 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3183 GST_TIME_ARGS (qtdemux->segment.stop));
3184 if (qtdemux->segment.duration == prevdur) {
3185 /* If the current segment has duration/stop identical to previous duration
3186 * update them also (because they were set at that point in time with
3187 * the wrong duration */
3188 /* We convert the value *from* the timescale version to avoid rounding errors */
3189 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3190 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3191 qtdemux->segment.duration = fixeddur;
3192 qtdemux->segment.stop = fixeddur;
3195 for (iter = qtdemux->active_streams, i = 0; iter;
3196 iter = g_list_next (iter), i++) {
3197 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3199 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3200 if (movdur > stream->duration) {
3201 GST_DEBUG_OBJECT (qtdemux,
3202 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3203 GST_TIME_ARGS (duration));
3204 stream->duration = movdur;
3205 /* internal duration tracking state has been updated above, so */
3206 /* preserve an open-ended dummy segment rather than repeatedly updating
3207 * it and spamming downstream accordingly with segment events */
3208 if (stream->dummy_segment &&
3209 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3210 /* Update all dummy values to new duration */
3211 stream->segments[0].stop_time = duration;
3212 stream->segments[0].duration = duration;
3213 stream->segments[0].media_stop = duration;
3215 /* let downstream know we possibly have a new stop time */
3216 if (stream->segment_index != -1) {
3219 if (qtdemux->segment.rate >= 0) {
3220 pos = stream->segment.start;
3222 pos = stream->segment.stop;
3225 gst_qtdemux_stream_update_segment (qtdemux, stream,
3226 stream->segment_index, pos, NULL, NULL);
3234 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3235 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3236 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3237 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3240 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3242 gint32 data_offset = 0;
3243 guint32 flags = 0, first_flags = 0, samples_count = 0;
3246 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3247 QtDemuxSample *sample;
3248 gboolean ismv = FALSE;
3249 gint64 initial_offset;
3251 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3252 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3253 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3254 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3256 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3257 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3261 /* presence of stss or not can't really tell us much,
3262 * and flags and so on tend to be marginally reliable in these files */
3263 if (stream->subtype == FOURCC_soun) {
3264 GST_DEBUG_OBJECT (qtdemux,
3265 "sound track in fragmented file; marking all keyframes");
3266 stream->all_keyframe = TRUE;
3269 if (!gst_byte_reader_skip (trun, 1) ||
3270 !gst_byte_reader_get_uint24_be (trun, &flags))
3273 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3276 if (flags & TR_DATA_OFFSET) {
3277 /* note this is really signed */
3278 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3280 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3281 /* default base offset = first byte of moof */
3282 if (*base_offset == -1) {
3283 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3284 *base_offset = moof_offset;
3286 *running_offset = *base_offset + data_offset;
3288 /* if no offset at all, that would mean data starts at moof start,
3289 * which is a bit wrong and is ismv crappy way, so compensate
3290 * assuming data is in mdat following moof */
3291 if (*base_offset == -1) {
3292 *base_offset = moof_offset + moof_length + 8;
3293 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3296 if (*running_offset == -1)
3297 *running_offset = *base_offset;
3300 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3302 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3303 data_offset, flags, samples_count);
3305 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3306 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3307 GST_DEBUG_OBJECT (qtdemux,
3308 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3309 flags ^= TR_FIRST_SAMPLE_FLAGS;
3311 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3313 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3317 /* FIXME ? spec says other bits should also be checked to determine
3318 * entry size (and prefix size for that matter) */
3320 dur_offset = size_offset = 0;
3321 if (flags & TR_SAMPLE_DURATION) {
3322 GST_LOG_OBJECT (qtdemux, "entry duration present");
3323 dur_offset = entry_size;
3326 if (flags & TR_SAMPLE_SIZE) {
3327 GST_LOG_OBJECT (qtdemux, "entry size present");
3328 size_offset = entry_size;
3331 if (flags & TR_SAMPLE_FLAGS) {
3332 GST_LOG_OBJECT (qtdemux, "entry flags present");
3333 flags_offset = entry_size;
3336 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3337 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3338 ct_offset = entry_size;
3342 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3344 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3346 if (stream->n_samples + samples_count >=
3347 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3350 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3351 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3352 (stream->n_samples + samples_count) *
3353 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3355 /* create a new array of samples if it's the first sample parsed */
3356 if (stream->n_samples == 0) {
3357 g_assert (stream->samples == NULL);
3358 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3359 /* or try to reallocate it with space enough to insert the new samples */
3361 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3362 stream->n_samples + samples_count);
3363 if (stream->samples == NULL)
3366 if (qtdemux->fragment_start != -1) {
3367 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3368 qtdemux->fragment_start = -1;
3370 if (stream->n_samples == 0) {
3371 if (decode_ts > 0) {
3372 timestamp = decode_ts;
3373 } else if (stream->pending_seek != NULL) {
3374 /* if we don't have a timestamp from a tfdt box, we'll use the one
3375 * from the mfra seek table */
3376 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3377 GST_TIME_ARGS (stream->pending_seek->ts));
3379 /* FIXME: this is not fully correct, the timestamp refers to the random
3380 * access sample refered to in the tfra entry, which may not necessarily
3381 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3382 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3387 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3388 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3389 GST_TIME_ARGS (gst_ts));
3391 /* subsequent fragments extend stream */
3393 stream->samples[stream->n_samples - 1].timestamp +
3394 stream->samples[stream->n_samples - 1].duration;
3396 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3397 * difference (1 sec.) between decode_ts and timestamp, prefer the
3399 if (has_tfdt && !qtdemux->upstream_format_is_time
3400 && ABSDIFF (decode_ts, timestamp) >
3401 MAX (stream->duration_last_moof / 2,
3402 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3403 GST_INFO_OBJECT (qtdemux,
3404 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3405 ") are significantly different (more than %" GST_TIME_FORMAT
3406 "), using decode_ts",
3407 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3408 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3409 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3410 MAX (stream->duration_last_moof / 2,
3411 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3412 timestamp = decode_ts;
3415 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3416 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3417 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3421 initial_offset = *running_offset;
3423 sample = stream->samples + stream->n_samples;
3424 for (i = 0; i < samples_count; i++) {
3425 guint32 dur, size, sflags, ct;
3427 /* first read sample data */
3428 if (flags & TR_SAMPLE_DURATION) {
3429 dur = QT_UINT32 (data + dur_offset);
3431 dur = d_sample_duration;
3433 if (flags & TR_SAMPLE_SIZE) {
3434 size = QT_UINT32 (data + size_offset);
3436 size = d_sample_size;
3438 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3440 sflags = first_flags;
3442 sflags = d_sample_flags;
3444 } else if (flags & TR_SAMPLE_FLAGS) {
3445 sflags = QT_UINT32 (data + flags_offset);
3447 sflags = d_sample_flags;
3449 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3450 ct = QT_UINT32 (data + ct_offset);
3456 /* fill the sample information */
3457 sample->offset = *running_offset;
3458 sample->pts_offset = ct;
3459 sample->size = size;
3460 sample->timestamp = timestamp;
3461 sample->duration = dur;
3462 /* sample-is-difference-sample */
3463 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3464 * now idea how it relates to bitfield other than massive LE/BE confusion */
3465 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3466 *running_offset += size;
3468 stream->duration_moof += dur;
3472 /* Update total duration if needed */
3473 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3475 /* Pre-emptively figure out size of mdat based on trun information.
3476 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3477 * size, else we will still be able to use this when dealing with gap'ed
3479 qtdemux->mdatleft = *running_offset - initial_offset;
3480 qtdemux->mdatoffset = initial_offset;
3481 qtdemux->mdatsize = qtdemux->mdatleft;
3483 stream->n_samples += samples_count;
3484 stream->n_samples_moof += samples_count;
3486 if (stream->pending_seek != NULL)
3487 stream->pending_seek = NULL;
3493 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3498 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3504 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3505 "be larger than %uMB (broken file?)", stream->n_samples,
3506 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3511 /* find stream with @id */
3512 static inline QtDemuxStream *
3513 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3515 QtDemuxStream *stream;
3519 if (G_UNLIKELY (!id)) {
3520 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3524 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3525 stream = QTDEMUX_STREAM (iter->data);
3526 if (stream->track_id == id)
3529 if (qtdemux->mss_mode) {
3530 /* mss should have only 1 stream anyway */
3531 return QTDEMUX_FIRST_STREAM (qtdemux);
3538 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3539 guint32 * fragment_number)
3541 if (!gst_byte_reader_skip (mfhd, 4))
3543 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3548 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3554 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3555 QtDemuxStream ** stream, guint32 * default_sample_duration,
3556 guint32 * default_sample_size, guint32 * default_sample_flags,
3557 gint64 * base_offset)
3560 guint32 track_id = 0;
3562 if (!gst_byte_reader_skip (tfhd, 1) ||
3563 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3566 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3569 *stream = qtdemux_find_stream (qtdemux, track_id);
3570 if (G_UNLIKELY (!*stream))
3571 goto unknown_stream;
3573 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3574 *base_offset = qtdemux->moof_offset;
3576 if (flags & TF_BASE_DATA_OFFSET)
3577 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3580 /* obtain stream defaults */
3581 qtdemux_parse_trex (qtdemux, *stream,
3582 default_sample_duration, default_sample_size, default_sample_flags);
3584 (*stream)->stsd_sample_description_id =
3585 (*stream)->def_sample_description_index - 1;
3587 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3588 guint32 sample_description_index;
3589 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3591 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3594 if (qtdemux->mss_mode) {
3595 /* mss has no stsd entry */
3596 (*stream)->stsd_sample_description_id = 0;
3599 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3600 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3603 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3604 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3607 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3608 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3615 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3620 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3626 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3627 guint64 * decode_time)
3629 guint32 version = 0;
3631 if (!gst_byte_reader_get_uint32_be (br, &version))
3636 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3639 guint32 dec_time = 0;
3640 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3642 *decode_time = dec_time;
3645 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3652 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3657 /* Returns a pointer to a GstStructure containing the properties of
3658 * the stream sample identified by @sample_index. The caller must unref
3659 * the returned object after use. Returns NULL if unsuccessful. */
3660 static GstStructure *
3661 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3662 QtDemuxStream * stream, guint sample_index)
3664 QtDemuxCencSampleSetInfo *info = NULL;
3666 g_return_val_if_fail (stream != NULL, NULL);
3667 g_return_val_if_fail (stream->protected, NULL);
3668 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3670 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3672 /* Currently, cenc properties for groups of samples are not supported, so
3673 * simply return a copy of the default sample properties */
3674 return gst_structure_copy (info->default_properties);
3677 /* Parses the sizes of sample auxiliary information contained within a stream,
3678 * as given in a saiz box. Returns array of sample_count guint8 size values,
3679 * or NULL on failure */
3681 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3682 GstByteReader * br, guint32 * sample_count)
3686 guint8 default_info_size;
3688 g_return_val_if_fail (qtdemux != NULL, NULL);
3689 g_return_val_if_fail (stream != NULL, NULL);
3690 g_return_val_if_fail (br != NULL, NULL);
3691 g_return_val_if_fail (sample_count != NULL, NULL);
3693 if (!gst_byte_reader_get_uint32_be (br, &flags))
3697 /* aux_info_type and aux_info_type_parameter are ignored */
3698 if (!gst_byte_reader_skip (br, 8))
3702 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3704 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3706 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3708 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3711 if (default_info_size == 0) {
3712 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3716 info_sizes = g_new (guint8, *sample_count);
3717 memset (info_sizes, default_info_size, *sample_count);
3723 /* Parses the offset of sample auxiliary information contained within a stream,
3724 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3726 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3727 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3732 guint32 aux_info_type = 0;
3733 guint32 aux_info_type_parameter = 0;
3734 guint32 entry_count;
3737 const guint8 *aux_info_type_data = NULL;
3739 g_return_val_if_fail (qtdemux != NULL, FALSE);
3740 g_return_val_if_fail (stream != NULL, FALSE);
3741 g_return_val_if_fail (br != NULL, FALSE);
3742 g_return_val_if_fail (offset != NULL, FALSE);
3744 if (!gst_byte_reader_get_uint8 (br, &version))
3747 if (!gst_byte_reader_get_uint24_be (br, &flags))
3752 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3754 aux_info_type = QT_FOURCC (aux_info_type_data);
3756 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3758 } else if (stream->protected) {
3759 aux_info_type = stream->protection_scheme_type;
3761 aux_info_type = CUR_STREAM (stream)->fourcc;
3765 *info_type = aux_info_type;
3766 if (info_type_parameter)
3767 *info_type_parameter = aux_info_type_parameter;
3769 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3770 "aux_info_type_parameter: %#06x",
3771 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3773 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3776 if (entry_count != 1) {
3777 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3782 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3784 *offset = (guint64) off_32;
3786 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3791 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3796 qtdemux_gst_structure_free (GstStructure * gststructure)
3799 gst_structure_free (gststructure);
3803 /* Parses auxiliary information relating to samples protected using Common
3804 * Encryption (cenc); the format of this information is defined in
3805 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3807 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3808 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3810 QtDemuxCencSampleSetInfo *ss_info = NULL;
3813 GPtrArray *old_crypto_info = NULL;
3814 guint old_entries = 0;
3816 g_return_val_if_fail (qtdemux != NULL, FALSE);
3817 g_return_val_if_fail (stream != NULL, FALSE);
3818 g_return_val_if_fail (br != NULL, FALSE);
3819 g_return_val_if_fail (stream->protected, FALSE);
3820 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3822 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3824 if (ss_info->crypto_info) {
3825 old_crypto_info = ss_info->crypto_info;
3826 /* Count number of non-null entries remaining at the tail end */
3827 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3828 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3834 ss_info->crypto_info =
3835 g_ptr_array_new_full (sample_count + old_entries,
3836 (GDestroyNotify) qtdemux_gst_structure_free);
3838 /* We preserve old entries because we parse the next moof in advance
3839 * of consuming all samples from the previous moof, and otherwise
3840 * we'd discard the corresponding crypto info for the samples
3841 * from the previous fragment. */
3843 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3845 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3846 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3848 g_ptr_array_index (old_crypto_info, i) = NULL;
3852 if (old_crypto_info) {
3853 /* Everything now belongs to the new array */
3854 g_ptr_array_free (old_crypto_info, TRUE);
3857 for (i = 0; i < sample_count; ++i) {
3858 GstStructure *properties;
3859 guint16 n_subsamples = 0;
3864 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3865 if (properties == NULL) {
3866 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3869 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3870 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3871 gst_structure_free (properties);
3874 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3875 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3876 gst_structure_free (properties);
3879 buf = gst_buffer_new_wrapped (data, iv_size);
3880 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3881 gst_buffer_unref (buf);
3882 size = info_sizes[i];
3883 if (size > iv_size) {
3884 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3885 || !(n_subsamples > 0)) {
3886 gst_structure_free (properties);
3887 GST_ERROR_OBJECT (qtdemux,
3888 "failed to get subsample count for sample %u", i);
3891 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3892 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3893 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3895 gst_structure_free (properties);
3898 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3900 gst_structure_free (properties);
3903 gst_structure_set (properties,
3904 "subsample_count", G_TYPE_UINT, n_subsamples,
3905 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3906 gst_buffer_unref (buf);
3908 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3910 g_ptr_array_add (ss_info->crypto_info, properties);
3915 /* Converts a UUID in raw byte form to a string representation, as defined in
3916 * RFC 4122. The caller takes ownership of the returned string and is
3917 * responsible for freeing it after use. */
3919 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3921 const guint8 *uuid = (const guint8 *) uuid_bytes;
3923 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3924 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3925 uuid[0], uuid[1], uuid[2], uuid[3],
3926 uuid[4], uuid[5], uuid[6], uuid[7],
3927 uuid[8], uuid[9], uuid[10], uuid[11],
3928 uuid[12], uuid[13], uuid[14], uuid[15]);
3931 /* Parses a Protection System Specific Header box (pssh), as defined in the
3932 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3933 * information needed by a specific content protection system in order to
3934 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3937 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3939 gchar *sysid_string;
3940 guint32 pssh_size = QT_UINT32 (node->data);
3941 GstBuffer *pssh = NULL;
3942 GstEvent *event = NULL;
3943 guint32 parent_box_type;
3946 if (G_UNLIKELY (pssh_size < 32U)) {
3947 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3952 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3954 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3956 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3957 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3958 gst_buffer_get_size (pssh));
3960 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3962 /* Push an event containing the pssh box onto the queues of all streams. */
3963 event = gst_event_new_protection (sysid_string, pssh,
3964 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3965 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3966 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3967 GST_TRACE_OBJECT (qtdemux,
3968 "adding protection event for stream %s and system %s",
3969 stream->stream_id, sysid_string);
3970 g_queue_push_tail (&stream->protection_scheme_event_queue,
3971 gst_event_ref (event));
3973 g_free (sysid_string);
3974 gst_event_unref (event);
3975 gst_buffer_unref (pssh);
3980 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3981 guint64 moof_offset, QtDemuxStream * stream)
3983 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3985 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3986 GNode *saiz_node, *saio_node, *pssh_node;
3987 GstByteReader saiz_data, saio_data;
3988 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3989 gint64 base_offset, running_offset;
3991 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
3993 /* NOTE @stream ignored */
3995 moof_node = g_node_new ((guint8 *) buffer);
3996 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3997 qtdemux_node_dump (qtdemux, moof_node);
3999 /* Get fragment number from mfhd and check it's valid */
4001 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4002 if (mfhd_node == NULL)
4004 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4006 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4008 /* unknown base_offset to start with */
4009 base_offset = running_offset = -1;
4010 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4012 guint64 decode_time = 0;
4014 /* Fragment Header node */
4016 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4020 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4021 &ds_size, &ds_flags, &base_offset))
4024 /* The following code assumes at most a single set of sample auxiliary
4025 * data in the fragment (consisting of a saiz box and a corresponding saio
4026 * box); in theory, however, there could be multiple sets of sample
4027 * auxiliary data in a fragment. */
4029 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4032 guint32 info_type = 0;
4034 guint32 info_type_parameter = 0;
4036 g_free (qtdemux->cenc_aux_info_sizes);
4038 qtdemux->cenc_aux_info_sizes =
4039 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4040 &qtdemux->cenc_aux_sample_count);
4041 if (qtdemux->cenc_aux_info_sizes == NULL) {
4042 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4046 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4049 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4050 g_free (qtdemux->cenc_aux_info_sizes);
4051 qtdemux->cenc_aux_info_sizes = NULL;
4055 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4056 &info_type, &info_type_parameter, &offset))) {
4057 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4058 g_free (qtdemux->cenc_aux_info_sizes);
4059 qtdemux->cenc_aux_info_sizes = NULL;
4062 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4063 offset += (guint64) (base_offset - qtdemux->moof_offset);
4064 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4066 if (offset > length) {
4067 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4068 qtdemux->cenc_aux_info_offset = offset;
4070 gst_byte_reader_init (&br, buffer + offset, length - offset);
4071 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4072 qtdemux->cenc_aux_info_sizes,
4073 qtdemux->cenc_aux_sample_count)) {
4074 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4075 g_free (qtdemux->cenc_aux_info_sizes);
4076 qtdemux->cenc_aux_info_sizes = NULL;
4084 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4087 /* We'll use decode_time to interpolate timestamps
4088 * in case the input timestamps are missing */
4089 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4091 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4092 " (%" GST_TIME_FORMAT ")", decode_time,
4093 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4094 decode_time) : GST_CLOCK_TIME_NONE));
4096 /* Discard the fragment buffer timestamp info to avoid using it.
4097 * Rely on tfdt instead as it is more accurate than the timestamp
4098 * that is fetched from a manifest/playlist and is usually
4100 qtdemux->fragment_start = -1;
4103 if (G_UNLIKELY (!stream)) {
4104 /* we lost track of offset, we'll need to regain it,
4105 * but can delay complaining until later or avoid doing so altogether */
4109 if (G_UNLIKELY (base_offset < -1))
4112 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4114 if (!qtdemux->pullbased) {
4115 /* Sample tables can grow enough to be problematic if the system memory
4116 * is very low (e.g. embedded devices) and the videos very long
4117 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4118 * Fortunately, we can easily discard them for each new fragment when
4119 * we know qtdemux will not receive seeks outside of the current fragment.
4120 * adaptivedemux honors this assumption.
4121 * This optimization is also useful for applications that use qtdemux as
4122 * a push-based simple demuxer, like Media Source Extensions. */
4123 gst_qtdemux_stream_flush_samples_data (stream);
4126 /* initialise moof sample data */
4127 stream->n_samples_moof = 0;
4128 stream->duration_last_moof = stream->duration_moof;
4129 stream->duration_moof = 0;
4131 /* Track Run node */
4133 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4136 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4137 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4138 &running_offset, decode_time, (tfdt_node != NULL));
4139 /* iterate all siblings */
4140 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4144 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4146 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4147 guint32 box_length = QT_UINT32 (uuid_buffer);
4149 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4152 /* if no new base_offset provided for next traf,
4153 * base is end of current traf */
4154 base_offset = running_offset;
4155 running_offset = -1;
4157 if (stream->n_samples_moof && stream->duration_moof)
4158 stream->new_caps = TRUE;
4161 /* iterate all siblings */
4162 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4165 /* parse any protection system info */
4166 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4168 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4169 qtdemux_parse_pssh (qtdemux, pssh_node);
4170 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4173 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4174 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4176 /* Unless the user has explictly requested another seek, perform an
4177 * internal seek to the time specified in the tfdt.
4179 * This way if the user opens a file where the first tfdt is 1 hour
4180 * into the presentation, they will not have to wait 1 hour for run
4181 * time to catch up and actual playback to start. */
4184 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4185 "performing an internal seek to %" GST_TIME_FORMAT,
4186 GST_TIME_ARGS (min_dts));
4188 qtdemux->segment.start = min_dts;
4189 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4191 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4192 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
4193 stream->time_position = min_dts;
4196 /* Before this code was run a segment was already sent when the moov was
4197 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4198 * be emitted after a moov, and we can emit a second segment anyway for
4199 * special cases like this. */
4200 qtdemux->need_segment = TRUE;
4203 qtdemux->first_moof_already_parsed = TRUE;
4205 g_node_destroy (moof_node);
4210 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4215 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4220 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4225 g_node_destroy (moof_node);
4226 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4227 (_("This file is corrupt and cannot be played.")), (NULL));
4233 /* might be used if some day we actually use mfra & co
4234 * for random access to fragments,
4235 * but that will require quite some modifications and much less relying
4236 * on a sample array */
4240 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4242 QtDemuxStream *stream;
4243 guint32 ver_flags, track_id, len, num_entries, i;
4244 guint value_size, traf_size, trun_size, sample_size;
4245 guint64 time = 0, moof_offset = 0;
4247 GstBuffer *buf = NULL;
4252 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4254 if (!gst_byte_reader_skip (&tfra, 8))
4257 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4260 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4261 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4262 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4265 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4267 stream = qtdemux_find_stream (qtdemux, track_id);
4269 goto unknown_trackid;
4271 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4272 sample_size = (len & 3) + 1;
4273 trun_size = ((len & 12) >> 2) + 1;
4274 traf_size = ((len & 48) >> 4) + 1;
4276 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4277 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4279 if (num_entries == 0)
4282 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4283 value_size + value_size + traf_size + trun_size + sample_size))
4286 g_free (stream->ra_entries);
4287 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4288 stream->n_ra_entries = num_entries;
4290 for (i = 0; i < num_entries; i++) {
4291 qt_atom_parser_get_offset (&tfra, value_size, &time);
4292 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4293 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4294 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4295 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4297 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4299 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4300 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4302 stream->ra_entries[i].ts = time;
4303 stream->ra_entries[i].moof_offset = moof_offset;
4305 /* don't want to go through the entire file and read all moofs at startup */
4307 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4308 if (ret != GST_FLOW_OK)
4310 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4311 moof_offset, stream);
4312 gst_buffer_unref (buf);
4316 check_update_duration (qtdemux, time);
4323 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4328 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4333 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4339 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4341 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4342 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4343 GstBuffer *mfro = NULL, *mfra = NULL;
4345 gboolean ret = FALSE;
4346 GNode *mfra_node, *tfra_node;
4347 guint64 mfra_offset = 0;
4348 guint32 fourcc, mfra_size;
4351 /* query upstream size in bytes */
4352 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4353 goto size_query_failed;
4355 /* mfro box should be at the very end of the file */
4356 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4357 if (flow != GST_FLOW_OK)
4360 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4362 fourcc = QT_FOURCC (mfro_map.data + 4);
4363 if (fourcc != FOURCC_mfro)
4366 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4367 if (mfro_map.size < 16)
4368 goto invalid_mfro_size;
4370 mfra_size = QT_UINT32 (mfro_map.data + 12);
4371 if (mfra_size >= len)
4372 goto invalid_mfra_size;
4374 mfra_offset = len - mfra_size;
4376 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4377 mfra_offset, mfra_size);
4379 /* now get and parse mfra box */
4380 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4381 if (flow != GST_FLOW_OK)
4384 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4386 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4387 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4389 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4392 qtdemux_parse_tfra (qtdemux, tfra_node);
4393 /* iterate all siblings */
4394 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4396 g_node_destroy (mfra_node);
4398 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4404 if (mfro_map.memory != NULL)
4405 gst_buffer_unmap (mfro, &mfro_map);
4406 gst_buffer_unref (mfro);
4409 if (mfra_map.memory != NULL)
4410 gst_buffer_unmap (mfra, &mfra_map);
4411 gst_buffer_unref (mfra);
4418 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4423 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4428 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4433 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4439 add_offset (guint64 offset, guint64 advance)
4441 /* Avoid 64-bit overflow by clamping */
4442 if (offset > G_MAXUINT64 - advance)
4444 return offset + advance;
4447 static GstFlowReturn
4448 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4452 GstBuffer *buf = NULL;
4453 GstFlowReturn ret = GST_FLOW_OK;
4454 guint64 cur_offset = qtdemux->offset;
4457 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4458 if (G_UNLIKELY (ret != GST_FLOW_OK))
4460 gst_buffer_map (buf, &map, GST_MAP_READ);
4461 if (G_LIKELY (map.size >= 8))
4462 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4463 gst_buffer_unmap (buf, &map);
4464 gst_buffer_unref (buf);
4466 /* maybe we already got most we needed, so only consider this eof */
4467 if (G_UNLIKELY (length == 0)) {
4468 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4469 (_("Invalid atom size.")),
4470 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4471 GST_FOURCC_ARGS (fourcc)));
4478 /* record for later parsing when needed */
4479 if (!qtdemux->moof_offset) {
4480 qtdemux->moof_offset = qtdemux->offset;
4482 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4485 qtdemux->offset += length; /* skip moof and keep going */
4487 if (qtdemux->got_moov) {
4488 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4500 GST_LOG_OBJECT (qtdemux,
4501 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4502 GST_FOURCC_ARGS (fourcc), cur_offset);
4503 qtdemux->offset = add_offset (qtdemux->offset, length);
4508 GstBuffer *moov = NULL;
4510 if (qtdemux->got_moov) {
4511 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4512 qtdemux->offset = add_offset (qtdemux->offset, length);
4516 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4517 if (ret != GST_FLOW_OK)
4519 gst_buffer_map (moov, &map, GST_MAP_READ);
4521 if (length != map.size) {
4522 /* Some files have a 'moov' atom at the end of the file which contains
4523 * a terminal 'free' atom where the body of the atom is missing.
4524 * Check for, and permit, this special case.
4526 if (map.size >= 8) {
4527 guint8 *final_data = map.data + (map.size - 8);
4528 guint32 final_length = QT_UINT32 (final_data);
4529 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4531 if (final_fourcc == FOURCC_free
4532 && map.size + final_length - 8 == length) {
4533 /* Ok, we've found that special case. Allocate a new buffer with
4534 * that free atom actually present. */
4535 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4536 gst_buffer_fill (newmoov, 0, map.data, map.size);
4537 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4538 gst_buffer_unmap (moov, &map);
4539 gst_buffer_unref (moov);
4541 gst_buffer_map (moov, &map, GST_MAP_READ);
4546 if (length != map.size) {
4547 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4548 (_("This file is incomplete and cannot be played.")),
4549 ("We got less than expected (received %" G_GSIZE_FORMAT
4550 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4551 (guint) length, cur_offset));
4552 gst_buffer_unmap (moov, &map);
4553 gst_buffer_unref (moov);
4554 ret = GST_FLOW_ERROR;
4557 qtdemux->offset += length;
4559 qtdemux_parse_moov (qtdemux, map.data, length);
4560 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4562 qtdemux_parse_tree (qtdemux);
4563 if (qtdemux->moov_node_compressed) {
4564 g_node_destroy (qtdemux->moov_node_compressed);
4565 g_free (qtdemux->moov_node->data);
4567 qtdemux->moov_node_compressed = NULL;
4568 g_node_destroy (qtdemux->moov_node);
4569 qtdemux->moov_node = NULL;
4570 gst_buffer_unmap (moov, &map);
4571 gst_buffer_unref (moov);
4572 qtdemux->got_moov = TRUE;
4578 GstBuffer *ftyp = NULL;
4580 /* extract major brand; might come in handy for ISO vs QT issues */
4581 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4582 if (ret != GST_FLOW_OK)
4584 qtdemux->offset += length;
4585 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4586 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4587 gst_buffer_unmap (ftyp, &map);
4588 gst_buffer_unref (ftyp);
4593 GstBuffer *uuid = NULL;
4595 /* uuid are extension atoms */
4596 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4597 if (ret != GST_FLOW_OK)
4599 qtdemux->offset += length;
4600 gst_buffer_map (uuid, &map, GST_MAP_READ);
4601 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4602 gst_buffer_unmap (uuid, &map);
4603 gst_buffer_unref (uuid);
4608 GstBuffer *sidx = NULL;
4609 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4610 if (ret != GST_FLOW_OK)
4612 qtdemux->offset += length;
4613 gst_buffer_map (sidx, &map, GST_MAP_READ);
4614 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4615 gst_buffer_unmap (sidx, &map);
4616 gst_buffer_unref (sidx);
4621 GstBuffer *unknown = NULL;
4623 GST_LOG_OBJECT (qtdemux,
4624 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4625 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4627 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4628 if (ret != GST_FLOW_OK)
4630 gst_buffer_map (unknown, &map, GST_MAP_READ);
4631 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4632 gst_buffer_unmap (unknown, &map);
4633 gst_buffer_unref (unknown);
4634 qtdemux->offset += length;
4640 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4641 /* digested all data, show what we have */
4642 qtdemux_prepare_streams (qtdemux);
4643 QTDEMUX_EXPOSE_LOCK (qtdemux);
4644 ret = qtdemux_expose_streams (qtdemux);
4645 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4647 qtdemux->state = QTDEMUX_STATE_MOVIE;
4648 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4655 /* Seeks to the previous keyframe of the indexed stream and
4656 * aligns other streams with respect to the keyframe timestamp
4657 * of indexed stream. Only called in case of Reverse Playback
4659 static GstFlowReturn
4660 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4662 guint32 seg_idx = 0, k_index = 0;
4663 guint32 ref_seg_idx, ref_k_index;
4664 GstClockTime k_pos = 0, last_stop = 0;
4665 QtDemuxSegment *seg = NULL;
4666 QtDemuxStream *ref_str = NULL;
4667 guint64 seg_media_start_mov; /* segment media start time in mov format */
4671 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4672 * and finally align all the other streams on that timestamp with their
4673 * respective keyframes */
4674 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4675 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4677 /* No candidate yet, take the first stream */
4683 /* So that stream has a segment, we prefer video streams */
4684 if (str->subtype == FOURCC_vide) {
4690 if (G_UNLIKELY (!ref_str)) {
4691 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4695 if (G_UNLIKELY (!ref_str->from_sample)) {
4696 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4700 /* So that stream has been playing from from_sample to to_sample. We will
4701 * get the timestamp of the previous sample and search for a keyframe before
4702 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4703 if (ref_str->subtype == FOURCC_vide) {
4704 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4705 ref_str->from_sample - 1, FALSE);
4707 if (ref_str->from_sample >= 10)
4708 k_index = ref_str->from_sample - 10;
4714 ref_str->samples[k_index].timestamp +
4715 ref_str->samples[k_index].pts_offset;
4717 /* get current segment for that stream */
4718 seg = &ref_str->segments[ref_str->segment_index];
4719 /* Use segment start in original timescale for comparisons */
4720 seg_media_start_mov = seg->trak_media_start;
4722 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4723 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4724 k_index, target_ts, seg_media_start_mov,
4725 GST_TIME_ARGS (seg->media_start));
4727 /* Crawl back through segments to find the one containing this I frame */
4728 while (target_ts < seg_media_start_mov) {
4729 GST_DEBUG_OBJECT (qtdemux,
4730 "keyframe position (sample %u) is out of segment %u " " target %"
4731 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4732 ref_str->segment_index, target_ts, seg_media_start_mov);
4734 if (G_UNLIKELY (!ref_str->segment_index)) {
4735 /* Reached first segment, let's consider it's EOS */
4738 ref_str->segment_index--;
4739 seg = &ref_str->segments[ref_str->segment_index];
4740 /* Use segment start in original timescale for comparisons */
4741 seg_media_start_mov = seg->trak_media_start;
4743 /* Calculate time position of the keyframe and where we should stop */
4745 QTSTREAMTIME_TO_GSTTIME (ref_str,
4746 target_ts - seg->trak_media_start) + seg->time;
4748 QTSTREAMTIME_TO_GSTTIME (ref_str,
4749 ref_str->samples[ref_str->from_sample].timestamp -
4750 seg->trak_media_start) + seg->time;
4752 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4753 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4754 k_index, GST_TIME_ARGS (k_pos));
4756 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4757 qtdemux->segment.position = last_stop;
4758 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4759 GST_TIME_ARGS (last_stop));
4761 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4762 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4766 ref_seg_idx = ref_str->segment_index;
4767 ref_k_index = k_index;
4769 /* Align them all on this */
4770 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4772 GstClockTime seg_time = 0;
4773 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4775 /* aligning reference stream again might lead to backing up to yet another
4776 * keyframe (due to timestamp rounding issues),
4777 * potentially putting more load on downstream; so let's try to avoid */
4778 if (str == ref_str) {
4779 seg_idx = ref_seg_idx;
4780 seg = &str->segments[seg_idx];
4781 k_index = ref_k_index;
4782 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4783 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4785 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4786 GST_DEBUG_OBJECT (qtdemux,
4787 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4788 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4790 /* get segment and time in the segment */
4791 seg = &str->segments[seg_idx];
4792 seg_time = k_pos - seg->time;
4794 /* get the media time in the segment.
4795 * No adjustment for empty "filler" segments */
4796 if (seg->media_start != GST_CLOCK_TIME_NONE)
4797 seg_time += seg->media_start;
4799 /* get the index of the sample with media time */
4800 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4801 GST_DEBUG_OBJECT (qtdemux,
4802 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4803 GST_TIME_ARGS (seg_time), index);
4805 /* find previous keyframe */
4806 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4809 /* Remember until where we want to go */
4810 str->to_sample = str->from_sample - 1;
4811 /* Define our time position */
4813 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4814 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4815 if (seg->media_start != GST_CLOCK_TIME_NONE)
4816 str->time_position -= seg->media_start;
4818 /* Now seek back in time */
4819 gst_qtdemux_move_stream (qtdemux, str, k_index);
4820 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4821 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4822 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4828 return GST_FLOW_EOS;
4832 * Gets the current qt segment start, stop and position for the
4833 * given time offset. This is used in update_segment()
4836 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4837 QtDemuxStream * stream, GstClockTime offset,
4838 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4840 GstClockTime seg_time;
4841 GstClockTime start, stop, time;
4842 QtDemuxSegment *segment;
4844 segment = &stream->segments[stream->segment_index];
4846 /* get time in this segment */
4847 seg_time = (offset - segment->time) * segment->rate;
4849 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4850 GST_TIME_ARGS (seg_time));
4852 if (G_UNLIKELY (seg_time > segment->duration)) {
4853 GST_LOG_OBJECT (stream->pad,
4854 "seg_time > segment->duration %" GST_TIME_FORMAT,
4855 GST_TIME_ARGS (segment->duration));
4856 seg_time = segment->duration;
4859 /* qtdemux->segment.stop is in outside-time-realm, whereas
4860 * segment->media_stop is in track-time-realm.
4862 * In order to compare the two, we need to bring segment.stop
4863 * into the track-time-realm
4865 * FIXME - does this comment still hold? Don't see any conversion here */
4867 stop = qtdemux->segment.stop;
4868 if (stop == GST_CLOCK_TIME_NONE)
4869 stop = qtdemux->segment.duration;
4870 if (stop == GST_CLOCK_TIME_NONE)
4871 stop = segment->media_stop;
4874 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4876 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4877 start = segment->time + seg_time;
4879 stop = start - seg_time + segment->duration;
4880 } else if (qtdemux->segment.rate >= 0) {
4881 start = MIN (segment->media_start + seg_time, stop);
4884 if (segment->media_start >= qtdemux->segment.start) {
4885 time = segment->time;
4887 time = segment->time + (qtdemux->segment.start - segment->media_start);
4890 start = MAX (segment->media_start, qtdemux->segment.start);
4891 stop = MIN (segment->media_start + seg_time, stop);
4900 * Updates the qt segment used for the stream and pushes a new segment event
4901 * downstream on this stream's pad.
4904 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4905 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4906 GstClockTime * _stop)
4908 QtDemuxSegment *segment;
4909 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4913 /* update the current segment */
4914 stream->segment_index = seg_idx;
4916 /* get the segment */
4917 segment = &stream->segments[seg_idx];
4919 if (G_UNLIKELY (offset < segment->time)) {
4920 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4921 GST_TIME_ARGS (segment->time));
4925 /* segment lies beyond total indicated duration */
4926 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4927 segment->time > qtdemux->segment.duration)) {
4928 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4929 " < segment->time %" GST_TIME_FORMAT,
4930 GST_TIME_ARGS (qtdemux->segment.duration),
4931 GST_TIME_ARGS (segment->time));
4935 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4936 &start, &stop, &time);
4938 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4939 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4940 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4942 /* combine global rate with that of the segment */
4943 rate = segment->rate * qtdemux->segment.rate;
4945 /* Copy flags from main segment */
4946 stream->segment.flags = qtdemux->segment.flags;
4948 /* update the segment values used for clipping */
4949 stream->segment.offset = qtdemux->segment.offset;
4950 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4951 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4952 stream->segment.rate = rate;
4953 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4954 stream->cslg_shift);
4955 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4956 stream->cslg_shift);
4957 stream->segment.time = time;
4958 stream->segment.position = stream->segment.start;
4960 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4963 /* now prepare and send the segment */
4965 event = gst_event_new_segment (&stream->segment);
4966 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4967 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4969 gst_pad_push_event (stream->pad, event);
4970 /* assume we can send more data now */
4971 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4972 /* clear to send tags on this pad now */
4973 gst_qtdemux_push_tags (qtdemux, stream);
4984 /* activate the given segment number @seg_idx of @stream at time @offset.
4985 * @offset is an absolute global position over all the segments.
4987 * This will push out a NEWSEGMENT event with the right values and
4988 * position the stream index to the first decodable sample before
4992 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4993 guint32 seg_idx, GstClockTime offset)
4995 QtDemuxSegment *segment;
4996 guint32 index, kf_index;
4997 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4999 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5000 seg_idx, GST_TIME_ARGS (offset));
5002 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5006 segment = &stream->segments[stream->segment_index];
5008 /* in the fragmented case, we pick a fragment that starts before our
5009 * desired position and rely on downstream to wait for a keyframe
5010 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5011 * tfra entries tells us which trun/sample the key unit is in, but we don't
5012 * make use of this additional information at the moment) */
5013 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5014 stream->to_sample = G_MAXUINT32;
5017 /* well, it will be taken care of below */
5018 qtdemux->fragmented_seek_pending = FALSE;
5019 /* FIXME ideally the do_fragmented_seek can be done right here,
5020 * rather than at loop level
5021 * (which might even allow handling edit lists in a fragmented file) */
5024 /* We don't need to look for a sample in push-based */
5025 if (!qtdemux->pullbased)
5028 /* and move to the keyframe before the indicated media time of the
5030 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5031 if (qtdemux->segment.rate >= 0) {
5032 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5033 stream->to_sample = G_MAXUINT32;
5034 GST_DEBUG_OBJECT (stream->pad,
5035 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5036 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5037 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5039 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5040 stream->to_sample = index;
5041 GST_DEBUG_OBJECT (stream->pad,
5042 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5043 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5044 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5047 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5048 "this is an empty segment");
5052 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5053 * encountered an error and printed a message so we return appropriately */
5057 /* we're at the right spot */
5058 if (index == stream->sample_index) {
5059 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5063 /* find keyframe of the target index */
5064 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5067 /* indent does stupid stuff with stream->samples[].timestamp */
5069 /* if we move forwards, we don't have to go back to the previous
5070 * keyframe since we already sent that. We can also just jump to
5071 * the keyframe right before the target index if there is one. */
5072 if (index > stream->sample_index) {
5073 /* moving forwards check if we move past a keyframe */
5074 if (kf_index > stream->sample_index) {
5075 GST_DEBUG_OBJECT (stream->pad,
5076 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5077 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5078 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5079 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5081 GST_DEBUG_OBJECT (stream->pad,
5082 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5083 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5084 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5087 GST_DEBUG_OBJECT (stream->pad,
5088 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5089 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5090 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5091 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5099 /* prepare to get the current sample of @stream, getting essential values.
5101 * This function will also prepare and send the segment when needed.
5103 * Return FALSE if the stream is EOS.
5108 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5109 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5110 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5111 gboolean * keyframe)
5113 QtDemuxSample *sample;
5114 GstClockTime time_position;
5117 g_return_val_if_fail (stream != NULL, FALSE);
5119 time_position = stream->time_position;
5120 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5123 seg_idx = stream->segment_index;
5124 if (G_UNLIKELY (seg_idx == -1)) {
5125 /* find segment corresponding to time_position if we are looking
5127 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5130 /* different segment, activate it, sample_index will be set. */
5131 if (G_UNLIKELY (stream->segment_index != seg_idx))
5132 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5134 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5136 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5138 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5139 " prepare empty sample");
5142 *pts = *dts = time_position;
5143 *duration = seg->duration - (time_position - seg->time);
5150 if (stream->sample_index == -1)
5151 stream->sample_index = 0;
5153 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5154 stream->sample_index, stream->n_samples);
5156 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5157 if (!qtdemux->fragmented)
5160 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5164 GST_OBJECT_LOCK (qtdemux);
5165 flow = qtdemux_add_fragmented_samples (qtdemux);
5166 GST_OBJECT_UNLOCK (qtdemux);
5168 if (flow != GST_FLOW_OK)
5171 while (stream->sample_index >= stream->n_samples);
5174 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5175 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5176 stream->sample_index);
5180 /* now get the info for the sample we're at */
5181 sample = &stream->samples[stream->sample_index];
5183 *dts = QTSAMPLE_DTS (stream, sample);
5184 *pts = QTSAMPLE_PTS (stream, sample);
5185 *offset = sample->offset;
5186 *size = sample->size;
5187 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5188 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5195 stream->time_position = GST_CLOCK_TIME_NONE;
5200 /* move to the next sample in @stream.
5202 * Moves to the next segment when needed.
5205 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5207 QtDemuxSample *sample;
5208 QtDemuxSegment *segment;
5210 /* get current segment */
5211 segment = &stream->segments[stream->segment_index];
5213 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5214 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5218 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5219 /* Mark the stream as EOS */
5220 GST_DEBUG_OBJECT (qtdemux,
5221 "reached max allowed sample %u, mark EOS", stream->to_sample);
5222 stream->time_position = GST_CLOCK_TIME_NONE;
5226 /* move to next sample */
5227 stream->sample_index++;
5228 stream->offset_in_sample = 0;
5230 /* reached the last sample, we need the next segment */
5231 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5234 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5235 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5236 stream->sample_index);
5240 /* get next sample */
5241 sample = &stream->samples[stream->sample_index];
5243 /* see if we are past the segment */
5244 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5247 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5248 /* inside the segment, update time_position, looks very familiar to
5249 * GStreamer segments, doesn't it? */
5250 stream->time_position =
5251 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5253 /* not yet in segment, time does not yet increment. This means
5254 * that we are still prerolling keyframes to the decoder so it can
5255 * decode the first sample of the segment. */
5256 stream->time_position = segment->time;
5260 /* move to the next segment */
5263 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5265 if (stream->segment_index == stream->n_segments - 1) {
5266 /* are we at the end of the last segment, we're EOS */
5267 stream->time_position = GST_CLOCK_TIME_NONE;
5269 /* else we're only at the end of the current segment */
5270 stream->time_position = segment->stop_time;
5272 /* make sure we select a new segment */
5274 /* accumulate previous segments */
5275 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5276 stream->accumulated_base +=
5277 (stream->segment.stop -
5278 stream->segment.start) / ABS (stream->segment.rate);
5280 stream->segment_index = -1;
5285 gst_qtdemux_sync_streams (GstQTDemux * demux)
5289 if (demux->n_streams <= 1)
5292 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
5293 QtDemuxStream *stream;
5294 GstClockTime end_time;
5296 stream = QTDEMUX_STREAM (iter->data);
5301 /* TODO advance time on subtitle streams here, if any some day */
5303 /* some clips/trailers may have unbalanced streams at the end,
5304 * so send EOS on shorter stream to prevent stalling others */
5306 /* do not mess with EOS if SEGMENT seeking */
5307 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5310 if (demux->pullbased) {
5311 /* loop mode is sample time based */
5312 if (!STREAM_IS_EOS (stream))
5315 /* push mode is byte position based */
5316 if (stream->n_samples &&
5317 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5321 if (stream->sent_eos)
5324 /* only act if some gap */
5325 end_time = stream->segments[stream->n_segments - 1].stop_time;
5326 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5327 ", stream end: %" GST_TIME_FORMAT,
5328 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5329 if (GST_CLOCK_TIME_IS_VALID (end_time)
5330 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5333 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5334 GST_PAD_NAME (stream->pad));
5335 stream->sent_eos = TRUE;
5336 event = gst_event_new_eos ();
5337 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5338 gst_event_set_seqnum (event, demux->segment_seqnum);
5339 gst_pad_push_event (stream->pad, event);
5344 /* EOS and NOT_LINKED need to be combined. This means that we return:
5346 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5347 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5349 static GstFlowReturn
5350 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5353 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5356 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5359 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5361 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5365 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5366 * completely clipped
5368 * Should be used only with raw buffers */
5370 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5373 guint64 start, stop, cstart, cstop, diff;
5374 GstClockTime pts, duration;
5376 gint num_rate, denom_rate;
5381 osize = size = gst_buffer_get_size (buf);
5384 /* depending on the type, setup the clip parameters */
5385 if (stream->subtype == FOURCC_soun) {
5386 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5387 num_rate = GST_SECOND;
5388 denom_rate = (gint) CUR_STREAM (stream)->rate;
5390 } else if (stream->subtype == FOURCC_vide) {
5392 num_rate = CUR_STREAM (stream)->fps_n;
5393 denom_rate = CUR_STREAM (stream)->fps_d;
5398 if (frame_size <= 0)
5399 goto bad_frame_size;
5401 /* we can only clip if we have a valid pts */
5402 pts = GST_BUFFER_PTS (buf);
5403 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5406 duration = GST_BUFFER_DURATION (buf);
5408 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5410 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5414 stop = start + duration;
5416 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5417 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5420 /* see if some clipping happened */
5421 diff = cstart - start;
5427 /* bring clipped time to samples and to bytes */
5428 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5431 GST_DEBUG_OBJECT (qtdemux,
5432 "clipping start to %" GST_TIME_FORMAT " %"
5433 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5439 diff = stop - cstop;
5444 /* bring clipped time to samples and then to bytes */
5445 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5447 GST_DEBUG_OBJECT (qtdemux,
5448 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5449 " bytes", GST_TIME_ARGS (cstop), diff);
5454 if (offset != 0 || size != osize)
5455 gst_buffer_resize (buf, offset, size);
5457 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5458 GST_BUFFER_PTS (buf) = pts;
5459 GST_BUFFER_DURATION (buf) = duration;
5463 /* dropped buffer */
5466 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5471 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5476 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5481 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5482 gst_buffer_unref (buf);
5488 gst_qtdemux_align_buffer (GstQTDemux * demux,
5489 GstBuffer * buffer, gsize alignment)
5493 gst_buffer_map (buffer, &map, GST_MAP_READ);
5495 if (map.size < sizeof (guintptr)) {
5496 gst_buffer_unmap (buffer, &map);
5500 if (((guintptr) map.data) & (alignment - 1)) {
5501 GstBuffer *new_buffer;
5502 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5504 new_buffer = gst_buffer_new_allocate (NULL,
5505 gst_buffer_get_size (buffer), ¶ms);
5507 /* Copy data "by hand", so ensure alignment is kept: */
5508 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5510 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5511 GST_DEBUG_OBJECT (demux,
5512 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5515 gst_buffer_unmap (buffer, &map);
5516 gst_buffer_unref (buffer);
5521 gst_buffer_unmap (buffer, &map);
5526 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5532 /* We are converting from pairs to triplets */
5533 *res = ccpair_size / 2 * 3;
5534 storage = g_malloc (*res);
5535 for (i = 0; i * 2 < ccpair_size; i += 1) {
5537 storage[i * 3] = 0xfc;
5539 storage[i * 3] = 0xfd;
5540 storage[i * 3 + 1] = ccpair[i * 2];
5541 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5548 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5552 guint32 atom_length, fourcc;
5553 QtDemuxStreamStsdEntry *stsd_entry;
5555 GST_MEMDUMP ("caption atom", data, size);
5557 /* There might be multiple atoms */
5562 atom_length = QT_UINT32 (data);
5563 fourcc = QT_FOURCC (data + 4);
5564 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5567 GST_DEBUG_OBJECT (stream->pad, "here");
5569 /* Check if we have somethig compatible */
5570 stsd_entry = CUR_STREAM (stream);
5571 switch (stsd_entry->fourcc) {
5573 guint8 *cdat = NULL, *cdt2 = NULL;
5574 gsize cdat_size = 0, cdt2_size = 0;
5575 /* Should be cdat or cdt2 */
5576 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5577 GST_WARNING_OBJECT (stream->pad,
5578 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5579 GST_FOURCC_ARGS (fourcc));
5583 /* Convert to cc_data triplet */
5584 if (fourcc == FOURCC_cdat)
5585 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5587 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5588 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5591 /* Check for another atom ? */
5592 if (size > atom_length + 8) {
5593 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5594 if (size >= atom_length + new_atom_length) {
5595 fourcc = QT_FOURCC (data + atom_length + 4);
5596 if (fourcc == FOURCC_cdat) {
5599 convert_to_ccdata (data + atom_length + 8,
5600 new_atom_length - 8, 1, &cdat_size);
5602 GST_WARNING_OBJECT (stream->pad,
5603 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5607 convert_to_ccdata (data + atom_length + 8,
5608 new_atom_length - 8, 2, &cdt2_size);
5610 GST_WARNING_OBJECT (stream->pad,
5611 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5616 *cclen = cdat_size + cdt2_size;
5617 res = g_malloc (*cclen);
5619 memcpy (res, cdat, cdat_size);
5621 memcpy (res + cdat_size, cdt2, cdt2_size);
5627 if (fourcc != FOURCC_ccdp) {
5628 GST_WARNING_OBJECT (stream->pad,
5629 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5630 GST_FOURCC_ARGS (fourcc));
5633 *cclen = atom_length - 8;
5634 res = g_memdup (data + 8, *cclen);
5637 /* Keep this here in case other closed caption formats are added */
5638 g_assert_not_reached ();
5642 GST_MEMDUMP ("Output", res, *cclen);
5647 GST_WARNING ("[cdat] atom is too small or invalid");
5651 /* the input buffer metadata must be writable,
5652 * but time/duration etc not yet set and need not be preserved */
5654 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5661 /* not many cases for now */
5662 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5663 /* send a one time dvd clut event */
5664 if (stream->pending_event && stream->pad)
5665 gst_pad_push_event (stream->pad, stream->pending_event);
5666 stream->pending_event = NULL;
5669 if (G_UNLIKELY (stream->subtype != FOURCC_text
5670 && stream->subtype != FOURCC_sbtl &&
5671 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5675 gst_buffer_map (buf, &map, GST_MAP_READ);
5677 /* empty buffer is sent to terminate previous subtitle */
5678 if (map.size <= 2) {
5679 gst_buffer_unmap (buf, &map);
5680 gst_buffer_unref (buf);
5683 if (stream->subtype == FOURCC_subp) {
5684 /* That's all the processing needed for subpictures */
5685 gst_buffer_unmap (buf, &map);
5689 if (stream->subtype == FOURCC_clcp) {
5692 /* For closed caption, we need to extract the information from the
5693 * [cdat],[cdt2] or [ccdp] atom */
5694 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5695 gst_buffer_unmap (buf, &map);
5696 gst_buffer_unref (buf);
5698 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5700 /* Conversion failed or there's nothing */
5706 nsize = GST_READ_UINT16_BE (map.data);
5707 nsize = MIN (nsize, map.size - 2);
5709 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5712 /* takes care of UTF-8 validation or UTF-16 recognition,
5713 * no other encoding expected */
5714 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5715 gst_buffer_unmap (buf, &map);
5717 gst_buffer_unref (buf);
5718 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5720 /* this should not really happen unless the subtitle is corrupted */
5721 gst_buffer_unref (buf);
5725 /* FIXME ? convert optional subsequent style info to markup */
5730 /* Sets a buffer's attributes properly and pushes it downstream.
5731 * Also checks for additional actions and custom processing that may
5732 * need to be done first.
5734 static GstFlowReturn
5735 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5736 QtDemuxStream * stream, GstBuffer * buf,
5737 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5738 gboolean keyframe, GstClockTime position, guint64 byte_position)
5740 GstFlowReturn ret = GST_FLOW_OK;
5742 /* offset the timestamps according to the edit list */
5744 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5748 gst_buffer_map (buf, &map, GST_MAP_READ);
5749 url = g_strndup ((gchar *) map.data, map.size);
5750 gst_buffer_unmap (buf, &map);
5751 if (url != NULL && strlen (url) != 0) {
5752 /* we have RTSP redirect now */
5753 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5754 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5755 gst_structure_new ("redirect",
5756 "new-location", G_TYPE_STRING, url, NULL)));
5757 qtdemux->posted_redirect = TRUE;
5759 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5765 /* position reporting */
5766 if (qtdemux->segment.rate >= 0) {
5767 qtdemux->segment.position = position;
5768 gst_qtdemux_sync_streams (qtdemux);
5771 if (G_UNLIKELY (!stream->pad)) {
5772 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5773 gst_buffer_unref (buf);
5777 /* send out pending buffers */
5778 while (stream->buffers) {
5779 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5781 if (G_UNLIKELY (stream->discont)) {
5782 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5783 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5784 stream->discont = FALSE;
5786 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5789 if (stream->alignment > 1)
5790 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5791 gst_pad_push (stream->pad, buffer);
5793 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5796 /* we're going to modify the metadata */
5797 buf = gst_buffer_make_writable (buf);
5799 if (G_UNLIKELY (stream->need_process))
5800 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5806 GST_BUFFER_DTS (buf) = dts;
5807 GST_BUFFER_PTS (buf) = pts;
5808 GST_BUFFER_DURATION (buf) = duration;
5809 GST_BUFFER_OFFSET (buf) = -1;
5810 GST_BUFFER_OFFSET_END (buf) = -1;
5812 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5813 gst_buffer_append_memory (buf,
5814 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5816 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5817 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5820 if (G_UNLIKELY (qtdemux->element_index)) {
5821 GstClockTime stream_time;
5824 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5826 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5827 GST_LOG_OBJECT (qtdemux,
5828 "adding association %" GST_TIME_FORMAT "-> %"
5829 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5830 gst_index_add_association (qtdemux->element_index,
5832 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5833 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5834 GST_FORMAT_BYTES, byte_position, NULL);
5839 if (stream->need_clip)
5840 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5842 if (G_UNLIKELY (buf == NULL))
5845 if (G_UNLIKELY (stream->discont)) {
5846 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5847 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5848 stream->discont = FALSE;
5850 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5854 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5855 stream->on_keyframe = FALSE;
5857 stream->on_keyframe = TRUE;
5861 GST_LOG_OBJECT (qtdemux,
5862 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5863 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5864 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5865 GST_PAD_NAME (stream->pad));
5867 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5868 GstStructure *crypto_info;
5869 QtDemuxCencSampleSetInfo *info =
5870 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5874 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5875 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5876 GST_PTR_FORMAT, event);
5877 gst_pad_push_event (stream->pad, event);
5880 if (info->crypto_info == NULL) {
5881 GST_DEBUG_OBJECT (qtdemux,
5882 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5884 /* The end of the crypto_info array matches our n_samples position,
5885 * so count backward from there */
5886 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5887 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5888 /* steal structure from array */
5889 crypto_info = g_ptr_array_index (info->crypto_info, index);
5890 g_ptr_array_index (info->crypto_info, index) = NULL;
5891 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5892 info->crypto_info->len);
5893 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5894 GST_ERROR_OBJECT (qtdemux,
5895 "failed to attach cenc metadata to buffer");
5897 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5898 index, stream->sample_index);
5903 if (stream->alignment > 1)
5904 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5906 ret = gst_pad_push (stream->pad, buf);
5908 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5909 /* mark position in stream, we'll need this to know when to send GAP event */
5910 stream->segment.position = pts + duration;
5917 static const QtDemuxRandomAccessEntry *
5918 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5919 GstClockTime pos, gboolean after)
5921 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5922 guint n_entries = stream->n_ra_entries;
5925 /* we assume the table is sorted */
5926 for (i = 0; i < n_entries; ++i) {
5927 if (entries[i].ts > pos)
5931 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5932 * probably okay to assume that the index lists the very first fragment */
5939 return &entries[i - 1];
5943 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5945 const QtDemuxRandomAccessEntry *best_entry = NULL;
5948 GST_OBJECT_LOCK (qtdemux);
5950 g_assert (qtdemux->n_streams > 0);
5952 /* first see if we can determine where to go to using mfra,
5953 * before we start clearing things */
5954 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5955 const QtDemuxRandomAccessEntry *entry;
5956 QtDemuxStream *stream;
5957 gboolean is_audio_or_video;
5959 stream = QTDEMUX_STREAM (iter->data);
5961 if (stream->ra_entries == NULL)
5964 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5965 is_audio_or_video = TRUE;
5967 is_audio_or_video = FALSE;
5970 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5971 stream->time_position, !is_audio_or_video);
5973 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5974 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5976 stream->pending_seek = entry;
5978 /* decide position to jump to just based on audio/video tracks, not subs */
5979 if (!is_audio_or_video)
5982 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5986 /* no luck, will handle seek otherwise */
5987 if (best_entry == NULL) {
5988 GST_OBJECT_UNLOCK (qtdemux);
5992 /* ok, now we can prepare for processing as of located moof */
5993 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5994 QtDemuxStream *stream;
5996 stream = QTDEMUX_STREAM (iter->data);
5998 g_free (stream->samples);
5999 stream->samples = NULL;
6000 stream->n_samples = 0;
6001 stream->stbl_index = -1; /* no samples have yet been parsed */
6002 stream->sample_index = -1;
6004 if (stream->protection_scheme_info) {
6005 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6006 if (stream->protection_scheme_type == FOURCC_cenc) {
6007 QtDemuxCencSampleSetInfo *info =
6008 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6009 if (info->crypto_info) {
6010 g_ptr_array_free (info->crypto_info, TRUE);
6011 info->crypto_info = NULL;
6017 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6018 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6019 GST_TIME_ARGS (QTDEMUX_FIRST_STREAM (qtdemux)->time_position),
6020 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6022 qtdemux->moof_offset = best_entry->moof_offset;
6024 qtdemux_add_fragmented_samples (qtdemux);
6026 GST_OBJECT_UNLOCK (qtdemux);
6030 static GstFlowReturn
6031 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6033 GstFlowReturn ret = GST_FLOW_OK;
6034 GstBuffer *buf = NULL;
6035 QtDemuxStream *stream, *target_stream = NULL;
6036 GstClockTime min_time;
6038 GstClockTime dts = GST_CLOCK_TIME_NONE;
6039 GstClockTime pts = GST_CLOCK_TIME_NONE;
6040 GstClockTime duration = 0;
6041 gboolean keyframe = FALSE;
6042 guint sample_size = 0;
6047 if (qtdemux->fragmented_seek_pending) {
6048 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6049 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6050 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6051 qtdemux->fragmented_seek_pending = FALSE;
6053 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6057 /* Figure out the next stream sample to output, min_time is expressed in
6058 * global time and runs over the edit list segments. */
6059 min_time = G_MAXUINT64;
6060 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6061 GstClockTime position;
6063 stream = QTDEMUX_STREAM (iter->data);
6064 position = stream->time_position;
6066 /* position of -1 is EOS */
6067 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6068 min_time = position;
6069 target_stream = stream;
6073 if (G_UNLIKELY (target_stream == NULL)) {
6074 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6078 /* check for segment end */
6079 if (G_UNLIKELY (qtdemux->segment.stop != -1
6080 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6081 || (qtdemux->segment.rate < 0
6082 && qtdemux->segment.start > min_time))
6083 && target_stream->on_keyframe)) {
6084 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6085 target_stream->time_position = GST_CLOCK_TIME_NONE;
6089 /* gap events for subtitle streams */
6090 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6091 stream = QTDEMUX_STREAM (iter->data);
6092 if (stream->pad && (stream->subtype == FOURCC_subp
6093 || stream->subtype == FOURCC_text
6094 || stream->subtype == FOURCC_sbtl)) {
6095 /* send one second gap events until the stream catches up */
6096 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6097 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6098 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6099 stream->segment.position + GST_SECOND < min_time) {
6101 gst_event_new_gap (stream->segment.position, GST_SECOND);
6102 gst_pad_push_event (stream->pad, gap);
6103 stream->segment.position += GST_SECOND;
6108 stream = target_stream;
6109 /* fetch info for the current sample of this stream */
6110 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6111 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6114 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6115 if (stream->new_caps) {
6116 gst_qtdemux_configure_stream (qtdemux, stream);
6117 qtdemux_do_allocation (stream, qtdemux);
6120 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6121 if (G_UNLIKELY (qtdemux->
6122 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6123 if (stream->subtype == FOURCC_vide && !keyframe) {
6124 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6130 GST_DEBUG_OBJECT (qtdemux,
6131 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6132 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6133 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6134 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6135 GST_TIME_ARGS (duration));
6137 if (G_UNLIKELY (empty)) {
6138 /* empty segment, push a gap if there's a second or more
6139 * difference and move to the next one */
6140 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6141 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6142 stream->segment.position = pts + duration;
6146 /* hmm, empty sample, skip and move to next sample */
6147 if (G_UNLIKELY (sample_size <= 0))
6150 /* last pushed sample was out of boundary, goto next sample */
6151 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6154 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6157 GST_DEBUG_OBJECT (qtdemux,
6158 "size %d larger than stream max_buffer_size %d, trimming",
6159 sample_size, stream->max_buffer_size);
6161 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6164 if (qtdemux->cenc_aux_info_offset > 0) {
6167 GstBuffer *aux_info = NULL;
6169 /* pull the data stored before the sample */
6171 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6172 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6173 if (G_UNLIKELY (ret != GST_FLOW_OK))
6175 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6176 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6177 gst_byte_reader_init (&br, map.data + 8, map.size);
6178 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6179 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6180 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6181 gst_buffer_unmap (aux_info, &map);
6182 gst_buffer_unref (aux_info);
6183 ret = GST_FLOW_ERROR;
6186 gst_buffer_unmap (aux_info, &map);
6187 gst_buffer_unref (aux_info);
6190 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6193 if (stream->use_allocator) {
6194 /* if we have a per-stream allocator, use it */
6195 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6198 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6200 if (G_UNLIKELY (ret != GST_FLOW_OK))
6203 if (size != sample_size) {
6204 pts += gst_util_uint64_scale_int (GST_SECOND,
6205 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6208 gst_util_uint64_scale_int (GST_SECOND,
6209 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6212 gst_util_uint64_scale_int (GST_SECOND,
6213 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6216 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6217 dts, pts, duration, keyframe, min_time, offset);
6219 if (size != sample_size) {
6220 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6221 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6223 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6225 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6226 if (time_position >= segment->media_start) {
6227 /* inside the segment, update time_position, looks very familiar to
6228 * GStreamer segments, doesn't it? */
6229 stream->time_position = (time_position - segment->media_start) +
6232 /* not yet in segment, time does not yet increment. This means
6233 * that we are still prerolling keyframes to the decoder so it can
6234 * decode the first sample of the segment. */
6235 stream->time_position = segment->time;
6240 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6241 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6242 * we have no more data for the pad to push */
6243 if (ret == GST_FLOW_EOS)
6246 stream->offset_in_sample += size;
6247 if (stream->offset_in_sample >= sample_size) {
6248 gst_qtdemux_advance_sample (qtdemux, stream);
6253 gst_qtdemux_advance_sample (qtdemux, stream);
6261 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6267 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6268 /* EOS will be raised if all are EOS */
6275 gst_qtdemux_loop (GstPad * pad)
6277 GstQTDemux *qtdemux;
6281 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6283 cur_offset = qtdemux->offset;
6284 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6285 cur_offset, qt_demux_state_string (qtdemux->state));
6287 switch (qtdemux->state) {
6288 case QTDEMUX_STATE_INITIAL:
6289 case QTDEMUX_STATE_HEADER:
6290 ret = gst_qtdemux_loop_state_header (qtdemux);
6292 case QTDEMUX_STATE_MOVIE:
6293 ret = gst_qtdemux_loop_state_movie (qtdemux);
6294 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6295 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6303 /* if something went wrong, pause */
6304 if (ret != GST_FLOW_OK)
6308 gst_object_unref (qtdemux);
6314 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6315 (NULL), ("streaming stopped, invalid state"));
6316 gst_pad_pause_task (pad);
6317 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6322 const gchar *reason = gst_flow_get_name (ret);
6324 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6326 gst_pad_pause_task (pad);
6328 /* fatal errors need special actions */
6330 if (ret == GST_FLOW_EOS) {
6331 if (qtdemux->n_streams == 0) {
6332 /* we have no streams, post an error */
6333 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6335 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6338 if ((stop = qtdemux->segment.stop) == -1)
6339 stop = qtdemux->segment.duration;
6341 if (qtdemux->segment.rate >= 0) {
6342 GstMessage *message;
6345 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6346 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6347 GST_FORMAT_TIME, stop);
6348 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6349 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6350 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6351 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6353 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6354 gst_qtdemux_push_event (qtdemux, event);
6356 GstMessage *message;
6359 /* For Reverse Playback */
6360 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6361 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6362 GST_FORMAT_TIME, qtdemux->segment.start);
6363 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6364 qtdemux->segment.start);
6365 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6366 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6367 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6369 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6370 gst_qtdemux_push_event (qtdemux, event);
6375 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6376 event = gst_event_new_eos ();
6377 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6378 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6379 gst_qtdemux_push_event (qtdemux, event);
6381 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6382 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6383 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6392 * Returns if there are samples to be played.
6395 has_next_entry (GstQTDemux * demux)
6397 QtDemuxStream *stream;
6400 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6402 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6403 stream = QTDEMUX_STREAM (iter->data);
6405 if (stream->sample_index == -1) {
6406 stream->sample_index = 0;
6407 stream->offset_in_sample = 0;
6410 if (stream->sample_index >= stream->n_samples) {
6411 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6414 GST_DEBUG_OBJECT (demux, "Found a sample");
6418 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6425 * Returns the size of the first entry at the current offset.
6426 * If -1, there are none (which means EOS or empty file).
6429 next_entry_size (GstQTDemux * demux)
6431 QtDemuxStream *stream, *target_stream = NULL;
6432 guint64 smalloffs = (guint64) - 1;
6433 QtDemuxSample *sample;
6436 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6439 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6440 stream = QTDEMUX_STREAM (iter->data);
6442 if (stream->sample_index == -1) {
6443 stream->sample_index = 0;
6444 stream->offset_in_sample = 0;
6447 if (stream->sample_index >= stream->n_samples) {
6448 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6452 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6453 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6454 stream->sample_index);
6458 sample = &stream->samples[stream->sample_index];
6460 GST_LOG_OBJECT (demux,
6461 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6462 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6463 stream->sample_index, sample->offset, sample->size);
6465 if (((smalloffs == -1)
6466 || (sample->offset < smalloffs)) && (sample->size)) {
6467 smalloffs = sample->offset;
6468 target_stream = stream;
6475 GST_LOG_OBJECT (demux,
6476 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6477 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6479 stream = target_stream;
6480 sample = &stream->samples[stream->sample_index];
6482 if (sample->offset >= demux->offset) {
6483 demux->todrop = sample->offset - demux->offset;
6484 return sample->size + demux->todrop;
6487 GST_DEBUG_OBJECT (demux,
6488 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6493 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6495 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6497 gst_element_post_message (GST_ELEMENT_CAST (demux),
6498 gst_message_new_element (GST_OBJECT_CAST (demux),
6499 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6503 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6508 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6511 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6512 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6513 GST_SEEK_TYPE_NONE, -1);
6515 /* store seqnum to drop flush events, they don't need to reach downstream */
6516 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6517 res = gst_pad_push_event (demux->sinkpad, event);
6518 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6523 /* check for seekable upstream, above and beyond a mere query */
6525 gst_qtdemux_check_seekability (GstQTDemux * demux)
6528 gboolean seekable = FALSE;
6529 gint64 start = -1, stop = -1;
6531 if (demux->upstream_size)
6534 if (demux->upstream_format_is_time)
6537 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6538 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6539 GST_DEBUG_OBJECT (demux, "seeking query failed");
6543 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6545 /* try harder to query upstream size if we didn't get it the first time */
6546 if (seekable && stop == -1) {
6547 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6548 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6551 /* if upstream doesn't know the size, it's likely that it's not seekable in
6552 * practice even if it technically may be seekable */
6553 if (seekable && (start != 0 || stop <= start)) {
6554 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6559 gst_query_unref (query);
6561 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6562 G_GUINT64_FORMAT ")", seekable, start, stop);
6563 demux->upstream_seekable = seekable;
6564 demux->upstream_size = seekable ? stop : -1;
6568 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6570 g_return_if_fail (bytes <= demux->todrop);
6572 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6573 gst_adapter_flush (demux->adapter, bytes);
6574 demux->neededbytes -= bytes;
6575 demux->offset += bytes;
6576 demux->todrop -= bytes;
6579 /* PUSH-MODE only: Send a segment, if not done already. */
6581 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6583 if (G_UNLIKELY (demux->need_segment)) {
6587 if (!demux->upstream_format_is_time) {
6588 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6590 GstEvent *segment_event;
6591 segment_event = gst_event_new_segment (&demux->segment);
6592 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6593 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6594 gst_qtdemux_push_event (demux, segment_event);
6597 demux->need_segment = FALSE;
6599 /* clear to send tags on all streams */
6600 for (iter = demux->active_streams, i = 0; iter;
6601 iter = g_list_next (iter), i++) {
6602 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6603 gst_qtdemux_push_tags (demux, stream);
6604 if (CUR_STREAM (stream)->sparse) {
6605 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6606 gst_pad_push_event (stream->pad,
6607 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6613 /* Used for push mode only. */
6615 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6616 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6618 GstClockTime ts, dur;
6622 stream->segments[segment_index].duration - (pos -
6623 stream->segments[segment_index].time);
6624 stream->time_position += dur;
6626 /* Only gaps with a duration of at least one second are propagated.
6627 * Same workaround as in pull mode.
6628 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6629 if (dur >= GST_SECOND) {
6631 gap = gst_event_new_gap (ts, dur);
6633 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6634 "segment: %" GST_PTR_FORMAT, gap);
6635 gst_pad_push_event (stream->pad, gap);
6639 static GstFlowReturn
6640 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6644 demux = GST_QTDEMUX (parent);
6646 GST_DEBUG_OBJECT (demux,
6647 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6648 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6649 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6650 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6651 gst_buffer_get_size (inbuf), demux->offset);
6653 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6654 gboolean is_gap_input = FALSE;
6657 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6659 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6660 QTDEMUX_STREAM (iter->data)->discont = TRUE;
6663 /* Check if we can land back on our feet in the case where upstream is
6664 * handling the seeking/pushing of samples with gaps in between (like
6665 * in the case of trick-mode DASH for example) */
6666 if (demux->upstream_format_is_time
6667 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6668 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6670 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6671 GST_LOG_OBJECT (demux,
6672 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6673 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6675 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6676 stream, GST_BUFFER_OFFSET (inbuf));
6678 QtDemuxSample *sample = &stream->samples[res];
6679 GST_LOG_OBJECT (demux,
6680 "Checking if sample %d from track-id %u is valid (offset:%"
6681 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6682 stream->track_id, sample->offset, sample->size);
6683 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6684 GST_LOG_OBJECT (demux,
6685 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6687 is_gap_input = TRUE;
6688 /* We can go back to standard playback mode */
6689 demux->state = QTDEMUX_STATE_MOVIE;
6690 /* Remember which sample this stream is at */
6691 stream->sample_index = res;
6692 /* Finally update all push-based values to the expected values */
6693 demux->neededbytes = stream->samples[res].size;
6694 demux->offset = GST_BUFFER_OFFSET (inbuf);
6696 demux->mdatsize - demux->offset + demux->mdatoffset;
6701 if (!is_gap_input) {
6702 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6703 /* Reset state if it's a real discont */
6704 demux->neededbytes = 16;
6705 demux->state = QTDEMUX_STATE_INITIAL;
6706 demux->offset = GST_BUFFER_OFFSET (inbuf);
6707 gst_adapter_clear (demux->adapter);
6710 /* Reverse fragmented playback, need to flush all we have before
6711 * consuming a new fragment.
6712 * The samples array have the timestamps calculated by accumulating the
6713 * durations but this won't work for reverse playback of fragments as
6714 * the timestamps of a subsequent fragment should be smaller than the
6715 * previously received one. */
6716 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6717 gst_qtdemux_process_adapter (demux, TRUE);
6718 g_list_foreach (demux->active_streams,
6719 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6723 gst_adapter_push (demux->adapter, inbuf);
6725 GST_DEBUG_OBJECT (demux,
6726 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6727 demux->neededbytes, gst_adapter_available (demux->adapter));
6729 return gst_qtdemux_process_adapter (demux, FALSE);
6732 static GstFlowReturn
6733 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6735 GstFlowReturn ret = GST_FLOW_OK;
6737 /* we never really mean to buffer that much */
6738 if (demux->neededbytes == -1) {
6742 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6743 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6745 #ifndef GST_DISABLE_GST_DEBUG
6747 guint64 discont_offset, distance_from_discont;
6749 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6750 distance_from_discont =
6751 gst_adapter_distance_from_discont (demux->adapter);
6753 GST_DEBUG_OBJECT (demux,
6754 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6755 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6756 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6757 demux->offset, discont_offset, distance_from_discont);
6761 switch (demux->state) {
6762 case QTDEMUX_STATE_INITIAL:{
6767 gst_qtdemux_check_seekability (demux);
6769 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6771 /* get fourcc/length, set neededbytes */
6772 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6774 gst_adapter_unmap (demux->adapter);
6776 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6777 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6779 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6780 (_("This file is invalid and cannot be played.")),
6781 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6782 GST_FOURCC_ARGS (fourcc)));
6783 ret = GST_FLOW_ERROR;
6786 if (fourcc == FOURCC_mdat) {
6787 gint next_entry = next_entry_size (demux);
6788 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6789 /* we have the headers, start playback */
6790 demux->state = QTDEMUX_STATE_MOVIE;
6791 demux->neededbytes = next_entry;
6792 demux->mdatleft = size;
6793 demux->mdatsize = demux->mdatleft;
6795 /* no headers yet, try to get them */
6798 guint64 old, target;
6801 old = demux->offset;
6802 target = old + size;
6804 /* try to jump over the atom with a seek */
6805 /* only bother if it seems worth doing so,
6806 * and avoids possible upstream/server problems */
6807 if (demux->upstream_seekable &&
6808 demux->upstream_size > 4 * (1 << 20)) {
6809 res = qtdemux_seek_offset (demux, target);
6811 GST_DEBUG_OBJECT (demux, "skipping seek");
6816 GST_DEBUG_OBJECT (demux, "seek success");
6817 /* remember the offset fo the first mdat so we can seek back to it
6818 * after we have the headers */
6819 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6820 demux->first_mdat = old;
6821 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6824 /* seek worked, continue reading */
6825 demux->offset = target;
6826 demux->neededbytes = 16;
6827 demux->state = QTDEMUX_STATE_INITIAL;
6829 /* seek failed, need to buffer */
6830 demux->offset = old;
6831 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6832 /* there may be multiple mdat (or alike) buffers */
6834 if (demux->mdatbuffer)
6835 bs = gst_buffer_get_size (demux->mdatbuffer);
6838 if (size + bs > 10 * (1 << 20))
6840 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6841 demux->neededbytes = size;
6842 if (!demux->mdatbuffer)
6843 demux->mdatoffset = demux->offset;
6846 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6847 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6848 (_("This file is invalid and cannot be played.")),
6849 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6850 GST_FOURCC_ARGS (fourcc), size));
6851 ret = GST_FLOW_ERROR;
6854 /* this means we already started buffering and still no moov header,
6855 * let's continue buffering everything till we get moov */
6856 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6857 || fourcc == FOURCC_moof))
6859 demux->neededbytes = size;
6860 demux->state = QTDEMUX_STATE_HEADER;
6864 case QTDEMUX_STATE_HEADER:{
6868 GST_DEBUG_OBJECT (demux, "In header");
6870 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6872 /* parse the header */
6873 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6875 if (fourcc == FOURCC_moov) {
6876 /* in usual fragmented setup we could try to scan for more
6877 * and end up at the the moov (after mdat) again */
6878 if (demux->got_moov && demux->n_streams > 0 &&
6880 || demux->last_moov_offset == demux->offset)) {
6881 GST_DEBUG_OBJECT (demux,
6882 "Skipping moov atom as we have (this) one already");
6884 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6886 if (demux->got_moov && demux->fragmented) {
6887 GST_DEBUG_OBJECT (demux,
6888 "Got a second moov, clean up data from old one");
6889 if (demux->moov_node_compressed) {
6890 g_node_destroy (demux->moov_node_compressed);
6891 if (demux->moov_node)
6892 g_free (demux->moov_node->data);
6894 demux->moov_node_compressed = NULL;
6895 if (demux->moov_node)
6896 g_node_destroy (demux->moov_node);
6897 demux->moov_node = NULL;
6900 demux->last_moov_offset = demux->offset;
6902 /* Update streams with new moov */
6903 demux->old_streams =
6904 g_list_concat (demux->old_streams, demux->active_streams);
6905 demux->active_streams = NULL;
6907 qtdemux_parse_moov (demux, data, demux->neededbytes);
6908 qtdemux_node_dump (demux, demux->moov_node);
6909 qtdemux_parse_tree (demux);
6910 qtdemux_prepare_streams (demux);
6911 QTDEMUX_EXPOSE_LOCK (demux);
6912 qtdemux_expose_streams (demux);
6913 QTDEMUX_EXPOSE_UNLOCK (demux);
6915 demux->got_moov = TRUE;
6917 gst_qtdemux_check_send_pending_segment (demux);
6919 if (demux->moov_node_compressed) {
6920 g_node_destroy (demux->moov_node_compressed);
6921 g_free (demux->moov_node->data);
6923 demux->moov_node_compressed = NULL;
6924 g_node_destroy (demux->moov_node);
6925 demux->moov_node = NULL;
6926 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6928 } else if (fourcc == FOURCC_moof) {
6929 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6931 GstClockTime prev_pts;
6932 guint64 prev_offset;
6933 guint64 adapter_discont_offset, adapter_discont_dist;
6935 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6938 * The timestamp of the moof buffer is relevant as some scenarios
6939 * won't have the initial timestamp in the atoms. Whenever a new
6940 * buffer has started, we get that buffer's PTS and use it as a base
6941 * timestamp for the trun entries.
6943 * To keep track of the current buffer timestamp and starting point
6944 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6945 * from the beggining of the buffer, with the distance and demux->offset
6946 * we know if it is still the same buffer or not.
6948 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6949 prev_offset = demux->offset - dist;
6950 if (demux->fragment_start_offset == -1
6951 || prev_offset > demux->fragment_start_offset) {
6952 demux->fragment_start_offset = prev_offset;
6953 demux->fragment_start = prev_pts;
6954 GST_DEBUG_OBJECT (demux,
6955 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6956 GST_TIME_FORMAT, demux->fragment_start_offset,
6957 GST_TIME_ARGS (demux->fragment_start));
6960 /* We can't use prev_offset() here because this would require
6961 * upstream to set consistent and correct offsets on all buffers
6962 * since the discont. Nothing ever did that in the past and we
6963 * would break backwards compatibility here then.
6964 * Instead take the offset we had at the last discont and count
6965 * the bytes from there. This works with old code as there would
6966 * be no discont between moov and moof, and also works with
6967 * adaptivedemux which correctly sets offset and will set the
6968 * DISCONT flag accordingly when needed.
6970 * We also only do this for upstream TIME segments as otherwise
6971 * there are potential backwards compatibility problems with
6972 * seeking in PUSH mode and upstream providing inconsistent
6974 adapter_discont_offset =
6975 gst_adapter_offset_at_discont (demux->adapter);
6976 adapter_discont_dist =
6977 gst_adapter_distance_from_discont (demux->adapter);
6979 GST_DEBUG_OBJECT (demux,
6980 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6981 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6982 demux->offset, adapter_discont_offset, adapter_discont_dist);
6984 if (demux->upstream_format_is_time) {
6985 demux->moof_offset = adapter_discont_offset;
6986 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6987 demux->moof_offset += adapter_discont_dist;
6988 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6989 demux->moof_offset = demux->offset;
6991 demux->moof_offset = demux->offset;
6994 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6995 demux->moof_offset, NULL)) {
6996 gst_adapter_unmap (demux->adapter);
6997 ret = GST_FLOW_ERROR;
7001 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7002 if (demux->mss_mode && !demux->exposed) {
7003 QTDEMUX_EXPOSE_LOCK (demux);
7004 qtdemux_expose_streams (demux);
7005 QTDEMUX_EXPOSE_UNLOCK (demux);
7008 gst_qtdemux_check_send_pending_segment (demux);
7010 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7012 } else if (fourcc == FOURCC_ftyp) {
7013 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7014 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7015 } else if (fourcc == FOURCC_uuid) {
7016 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7017 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7018 } else if (fourcc == FOURCC_sidx) {
7019 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7020 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7024 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7028 /* [free] and [skip] are padding atoms */
7029 GST_DEBUG_OBJECT (demux,
7030 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7031 GST_FOURCC_ARGS (fourcc));
7034 GST_WARNING_OBJECT (demux,
7035 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7036 GST_FOURCC_ARGS (fourcc));
7037 /* Let's jump that one and go back to initial state */
7041 gst_adapter_unmap (demux->adapter);
7044 if (demux->mdatbuffer && demux->n_streams) {
7045 gsize remaining_data_size = 0;
7047 /* the mdat was before the header */
7048 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7049 demux->n_streams, demux->mdatbuffer);
7050 /* restore our adapter/offset view of things with upstream;
7051 * put preceding buffered data ahead of current moov data.
7052 * This should also handle evil mdat, moov, mdat cases and alike */
7053 gst_adapter_flush (demux->adapter, demux->neededbytes);
7055 /* Store any remaining data after the mdat for later usage */
7056 remaining_data_size = gst_adapter_available (demux->adapter);
7057 if (remaining_data_size > 0) {
7058 g_assert (demux->restoredata_buffer == NULL);
7059 demux->restoredata_buffer =
7060 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7061 demux->restoredata_offset = demux->offset + demux->neededbytes;
7062 GST_DEBUG_OBJECT (demux,
7063 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7064 G_GUINT64_FORMAT, remaining_data_size,
7065 demux->restoredata_offset);
7068 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7069 demux->mdatbuffer = NULL;
7070 demux->offset = demux->mdatoffset;
7071 demux->neededbytes = next_entry_size (demux);
7072 demux->state = QTDEMUX_STATE_MOVIE;
7073 demux->mdatleft = gst_adapter_available (demux->adapter);
7074 demux->mdatsize = demux->mdatleft;
7076 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7077 gst_adapter_flush (demux->adapter, demux->neededbytes);
7079 /* only go back to the mdat if there are samples to play */
7080 if (demux->got_moov && demux->first_mdat != -1
7081 && has_next_entry (demux)) {
7084 /* we need to seek back */
7085 res = qtdemux_seek_offset (demux, demux->first_mdat);
7087 demux->offset = demux->first_mdat;
7089 GST_DEBUG_OBJECT (demux, "Seek back failed");
7092 demux->offset += demux->neededbytes;
7094 demux->neededbytes = 16;
7095 demux->state = QTDEMUX_STATE_INITIAL;
7100 case QTDEMUX_STATE_BUFFER_MDAT:{
7104 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7106 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7107 gst_buffer_extract (buf, 0, fourcc, 4);
7108 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7109 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7110 if (demux->mdatbuffer)
7111 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7113 demux->mdatbuffer = buf;
7114 demux->offset += demux->neededbytes;
7115 demux->neededbytes = 16;
7116 demux->state = QTDEMUX_STATE_INITIAL;
7117 gst_qtdemux_post_progress (demux, 1, 1);
7121 case QTDEMUX_STATE_MOVIE:{
7122 QtDemuxStream *stream = NULL;
7123 QtDemuxSample *sample;
7124 GstClockTime dts, pts, duration;
7128 GST_DEBUG_OBJECT (demux,
7129 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7131 if (demux->fragmented) {
7132 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7134 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7135 /* if needed data starts within this atom,
7136 * then it should not exceed this atom */
7137 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7138 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7139 (_("This file is invalid and cannot be played.")),
7140 ("sample data crosses atom boundary"));
7141 ret = GST_FLOW_ERROR;
7144 demux->mdatleft -= demux->neededbytes;
7146 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7147 /* so we are dropping more than left in this atom */
7148 gst_qtdemux_drop_data (demux, demux->mdatleft);
7149 demux->mdatleft = 0;
7151 /* need to resume atom parsing so we do not miss any other pieces */
7152 demux->state = QTDEMUX_STATE_INITIAL;
7153 demux->neededbytes = 16;
7155 /* check if there was any stored post mdat data from previous buffers */
7156 if (demux->restoredata_buffer) {
7157 g_assert (gst_adapter_available (demux->adapter) == 0);
7159 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7160 demux->restoredata_buffer = NULL;
7161 demux->offset = demux->restoredata_offset;
7168 if (demux->todrop) {
7169 if (demux->cenc_aux_info_offset > 0) {
7173 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7174 data = gst_adapter_map (demux->adapter, demux->todrop);
7175 gst_byte_reader_init (&br, data + 8, demux->todrop);
7176 if (!qtdemux_parse_cenc_aux_info (demux,
7177 QTDEMUX_FIRST_STREAM (demux), &br,
7178 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7179 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7180 ret = GST_FLOW_ERROR;
7181 gst_adapter_unmap (demux->adapter);
7182 g_free (demux->cenc_aux_info_sizes);
7183 demux->cenc_aux_info_sizes = NULL;
7186 demux->cenc_aux_info_offset = 0;
7187 g_free (demux->cenc_aux_info_sizes);
7188 demux->cenc_aux_info_sizes = NULL;
7189 gst_adapter_unmap (demux->adapter);
7191 gst_qtdemux_drop_data (demux, demux->todrop);
7195 /* initial newsegment sent here after having added pads,
7196 * possible others in sink_event */
7197 gst_qtdemux_check_send_pending_segment (demux);
7199 /* Figure out which stream this packet belongs to */
7200 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7201 stream = QTDEMUX_STREAM (iter->data);
7202 if (stream->sample_index >= stream->n_samples) {
7203 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7207 GST_LOG_OBJECT (demux,
7208 "Checking track-id %u (sample_index:%d / offset:%"
7209 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7210 stream->sample_index,
7211 stream->samples[stream->sample_index].offset,
7212 stream->samples[stream->sample_index].size);
7214 if (stream->samples[stream->sample_index].offset == demux->offset)
7218 if (G_UNLIKELY (stream == NULL))
7219 goto unknown_stream;
7221 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7223 if (stream->new_caps) {
7224 gst_qtdemux_configure_stream (demux, stream);
7227 /* Put data in a buffer, set timestamps, caps, ... */
7228 sample = &stream->samples[stream->sample_index];
7230 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7231 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7232 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7234 dts = QTSAMPLE_DTS (stream, sample);
7235 pts = QTSAMPLE_PTS (stream, sample);
7236 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7237 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7239 /* check for segment end */
7240 if (G_UNLIKELY (demux->segment.stop != -1
7241 && demux->segment.stop <= pts && stream->on_keyframe)
7242 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7243 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7244 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7246 /* skip this data, stream is EOS */
7247 gst_adapter_flush (demux->adapter, demux->neededbytes);
7248 demux->offset += demux->neededbytes;
7250 /* check if all streams are eos */
7252 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7253 if (!STREAM_IS_EOS (QTDEMUX_STREAM (iter->data))) {
7262 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7264 /* FIXME: should either be an assert or a plain check */
7265 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7267 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7268 dts, pts, duration, keyframe, dts, demux->offset);
7272 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7274 /* skip this data, stream is EOS */
7275 gst_adapter_flush (demux->adapter, demux->neededbytes);
7278 stream->sample_index++;
7279 stream->offset_in_sample = 0;
7281 /* update current offset and figure out size of next buffer */
7282 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7283 demux->offset, demux->neededbytes);
7284 demux->offset += demux->neededbytes;
7285 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7289 if (ret == GST_FLOW_EOS) {
7290 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7291 demux->neededbytes = -1;
7295 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7296 if (demux->fragmented) {
7297 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7298 /* there may be more to follow, only finish this atom */
7299 demux->todrop = demux->mdatleft;
7300 demux->neededbytes = demux->todrop;
7305 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7306 goto non_ok_unlinked_flow;
7315 /* when buffering movie data, at least show user something is happening */
7316 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7317 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7318 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7319 demux->neededbytes);
7326 non_ok_unlinked_flow:
7328 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7329 gst_flow_get_name (ret));
7334 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7335 ret = GST_FLOW_ERROR;
7340 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7346 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7347 (NULL), ("qtdemuxer invalid state %d", demux->state));
7348 ret = GST_FLOW_ERROR;
7353 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7354 (NULL), ("no 'moov' atom within the first 10 MB"));
7355 ret = GST_FLOW_ERROR;
7361 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7366 query = gst_query_new_scheduling ();
7368 if (!gst_pad_peer_query (sinkpad, query)) {
7369 gst_query_unref (query);
7373 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7374 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7375 gst_query_unref (query);
7380 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7381 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7385 GST_DEBUG_OBJECT (sinkpad, "activating push");
7386 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7391 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7392 GstPadMode mode, gboolean active)
7395 GstQTDemux *demux = GST_QTDEMUX (parent);
7398 case GST_PAD_MODE_PUSH:
7399 demux->pullbased = FALSE;
7402 case GST_PAD_MODE_PULL:
7404 demux->pullbased = TRUE;
7405 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7408 res = gst_pad_stop_task (sinkpad);
7420 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7426 memset (&z, 0, sizeof (z));
7431 if ((ret = inflateInit (&z)) != Z_OK) {
7432 GST_ERROR ("inflateInit() returned %d", ret);
7436 z.next_in = z_buffer;
7437 z.avail_in = z_length;
7439 buffer = (guint8 *) g_malloc (*length);
7440 z.avail_out = *length;
7441 z.next_out = (Bytef *) buffer;
7443 ret = inflate (&z, Z_NO_FLUSH);
7444 if (ret == Z_STREAM_END) {
7446 } else if (ret != Z_OK) {
7447 GST_WARNING ("inflate() returned %d", ret);
7452 buffer = (guint8 *) g_realloc (buffer, *length);
7453 z.next_out = (Bytef *) (buffer + z.total_out);
7454 z.avail_out += 4096;
7455 } while (z.avail_in > 0);
7457 if (ret != Z_STREAM_END) {
7462 *length = z.total_out;
7469 #endif /* HAVE_ZLIB */
7472 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7476 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7478 /* counts as header data */
7479 qtdemux->header_size += length;
7481 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7482 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7484 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7491 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7492 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7493 if (dcom == NULL || cmvd == NULL)
7494 goto invalid_compression;
7496 dcom_len = QT_UINT32 (dcom->data);
7498 goto invalid_compression;
7500 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7504 guint uncompressed_length;
7505 guint compressed_length;
7509 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7511 goto invalid_compression;
7513 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7514 compressed_length = cmvd_len - 12;
7515 GST_LOG ("length = %u", uncompressed_length);
7518 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7519 compressed_length, &uncompressed_length);
7522 qtdemux->moov_node_compressed = qtdemux->moov_node;
7523 qtdemux->moov_node = g_node_new (buf);
7525 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7526 uncompressed_length);
7530 #endif /* HAVE_ZLIB */
7532 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7533 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7540 invalid_compression:
7542 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7548 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7551 while (G_UNLIKELY (buf < end)) {
7555 if (G_UNLIKELY (buf + 4 > end)) {
7556 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7559 len = QT_UINT32 (buf);
7560 if (G_UNLIKELY (len == 0)) {
7561 GST_LOG_OBJECT (qtdemux, "empty container");
7564 if (G_UNLIKELY (len < 8)) {
7565 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7568 if (G_UNLIKELY (len > (end - buf))) {
7569 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7570 (gint) (end - buf));
7574 child = g_node_new ((guint8 *) buf);
7575 g_node_append (node, child);
7576 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7577 qtdemux_parse_node (qtdemux, child, buf, len);
7585 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7588 int len = QT_UINT32 (xdxt->data);
7589 guint8 *buf = xdxt->data;
7590 guint8 *end = buf + len;
7593 /* skip size and type */
7601 size = QT_UINT32 (buf);
7602 type = QT_FOURCC (buf + 4);
7604 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7606 if (buf + size > end || size <= 0)
7612 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7613 GST_FOURCC_ARGS (type));
7617 buffer = gst_buffer_new_and_alloc (size);
7618 gst_buffer_fill (buffer, 0, buf, size);
7619 stream->buffers = g_slist_append (stream->buffers, buffer);
7620 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7623 buffer = gst_buffer_new_and_alloc (size);
7624 gst_buffer_fill (buffer, 0, buf, size);
7625 stream->buffers = g_slist_append (stream->buffers, buffer);
7626 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7629 buffer = gst_buffer_new_and_alloc (size);
7630 gst_buffer_fill (buffer, 0, buf, size);
7631 stream->buffers = g_slist_append (stream->buffers, buffer);
7632 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7635 GST_WARNING_OBJECT (qtdemux,
7636 "unknown theora cookie %" GST_FOURCC_FORMAT,
7637 GST_FOURCC_ARGS (type));
7646 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7650 guint32 node_length = 0;
7651 const QtNodeType *type;
7654 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7656 if (G_UNLIKELY (length < 8))
7657 goto not_enough_data;
7659 node_length = QT_UINT32 (buffer);
7660 fourcc = QT_FOURCC (buffer + 4);
7662 /* ignore empty nodes */
7663 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7666 type = qtdemux_type_get (fourcc);
7668 end = buffer + length;
7670 GST_LOG_OBJECT (qtdemux,
7671 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7672 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7674 if (node_length > length)
7675 goto broken_atom_size;
7677 if (type->flags & QT_FLAG_CONTAINER) {
7678 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7683 if (node_length < 20) {
7684 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7687 GST_DEBUG_OBJECT (qtdemux,
7688 "parsing stsd (sample table, sample description) atom");
7689 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7690 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7701 /* also read alac (or whatever) in stead of mp4a in the following,
7702 * since a similar layout is used in other cases as well */
7703 if (fourcc == FOURCC_mp4a)
7705 else if (fourcc == FOURCC_fLaC)
7710 /* There are two things we might encounter here: a true mp4a atom, and
7711 an mp4a entry in an stsd atom. The latter is what we're interested
7712 in, and it looks like an atom, but isn't really one. The true mp4a
7713 atom is short, so we detect it based on length here. */
7714 if (length < min_size) {
7715 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7716 GST_FOURCC_ARGS (fourcc));
7720 /* 'version' here is the sound sample description version. Types 0 and
7721 1 are documented in the QTFF reference, but type 2 is not: it's
7722 described in Apple header files instead (struct SoundDescriptionV2
7724 version = QT_UINT16 (buffer + 16);
7726 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7727 GST_FOURCC_ARGS (fourcc), version);
7729 /* parse any esds descriptors */
7741 GST_WARNING_OBJECT (qtdemux,
7742 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7743 GST_FOURCC_ARGS (fourcc), version);
7748 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7774 /* codec_data is contained inside these atoms, which all have
7775 * the same format. */
7776 /* video sample description size is 86 bytes without extension.
7777 * node_length have to be bigger than 86 bytes because video sample
7778 * description can include extenstions such as esds, fiel, glbl, etc. */
7779 if (node_length < 86) {
7780 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7781 " sample description length too short (%u < 86)",
7782 GST_FOURCC_ARGS (fourcc), node_length);
7786 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7787 GST_FOURCC_ARGS (fourcc));
7789 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7791 * revision level (2 bytes) : must be set to 0. */
7792 version = QT_UINT32 (buffer + 16);
7793 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7795 /* compressor name : PASCAL string and informative purposes
7796 * first byte : the number of bytes to be displayed.
7797 * it has to be less than 32 because it is reserved
7798 * space of 32 bytes total including itself. */
7799 str_len = QT_UINT8 (buffer + 50);
7801 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7802 (char *) buffer + 51);
7804 GST_WARNING_OBJECT (qtdemux,
7805 "compressorname length too big (%u > 31)", str_len);
7807 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7809 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7814 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7816 /* You are reading this correctly. QTFF specifies that the
7817 * metadata atom is a short atom, whereas ISO BMFF specifies
7818 * it's a full atom. But since so many people are doing things
7819 * differently, we actually peek into the atom to see which
7822 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7823 GST_FOURCC_ARGS (fourcc));
7826 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7827 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7828 * starts with a 'hdlr' atom */
7829 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7830 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7831 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7832 * with version/flags both set to zero */
7833 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7835 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7840 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7841 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7842 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7851 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7852 GST_FOURCC_ARGS (fourcc));
7856 version = QT_UINT32 (buffer + 12);
7857 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7864 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7869 if (length < offset) {
7870 GST_WARNING_OBJECT (qtdemux,
7871 "skipping too small %" GST_FOURCC_FORMAT " box",
7872 GST_FOURCC_ARGS (fourcc));
7875 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7881 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7886 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7891 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7895 if (!strcmp (type->name, "unknown"))
7896 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7900 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7901 GST_FOURCC_ARGS (fourcc));
7907 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7908 (_("This file is corrupt and cannot be played.")),
7909 ("Not enough data for an atom header, got only %u bytes", length));
7914 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7915 (_("This file is corrupt and cannot be played.")),
7916 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7917 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7924 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7928 guint32 child_fourcc;
7930 for (child = g_node_first_child (node); child;
7931 child = g_node_next_sibling (child)) {
7932 buffer = (guint8 *) child->data;
7934 child_fourcc = QT_FOURCC (buffer + 4);
7936 if (G_UNLIKELY (child_fourcc == fourcc)) {
7944 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7945 GstByteReader * parser)
7949 guint32 child_fourcc, child_len;
7951 for (child = g_node_first_child (node); child;
7952 child = g_node_next_sibling (child)) {
7953 buffer = (guint8 *) child->data;
7955 child_len = QT_UINT32 (buffer);
7956 child_fourcc = QT_FOURCC (buffer + 4);
7958 if (G_UNLIKELY (child_fourcc == fourcc)) {
7959 if (G_UNLIKELY (child_len < (4 + 4)))
7961 /* FIXME: must verify if atom length < parent atom length */
7962 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7970 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7972 return g_node_nth_child (node, index);
7976 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7977 GstByteReader * parser)
7981 guint32 child_fourcc, child_len;
7983 for (child = g_node_next_sibling (node); child;
7984 child = g_node_next_sibling (child)) {
7985 buffer = (guint8 *) child->data;
7987 child_fourcc = QT_FOURCC (buffer + 4);
7989 if (child_fourcc == fourcc) {
7991 child_len = QT_UINT32 (buffer);
7992 if (G_UNLIKELY (child_len < (4 + 4)))
7994 /* FIXME: must verify if atom length < parent atom length */
7995 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8004 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8006 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8010 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8012 /* FIXME: This can only reliably work if demuxers have a
8013 * separate streaming thread per srcpad. This should be
8014 * done in a demuxer base class, which integrates parts
8017 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8022 query = gst_query_new_allocation (stream->caps, FALSE);
8024 if (!gst_pad_peer_query (stream->pad, query)) {
8025 /* not a problem, just debug a little */
8026 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8029 if (stream->allocator)
8030 gst_object_unref (stream->allocator);
8032 if (gst_query_get_n_allocation_params (query) > 0) {
8033 /* try the allocator */
8034 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8036 stream->use_allocator = TRUE;
8038 stream->allocator = NULL;
8039 gst_allocation_params_init (&stream->params);
8040 stream->use_allocator = FALSE;
8042 gst_query_unref (query);
8047 pad_query (const GValue * item, GValue * value, gpointer user_data)
8049 GstPad *pad = g_value_get_object (item);
8050 GstQuery *query = user_data;
8053 res = gst_pad_peer_query (pad, query);
8056 g_value_set_boolean (value, TRUE);
8060 GST_INFO_OBJECT (pad, "pad peer query failed");
8065 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8066 GstPadDirection direction)
8069 GstIteratorFoldFunction func = pad_query;
8070 GValue res = { 0, };
8072 g_value_init (&res, G_TYPE_BOOLEAN);
8073 g_value_set_boolean (&res, FALSE);
8076 if (direction == GST_PAD_SRC)
8077 it = gst_element_iterate_src_pads (element);
8079 it = gst_element_iterate_sink_pads (element);
8081 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8082 gst_iterator_resync (it);
8084 gst_iterator_free (it);
8086 return g_value_get_boolean (&res);
8090 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8091 QtDemuxStream * stream)
8095 GstElement *element = GST_ELEMENT (qtdemux);
8097 gchar **filtered_sys_ids;
8098 GValue event_list = G_VALUE_INIT;
8101 /* 1. Check if we already have the context. */
8102 if (qtdemux->preferred_protection_system_id != NULL) {
8103 GST_LOG_OBJECT (element,
8104 "already have the protection context, no need to request it again");
8108 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8109 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8110 (const gchar **) qtdemux->protection_system_ids->pdata);
8112 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8113 qtdemux->protection_system_ids->len - 1);
8114 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8115 "decryptors for %u of them, running context request",
8116 qtdemux->protection_system_ids->len,
8117 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8120 if (stream->protection_scheme_event_queue.length) {
8121 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8122 stream->protection_scheme_event_queue.length);
8123 walk = stream->protection_scheme_event_queue.tail;
8125 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8126 qtdemux->protection_event_queue.length);
8127 walk = qtdemux->protection_event_queue.tail;
8130 g_value_init (&event_list, GST_TYPE_LIST);
8131 for (; walk; walk = g_list_previous (walk)) {
8132 GValue *event_value = g_new0 (GValue, 1);
8133 g_value_init (event_value, GST_TYPE_EVENT);
8134 g_value_set_boxed (event_value, walk->data);
8135 gst_value_list_append_and_take_value (&event_list, event_value);
8138 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8139 * check if downstream already has a context of the specific type
8140 * 2b) Query upstream as above.
8142 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8143 st = gst_query_writable_structure (query);
8144 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8145 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8147 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8148 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8149 gst_query_parse_context (query, &ctxt);
8150 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8151 gst_element_set_context (element, ctxt);
8152 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8153 gst_query_parse_context (query, &ctxt);
8154 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8155 gst_element_set_context (element, ctxt);
8157 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8158 * the required context type and afterwards check if a
8159 * usable context was set now as in 1). The message could
8160 * be handled by the parent bins of the element and the
8165 GST_INFO_OBJECT (element, "posting need context message");
8166 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8167 "drm-preferred-decryption-system-id");
8168 st = (GstStructure *) gst_message_get_structure (msg);
8169 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8170 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8173 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8174 gst_element_post_message (element, msg);
8177 g_strfreev (filtered_sys_ids);
8178 g_value_unset (&event_list);
8179 gst_query_unref (query);
8183 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8184 QtDemuxStream * stream)
8187 const gchar *selected_system = NULL;
8189 g_return_val_if_fail (qtdemux != NULL, FALSE);
8190 g_return_val_if_fail (stream != NULL, FALSE);
8191 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8194 if (stream->protection_scheme_type != FOURCC_cenc) {
8195 GST_ERROR_OBJECT (qtdemux,
8196 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8197 GST_FOURCC_ARGS (stream->protection_scheme_type));
8200 if (qtdemux->protection_system_ids == NULL) {
8201 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8202 "cenc protection system information has been found");
8206 gst_qtdemux_request_protection_context (qtdemux, stream);
8207 if (qtdemux->preferred_protection_system_id != NULL) {
8208 const gchar *preferred_system_array[] =
8209 { qtdemux->preferred_protection_system_id, NULL };
8211 selected_system = gst_protection_select_system (preferred_system_array);
8213 if (selected_system) {
8214 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8215 qtdemux->preferred_protection_system_id);
8217 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8218 "because there is no available decryptor",
8219 qtdemux->preferred_protection_system_id);
8223 if (!selected_system) {
8224 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8225 selected_system = gst_protection_select_system ((const gchar **)
8226 qtdemux->protection_system_ids->pdata);
8227 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8228 qtdemux->protection_system_ids->len - 1);
8231 if (!selected_system) {
8232 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8233 "suitable decryptor element has been found");
8237 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8240 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8241 if (!gst_structure_has_name (s, "application/x-cenc")) {
8242 gst_structure_set (s,
8243 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8244 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8246 gst_structure_set_name (s, "application/x-cenc");
8252 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8254 if (stream->subtype == FOURCC_vide) {
8255 /* fps is calculated base on the duration of the average framerate since
8256 * qt does not have a fixed framerate. */
8257 gboolean fps_available = TRUE;
8258 guint32 first_duration = 0;
8260 if (stream->n_samples > 0)
8261 first_duration = stream->samples[0].duration;
8263 if ((stream->n_samples == 1 && first_duration == 0)
8264 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8266 CUR_STREAM (stream)->fps_n = 0;
8267 CUR_STREAM (stream)->fps_d = 1;
8269 if (stream->duration == 0 || stream->n_samples < 2) {
8270 CUR_STREAM (stream)->fps_n = stream->timescale;
8271 CUR_STREAM (stream)->fps_d = 1;
8272 fps_available = FALSE;
8274 GstClockTime avg_duration;
8278 /* duration and n_samples can be updated for fragmented format
8279 * so, framerate of fragmented format is calculated using data in a moof */
8280 if (qtdemux->fragmented && stream->n_samples_moof > 0
8281 && stream->duration_moof > 0) {
8282 n_samples = stream->n_samples_moof;
8283 duration = stream->duration_moof;
8285 n_samples = stream->n_samples;
8286 duration = stream->duration;
8289 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8290 /* stream->duration is guint64, timescale, n_samples are guint32 */
8292 gst_util_uint64_scale_round (duration -
8293 first_duration, GST_SECOND,
8294 (guint64) (stream->timescale) * (n_samples - 1));
8296 GST_LOG_OBJECT (qtdemux,
8297 "Calculating avg sample duration based on stream (or moof) duration %"
8299 " minus first sample %u, leaving %d samples gives %"
8300 GST_TIME_FORMAT, duration, first_duration,
8301 n_samples - 1, GST_TIME_ARGS (avg_duration));
8303 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8304 &CUR_STREAM (stream)->fps_d);
8306 GST_DEBUG_OBJECT (qtdemux,
8307 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8308 stream->timescale, CUR_STREAM (stream)->fps_n,
8309 CUR_STREAM (stream)->fps_d);
8313 if (CUR_STREAM (stream)->caps) {
8314 CUR_STREAM (stream)->caps =
8315 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8317 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8318 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8319 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8320 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8322 /* set framerate if calculated framerate is reliable */
8323 if (fps_available) {
8324 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8325 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8326 CUR_STREAM (stream)->fps_d, NULL);
8329 /* calculate pixel-aspect-ratio using display width and height */
8330 GST_DEBUG_OBJECT (qtdemux,
8331 "video size %dx%d, target display size %dx%d",
8332 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8333 stream->display_width, stream->display_height);
8334 /* qt file might have pasp atom */
8335 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8336 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8337 CUR_STREAM (stream)->par_h);
8338 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8339 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8340 CUR_STREAM (stream)->par_h, NULL);
8341 } else if (stream->display_width > 0 && stream->display_height > 0
8342 && CUR_STREAM (stream)->width > 0
8343 && CUR_STREAM (stream)->height > 0) {
8346 /* calculate the pixel aspect ratio using the display and pixel w/h */
8347 n = stream->display_width * CUR_STREAM (stream)->height;
8348 d = stream->display_height * CUR_STREAM (stream)->width;
8351 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8352 CUR_STREAM (stream)->par_w = n;
8353 CUR_STREAM (stream)->par_h = d;
8354 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8355 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8356 CUR_STREAM (stream)->par_h, NULL);
8359 if (CUR_STREAM (stream)->interlace_mode > 0) {
8360 if (CUR_STREAM (stream)->interlace_mode == 1) {
8361 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8362 G_TYPE_STRING, "progressive", NULL);
8363 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8364 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8365 G_TYPE_STRING, "interleaved", NULL);
8366 if (CUR_STREAM (stream)->field_order == 9) {
8367 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8368 G_TYPE_STRING, "top-field-first", NULL);
8369 } else if (CUR_STREAM (stream)->field_order == 14) {
8370 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8371 G_TYPE_STRING, "bottom-field-first", NULL);
8376 /* Create incomplete colorimetry here if needed */
8377 if (CUR_STREAM (stream)->colorimetry.range ||
8378 CUR_STREAM (stream)->colorimetry.matrix ||
8379 CUR_STREAM (stream)->colorimetry.transfer
8380 || CUR_STREAM (stream)->colorimetry.primaries) {
8381 gchar *colorimetry =
8382 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8383 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8384 G_TYPE_STRING, colorimetry, NULL);
8385 g_free (colorimetry);
8388 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8389 guint par_w = 1, par_h = 1;
8391 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8392 par_w = CUR_STREAM (stream)->par_w;
8393 par_h = CUR_STREAM (stream)->par_h;
8396 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8397 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8399 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8402 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8403 "multiview-mode", G_TYPE_STRING,
8404 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8405 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8406 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8411 else if (stream->subtype == FOURCC_soun) {
8412 if (CUR_STREAM (stream)->caps) {
8413 CUR_STREAM (stream)->caps =
8414 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8415 if (CUR_STREAM (stream)->rate > 0)
8416 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8417 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8418 if (CUR_STREAM (stream)->n_channels > 0)
8419 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8420 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8421 if (CUR_STREAM (stream)->n_channels > 2) {
8422 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8423 * correctly; this is just the minimum we can do - assume
8424 * we don't actually have any channel positions. */
8425 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8426 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8432 GstCaps *prev_caps = NULL;
8434 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8435 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8436 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8437 gst_pad_set_active (stream->pad, TRUE);
8439 gst_pad_use_fixed_caps (stream->pad);
8441 if (stream->protected) {
8442 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8443 GST_ERROR_OBJECT (qtdemux,
8444 "Failed to configure protected stream caps.");
8449 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8450 CUR_STREAM (stream)->caps);
8451 if (stream->new_stream) {
8453 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8456 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8459 gst_event_parse_stream_flags (event, &stream_flags);
8460 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8461 qtdemux->have_group_id = TRUE;
8463 qtdemux->have_group_id = FALSE;
8464 gst_event_unref (event);
8465 } else if (!qtdemux->have_group_id) {
8466 qtdemux->have_group_id = TRUE;
8467 qtdemux->group_id = gst_util_group_id_next ();
8470 stream->new_stream = FALSE;
8471 event = gst_event_new_stream_start (stream->stream_id);
8472 if (qtdemux->have_group_id)
8473 gst_event_set_group_id (event, qtdemux->group_id);
8474 if (stream->disabled)
8475 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8476 if (CUR_STREAM (stream)->sparse) {
8477 stream_flags |= GST_STREAM_FLAG_SPARSE;
8479 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8481 gst_event_set_stream_flags (event, stream_flags);
8482 gst_pad_push_event (stream->pad, event);
8485 prev_caps = gst_pad_get_current_caps (stream->pad);
8487 if (CUR_STREAM (stream)->caps) {
8489 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8490 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8491 CUR_STREAM (stream)->caps);
8492 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8494 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8497 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8501 gst_caps_unref (prev_caps);
8502 stream->new_caps = FALSE;
8508 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8509 QtDemuxStream * stream)
8511 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8514 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8515 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8516 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8517 stream->stsd_entries_length)) {
8518 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8519 (_("This file is invalid and cannot be played.")),
8520 ("New sample description id is out of bounds (%d >= %d)",
8521 stream->stsd_sample_description_id, stream->stsd_entries_length));
8523 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8524 stream->new_caps = TRUE;
8529 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8530 QtDemuxStream * stream, GstTagList * list)
8532 gboolean ret = TRUE;
8533 /* consistent default for push based mode */
8534 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8536 if (stream->subtype == FOURCC_vide) {
8537 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8540 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8543 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8544 gst_object_unref (stream->pad);
8550 qtdemux->n_video_streams++;
8551 } else if (stream->subtype == FOURCC_soun) {
8552 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8555 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8557 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8558 gst_object_unref (stream->pad);
8563 qtdemux->n_audio_streams++;
8564 } else if (stream->subtype == FOURCC_strm) {
8565 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8566 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8567 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8568 || stream->subtype == FOURCC_clcp) {
8569 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8572 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8574 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8575 gst_object_unref (stream->pad);
8580 qtdemux->n_sub_streams++;
8581 } else if (CUR_STREAM (stream)->caps) {
8582 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8585 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8587 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8588 gst_object_unref (stream->pad);
8593 qtdemux->n_video_streams++;
8595 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8602 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8603 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8604 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8605 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8607 if (stream->stream_tags)
8608 gst_tag_list_unref (stream->stream_tags);
8609 stream->stream_tags = list;
8611 /* global tags go on each pad anyway */
8612 stream->send_global_tags = TRUE;
8613 /* send upstream GST_EVENT_PROTECTION events that were received before
8614 this source pad was created */
8615 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8616 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8620 gst_tag_list_unref (list);
8624 /* find next atom with @fourcc starting at @offset */
8625 static GstFlowReturn
8626 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8627 guint64 * length, guint32 fourcc)
8633 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8634 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8640 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8641 if (G_UNLIKELY (ret != GST_FLOW_OK))
8643 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8646 gst_buffer_unref (buf);
8649 gst_buffer_map (buf, &map, GST_MAP_READ);
8650 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8651 gst_buffer_unmap (buf, &map);
8652 gst_buffer_unref (buf);
8654 if (G_UNLIKELY (*length == 0)) {
8655 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8656 ret = GST_FLOW_ERROR;
8660 if (lfourcc == fourcc) {
8661 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8665 GST_LOG_OBJECT (qtdemux,
8666 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8667 GST_FOURCC_ARGS (fourcc), *offset);
8676 /* might simply have had last one */
8677 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8682 /* should only do something in pull mode */
8683 /* call with OBJECT lock */
8684 static GstFlowReturn
8685 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8687 guint64 length, offset;
8688 GstBuffer *buf = NULL;
8689 GstFlowReturn ret = GST_FLOW_OK;
8690 GstFlowReturn res = GST_FLOW_OK;
8693 offset = qtdemux->moof_offset;
8694 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8697 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8698 return GST_FLOW_EOS;
8701 /* best not do pull etc with lock held */
8702 GST_OBJECT_UNLOCK (qtdemux);
8704 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8705 if (ret != GST_FLOW_OK)
8708 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8709 if (G_UNLIKELY (ret != GST_FLOW_OK))
8711 gst_buffer_map (buf, &map, GST_MAP_READ);
8712 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8713 gst_buffer_unmap (buf, &map);
8714 gst_buffer_unref (buf);
8719 gst_buffer_unmap (buf, &map);
8720 gst_buffer_unref (buf);
8724 /* look for next moof */
8725 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8726 if (G_UNLIKELY (ret != GST_FLOW_OK))
8730 GST_OBJECT_LOCK (qtdemux);
8732 qtdemux->moof_offset = offset;
8738 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8740 res = GST_FLOW_ERROR;
8745 /* maybe upstream temporarily flushing */
8746 if (ret != GST_FLOW_FLUSHING) {
8747 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8750 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8751 /* resume at current position next time */
8758 /* initialise bytereaders for stbl sub-atoms */
8760 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8762 stream->stbl_index = -1; /* no samples have yet been parsed */
8763 stream->sample_index = -1;
8765 /* time-to-sample atom */
8766 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8769 /* copy atom data into a new buffer for later use */
8770 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8772 /* skip version + flags */
8773 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8774 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8776 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8778 /* make sure there's enough data */
8779 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8780 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8781 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8782 stream->n_sample_times);
8783 if (!stream->n_sample_times)
8787 /* sync sample atom */
8788 stream->stps_present = FALSE;
8789 if ((stream->stss_present =
8790 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8791 &stream->stss) ? TRUE : FALSE) == TRUE) {
8792 /* copy atom data into a new buffer for later use */
8793 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8795 /* skip version + flags */
8796 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8797 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8800 if (stream->n_sample_syncs) {
8801 /* make sure there's enough data */
8802 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8806 /* partial sync sample atom */
8807 if ((stream->stps_present =
8808 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8809 &stream->stps) ? TRUE : FALSE) == TRUE) {
8810 /* copy atom data into a new buffer for later use */
8811 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8813 /* skip version + flags */
8814 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8815 !gst_byte_reader_get_uint32_be (&stream->stps,
8816 &stream->n_sample_partial_syncs))
8819 /* if there are no entries, the stss table contains the real
8821 if (stream->n_sample_partial_syncs) {
8822 /* make sure there's enough data */
8823 if (!qt_atom_parser_has_chunks (&stream->stps,
8824 stream->n_sample_partial_syncs, 4))
8831 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8834 /* copy atom data into a new buffer for later use */
8835 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8837 /* skip version + flags */
8838 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8839 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8842 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8845 if (!stream->n_samples)
8848 /* sample-to-chunk atom */
8849 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8852 /* copy atom data into a new buffer for later use */
8853 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8855 /* skip version + flags */
8856 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8857 !gst_byte_reader_get_uint32_be (&stream->stsc,
8858 &stream->n_samples_per_chunk))
8861 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8862 stream->n_samples_per_chunk);
8864 /* make sure there's enough data */
8865 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8871 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8872 stream->co_size = sizeof (guint32);
8873 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8875 stream->co_size = sizeof (guint64);
8879 /* copy atom data into a new buffer for later use */
8880 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8882 /* skip version + flags */
8883 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8886 /* chunks_are_samples == TRUE means treat chunks as samples */
8887 stream->chunks_are_samples = stream->sample_size
8888 && !CUR_STREAM (stream)->sampled;
8889 if (stream->chunks_are_samples) {
8890 /* treat chunks as samples */
8891 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8894 /* skip number of entries */
8895 if (!gst_byte_reader_skip (&stream->stco, 4))
8898 /* make sure there are enough data in the stsz atom */
8899 if (!stream->sample_size) {
8900 /* different sizes for each sample */
8901 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8906 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8907 stream->n_samples, (guint) sizeof (QtDemuxSample),
8908 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8910 if (stream->n_samples >=
8911 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8912 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8913 "be larger than %uMB (broken file?)", stream->n_samples,
8914 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8918 g_assert (stream->samples == NULL);
8919 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8920 if (!stream->samples) {
8921 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8926 /* composition time-to-sample */
8927 if ((stream->ctts_present =
8928 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8929 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8930 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8932 /* copy atom data into a new buffer for later use */
8933 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8935 /* skip version + flags */
8936 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8937 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8938 &stream->n_composition_times))
8941 /* make sure there's enough data */
8942 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8946 /* This is optional, if missing we iterate the ctts */
8947 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8948 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8949 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8950 g_free ((gpointer) cslg.data);
8954 gint32 cslg_least = 0;
8955 guint num_entries, pos;
8958 pos = gst_byte_reader_get_pos (&stream->ctts);
8959 num_entries = stream->n_composition_times;
8961 stream->cslg_shift = 0;
8963 for (i = 0; i < num_entries; i++) {
8966 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8967 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8969 if (offset < cslg_least)
8970 cslg_least = offset;
8974 stream->cslg_shift = ABS (cslg_least);
8976 stream->cslg_shift = 0;
8978 /* reset the reader so we can generate sample table */
8979 gst_byte_reader_set_pos (&stream->ctts, pos);
8982 /* Ensure the cslg_shift value is consistent so we can use it
8983 * unconditionnally to produce TS and Segment */
8984 stream->cslg_shift = 0;
8991 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8992 (_("This file is corrupt and cannot be played.")), (NULL));
8997 gst_qtdemux_stbl_free (stream);
8998 if (!qtdemux->fragmented) {
8999 /* not quite good */
9000 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9003 /* may pick up samples elsewhere */
9009 /* collect samples from the next sample to be parsed up to sample @n for @stream
9010 * by reading the info from @stbl
9012 * This code can be executed from both the streaming thread and the seeking
9013 * thread so it takes the object lock to protect itself
9016 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9019 QtDemuxSample *samples, *first, *cur, *last;
9020 guint32 n_samples_per_chunk;
9023 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9024 GST_FOURCC_FORMAT ", pad %s",
9025 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9026 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9028 n_samples = stream->n_samples;
9031 goto out_of_samples;
9033 GST_OBJECT_LOCK (qtdemux);
9034 if (n <= stream->stbl_index)
9035 goto already_parsed;
9037 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9039 if (!stream->stsz.data) {
9040 /* so we already parsed and passed all the moov samples;
9041 * onto fragmented ones */
9042 g_assert (qtdemux->fragmented);
9046 /* pointer to the sample table */
9047 samples = stream->samples;
9049 /* starts from -1, moves to the next sample index to parse */
9050 stream->stbl_index++;
9052 /* keep track of the first and last sample to fill */
9053 first = &samples[stream->stbl_index];
9056 if (!stream->chunks_are_samples) {
9057 /* set the sample sizes */
9058 if (stream->sample_size == 0) {
9059 /* different sizes for each sample */
9060 for (cur = first; cur <= last; cur++) {
9061 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9062 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9063 (guint) (cur - samples), cur->size);
9066 /* samples have the same size */
9067 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9068 for (cur = first; cur <= last; cur++)
9069 cur->size = stream->sample_size;
9073 n_samples_per_chunk = stream->n_samples_per_chunk;
9076 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9079 if (stream->stsc_chunk_index >= stream->last_chunk
9080 || stream->stsc_chunk_index < stream->first_chunk) {
9081 stream->first_chunk =
9082 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9083 stream->samples_per_chunk =
9084 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9086 stream->stsd_sample_description_id =
9087 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9089 /* chunk numbers are counted from 1 it seems */
9090 if (G_UNLIKELY (stream->first_chunk == 0))
9093 --stream->first_chunk;
9095 /* the last chunk of each entry is calculated by taking the first chunk
9096 * of the next entry; except if there is no next, where we fake it with
9098 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9099 stream->last_chunk = G_MAXUINT32;
9101 stream->last_chunk =
9102 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9103 if (G_UNLIKELY (stream->last_chunk == 0))
9106 --stream->last_chunk;
9109 GST_LOG_OBJECT (qtdemux,
9110 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9111 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9112 stream->samples_per_chunk, stream->stsd_sample_description_id);
9114 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9117 if (stream->last_chunk != G_MAXUINT32) {
9118 if (!qt_atom_parser_peek_sub (&stream->stco,
9119 stream->first_chunk * stream->co_size,
9120 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9125 stream->co_chunk = stream->stco;
9126 if (!gst_byte_reader_skip (&stream->co_chunk,
9127 stream->first_chunk * stream->co_size))
9131 stream->stsc_chunk_index = stream->first_chunk;
9134 last_chunk = stream->last_chunk;
9136 if (stream->chunks_are_samples) {
9137 cur = &samples[stream->stsc_chunk_index];
9139 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9142 stream->stsc_chunk_index = j;
9147 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9150 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9151 "%" G_GUINT64_FORMAT, j, cur->offset);
9153 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9154 CUR_STREAM (stream)->bytes_per_frame > 0) {
9156 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9157 CUR_STREAM (stream)->samples_per_frame *
9158 CUR_STREAM (stream)->bytes_per_frame;
9160 cur->size = stream->samples_per_chunk;
9163 GST_DEBUG_OBJECT (qtdemux,
9164 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9165 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9166 stream->stco_sample_index)), cur->size);
9168 cur->timestamp = stream->stco_sample_index;
9169 cur->duration = stream->samples_per_chunk;
9170 cur->keyframe = TRUE;
9173 stream->stco_sample_index += stream->samples_per_chunk;
9175 stream->stsc_chunk_index = j;
9177 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9178 guint32 samples_per_chunk;
9179 guint64 chunk_offset;
9181 if (!stream->stsc_sample_index
9182 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9183 &stream->chunk_offset))
9186 samples_per_chunk = stream->samples_per_chunk;
9187 chunk_offset = stream->chunk_offset;
9189 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9190 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9191 G_GUINT64_FORMAT " and size %d",
9192 (guint) (cur - samples), chunk_offset, cur->size);
9194 cur->offset = chunk_offset;
9195 chunk_offset += cur->size;
9198 if (G_UNLIKELY (cur > last)) {
9200 stream->stsc_sample_index = k + 1;
9201 stream->chunk_offset = chunk_offset;
9202 stream->stsc_chunk_index = j;
9206 stream->stsc_sample_index = 0;
9208 stream->stsc_chunk_index = j;
9210 stream->stsc_index++;
9213 if (stream->chunks_are_samples)
9217 guint32 n_sample_times;
9219 n_sample_times = stream->n_sample_times;
9222 for (i = stream->stts_index; i < n_sample_times; i++) {
9223 guint32 stts_samples;
9224 gint32 stts_duration;
9227 if (stream->stts_sample_index >= stream->stts_samples
9228 || !stream->stts_sample_index) {
9230 stream->stts_samples =
9231 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9232 stream->stts_duration =
9233 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9235 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9236 i, stream->stts_samples, stream->stts_duration);
9238 stream->stts_sample_index = 0;
9241 stts_samples = stream->stts_samples;
9242 stts_duration = stream->stts_duration;
9243 stts_time = stream->stts_time;
9245 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9246 GST_DEBUG_OBJECT (qtdemux,
9247 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9248 (guint) (cur - samples), j,
9249 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9251 cur->timestamp = stts_time;
9252 cur->duration = stts_duration;
9254 /* avoid 32-bit wrap-around,
9255 * but still mind possible 'negative' duration */
9256 stts_time += (gint64) stts_duration;
9259 if (G_UNLIKELY (cur > last)) {
9261 stream->stts_time = stts_time;
9262 stream->stts_sample_index = j + 1;
9263 if (stream->stts_sample_index >= stream->stts_samples)
9264 stream->stts_index++;
9268 stream->stts_sample_index = 0;
9269 stream->stts_time = stts_time;
9270 stream->stts_index++;
9272 /* fill up empty timestamps with the last timestamp, this can happen when
9273 * the last samples do not decode and so we don't have timestamps for them.
9274 * We however look at the last timestamp to estimate the track length so we
9275 * need something in here. */
9276 for (; cur < last; cur++) {
9277 GST_DEBUG_OBJECT (qtdemux,
9278 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9279 (guint) (cur - samples),
9280 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9281 cur->timestamp = stream->stts_time;
9287 /* sample sync, can be NULL */
9288 if (stream->stss_present == TRUE) {
9289 guint32 n_sample_syncs;
9291 n_sample_syncs = stream->n_sample_syncs;
9293 if (!n_sample_syncs) {
9294 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9295 stream->all_keyframe = TRUE;
9297 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9298 /* note that the first sample is index 1, not 0 */
9301 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9303 if (G_LIKELY (index > 0 && index <= n_samples)) {
9305 samples[index].keyframe = TRUE;
9306 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9307 /* and exit if we have enough samples */
9308 if (G_UNLIKELY (index >= n)) {
9315 stream->stss_index = i;
9318 /* stps marks partial sync frames like open GOP I-Frames */
9319 if (stream->stps_present == TRUE) {
9320 guint32 n_sample_partial_syncs;
9322 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9324 /* if there are no entries, the stss table contains the real
9326 if (n_sample_partial_syncs) {
9327 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9328 /* note that the first sample is index 1, not 0 */
9331 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9333 if (G_LIKELY (index > 0 && index <= n_samples)) {
9335 samples[index].keyframe = TRUE;
9336 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9337 /* and exit if we have enough samples */
9338 if (G_UNLIKELY (index >= n)) {
9345 stream->stps_index = i;
9349 /* no stss, all samples are keyframes */
9350 stream->all_keyframe = TRUE;
9351 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9356 /* composition time to sample */
9357 if (stream->ctts_present == TRUE) {
9358 guint32 n_composition_times;
9360 gint32 ctts_soffset;
9362 /* Fill in the pts_offsets */
9364 n_composition_times = stream->n_composition_times;
9366 for (i = stream->ctts_index; i < n_composition_times; i++) {
9367 if (stream->ctts_sample_index >= stream->ctts_count
9368 || !stream->ctts_sample_index) {
9369 stream->ctts_count =
9370 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9371 stream->ctts_soffset =
9372 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9373 stream->ctts_sample_index = 0;
9376 ctts_count = stream->ctts_count;
9377 ctts_soffset = stream->ctts_soffset;
9379 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9380 cur->pts_offset = ctts_soffset;
9383 if (G_UNLIKELY (cur > last)) {
9385 stream->ctts_sample_index = j + 1;
9389 stream->ctts_sample_index = 0;
9390 stream->ctts_index++;
9394 stream->stbl_index = n;
9395 /* if index has been completely parsed, free data that is no-longer needed */
9396 if (n + 1 == stream->n_samples) {
9397 gst_qtdemux_stbl_free (stream);
9398 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9399 if (qtdemux->pullbased) {
9400 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9401 while (n + 1 == stream->n_samples)
9402 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9406 GST_OBJECT_UNLOCK (qtdemux);
9413 GST_LOG_OBJECT (qtdemux,
9414 "Tried to parse up to sample %u but this sample has already been parsed",
9416 /* if fragmented, there may be more */
9417 if (qtdemux->fragmented && n == stream->stbl_index)
9419 GST_OBJECT_UNLOCK (qtdemux);
9425 GST_LOG_OBJECT (qtdemux,
9426 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9428 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9429 (_("This file is corrupt and cannot be played.")), (NULL));
9434 GST_OBJECT_UNLOCK (qtdemux);
9435 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9436 (_("This file is corrupt and cannot be played.")), (NULL));
9441 /* collect all segment info for @stream.
9444 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9448 /* accept edts if they contain gaps at start and there is only
9449 * one media segment */
9450 gboolean allow_pushbased_edts = TRUE;
9451 gint media_segments_count = 0;
9453 /* parse and prepare segment info from the edit list */
9454 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9455 stream->n_segments = 0;
9456 stream->segments = NULL;
9457 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9460 gint segment_number, entry_size;
9463 const guint8 *buffer;
9467 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9468 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9471 buffer = elst->data;
9473 size = QT_UINT32 (buffer);
9474 /* version, flags, n_segments */
9476 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9479 version = QT_UINT8 (buffer + 8);
9480 entry_size = (version == 1) ? 20 : 12;
9482 n_segments = QT_UINT32 (buffer + 12);
9484 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9485 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9489 /* we might allocate a bit too much, at least allocate 1 segment */
9490 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9492 /* segments always start from 0 */
9496 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9499 gboolean empty_edit = FALSE;
9500 QtDemuxSegment *segment;
9502 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9505 media_time = QT_UINT64 (buffer + 8);
9506 duration = QT_UINT64 (buffer);
9507 if (media_time == G_MAXUINT64)
9510 media_time = QT_UINT32 (buffer + 4);
9511 duration = QT_UINT32 (buffer);
9512 if (media_time == G_MAXUINT32)
9517 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9519 segment = &stream->segments[segment_number];
9521 /* time and duration expressed in global timescale */
9522 segment->time = stime;
9523 if (duration != 0 || empty_edit) {
9524 /* edge case: empty edits with duration=zero are treated here.
9525 * (files should not have these anyway). */
9527 /* add non scaled values so we don't cause roundoff errors */
9529 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9530 segment->duration = stime - segment->time;
9532 /* zero duration does not imply media_start == media_stop
9533 * but, only specify media_start. The edit ends with the track. */
9534 stime = segment->duration = GST_CLOCK_TIME_NONE;
9535 /* Don't allow more edits after this one. */
9536 n_segments = segment_number + 1;
9538 segment->stop_time = stime;
9540 segment->trak_media_start = media_time;
9541 /* media_time expressed in stream timescale */
9543 segment->media_start = media_start;
9544 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9545 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9546 media_segments_count++;
9548 segment->media_start = GST_CLOCK_TIME_NONE;
9549 segment->media_stop = GST_CLOCK_TIME_NONE;
9551 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9553 if (rate_int <= 1) {
9554 /* 0 is not allowed, some programs write 1 instead of the floating point
9556 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9560 segment->rate = rate_int / 65536.0;
9563 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9564 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9565 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9566 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9567 segment_number, GST_TIME_ARGS (segment->time),
9568 GST_TIME_ARGS (segment->duration),
9569 GST_TIME_ARGS (segment->media_start), media_time,
9570 GST_TIME_ARGS (segment->media_stop),
9571 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9573 if (segment->stop_time > qtdemux->segment.stop &&
9574 !qtdemux->upstream_format_is_time) {
9575 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9576 " extends to %" GST_TIME_FORMAT
9577 " past the end of the declared movie duration %" GST_TIME_FORMAT
9578 " movie segment will be extended", segment_number,
9579 GST_TIME_ARGS (segment->stop_time),
9580 GST_TIME_ARGS (qtdemux->segment.stop));
9581 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9584 buffer += entry_size;
9586 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9587 stream->n_segments = n_segments;
9588 if (media_segments_count != 1)
9589 allow_pushbased_edts = FALSE;
9593 /* push based does not handle segments, so act accordingly here,
9594 * and warn if applicable */
9595 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9596 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9597 /* remove and use default one below, we stream like it anyway */
9598 g_free (stream->segments);
9599 stream->segments = NULL;
9600 stream->n_segments = 0;
9603 /* no segments, create one to play the complete trak */
9604 if (stream->n_segments == 0) {
9605 GstClockTime stream_duration =
9606 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9608 if (stream->segments == NULL)
9609 stream->segments = g_new (QtDemuxSegment, 1);
9611 /* represent unknown our way */
9612 if (stream_duration == 0)
9613 stream_duration = GST_CLOCK_TIME_NONE;
9615 stream->segments[0].time = 0;
9616 stream->segments[0].stop_time = stream_duration;
9617 stream->segments[0].duration = stream_duration;
9618 stream->segments[0].media_start = 0;
9619 stream->segments[0].media_stop = stream_duration;
9620 stream->segments[0].rate = 1.0;
9621 stream->segments[0].trak_media_start = 0;
9623 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9624 GST_TIME_ARGS (stream_duration));
9625 stream->n_segments = 1;
9626 stream->dummy_segment = TRUE;
9628 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9634 * Parses the stsd atom of a svq3 trak looking for
9635 * the SMI and gama atoms.
9638 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9639 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9641 const guint8 *_gamma = NULL;
9642 GstBuffer *_seqh = NULL;
9643 const guint8 *stsd_data = stsd_entry_data;
9644 guint32 length = QT_UINT32 (stsd_data);
9648 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9654 version = QT_UINT16 (stsd_data);
9659 while (length > 8) {
9660 guint32 fourcc, size;
9662 size = QT_UINT32 (stsd_data);
9663 fourcc = QT_FOURCC (stsd_data + 4);
9664 data = stsd_data + 8;
9667 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9668 "svq3 atom parsing");
9677 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9678 " for gama atom, expected 12", size);
9683 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9685 if (_seqh != NULL) {
9686 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9687 " found, ignoring");
9689 seqh_size = QT_UINT32 (data + 4);
9690 if (seqh_size > 0) {
9691 _seqh = gst_buffer_new_and_alloc (seqh_size);
9692 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9699 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9700 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9704 if (size <= length) {
9710 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9713 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9714 G_GUINT16_FORMAT, version);
9725 gst_buffer_unref (_seqh);
9730 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9737 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9738 * atom that might contain a 'data' atom with the rtsp uri.
9739 * This case was reported in bug #597497, some info about
9740 * the hndl atom can be found in TN1195
9742 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9743 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9746 guint32 dref_num_entries = 0;
9747 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9748 gst_byte_reader_skip (&dref, 4) &&
9749 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9752 /* search dref entries for hndl atom */
9753 for (i = 0; i < dref_num_entries; i++) {
9754 guint32 size = 0, type;
9755 guint8 string_len = 0;
9756 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9757 qt_atom_parser_get_fourcc (&dref, &type)) {
9758 if (type == FOURCC_hndl) {
9759 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9761 /* skip data reference handle bytes and the
9762 * following pascal string and some extra 4
9763 * bytes I have no idea what are */
9764 if (!gst_byte_reader_skip (&dref, 4) ||
9765 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9766 !gst_byte_reader_skip (&dref, string_len + 4)) {
9767 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9771 /* iterate over the atoms to find the data atom */
9772 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9776 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9777 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9778 if (atom_type == FOURCC_data) {
9779 const guint8 *uri_aux = NULL;
9781 /* found the data atom that might contain the rtsp uri */
9782 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9783 "hndl atom, interpreting it as an URI");
9784 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9786 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9787 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9789 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9790 "didn't contain a rtsp address");
9792 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9797 /* skipping to the next entry */
9798 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9801 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9808 /* skip to the next entry */
9809 if (!gst_byte_reader_skip (&dref, size - 8))
9812 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9815 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9821 #define AMR_NB_ALL_MODES 0x81ff
9822 #define AMR_WB_ALL_MODES 0x83ff
9824 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9826 /* The 'damr' atom is of the form:
9828 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9829 * 32 b 8 b 16 b 8 b 8 b
9831 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9832 * represents the highest mode used in the stream (and thus the maximum
9833 * bitrate), with a couple of special cases as seen below.
9836 /* Map of frame type ID -> bitrate */
9837 static const guint nb_bitrates[] = {
9838 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9840 static const guint wb_bitrates[] = {
9841 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9847 gst_buffer_map (buf, &map, GST_MAP_READ);
9849 if (map.size != 0x11) {
9850 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9854 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9855 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9856 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9860 mode_set = QT_UINT16 (map.data + 13);
9862 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9863 max_mode = 7 + (wb ? 1 : 0);
9865 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9866 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9868 if (max_mode == -1) {
9869 GST_DEBUG ("No mode indication was found (mode set) = %x",
9874 gst_buffer_unmap (buf, &map);
9875 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9878 gst_buffer_unmap (buf, &map);
9883 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9884 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9887 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9893 if (gst_byte_reader_get_remaining (reader) < 36)
9896 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9897 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9898 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9899 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9900 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9901 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9902 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9903 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9904 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9906 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9907 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9908 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9910 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9911 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9913 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9914 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9921 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9922 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9929 * This macro will only compare value abdegh, it expects cfi to have already
9932 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9933 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9935 /* only handle the cases where the last column has standard values */
9936 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9937 const gchar *rotation_tag = NULL;
9939 /* no rotation needed */
9940 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9942 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9943 rotation_tag = "rotate-90";
9944 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9945 rotation_tag = "rotate-180";
9946 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9947 rotation_tag = "rotate-270";
9949 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9952 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9954 if (rotation_tag != NULL) {
9955 if (*taglist == NULL)
9956 *taglist = gst_tag_list_new_empty ();
9957 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9958 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9961 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9965 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9966 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9967 * Common Encryption (cenc), the function will also parse the tenc box (defined
9968 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9969 * (typically an enc[v|a|t|s] sample entry); the function will set
9970 * @original_fmt to the fourcc of the original unencrypted stream format.
9971 * Returns TRUE if successful; FALSE otherwise. */
9973 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9974 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9980 QtDemuxCencSampleSetInfo *info;
9982 const guint8 *tenc_data;
9984 g_return_val_if_fail (qtdemux != NULL, FALSE);
9985 g_return_val_if_fail (stream != NULL, FALSE);
9986 g_return_val_if_fail (container != NULL, FALSE);
9987 g_return_val_if_fail (original_fmt != NULL, FALSE);
9989 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9990 if (G_UNLIKELY (!sinf)) {
9991 if (stream->protection_scheme_type == FOURCC_cenc) {
9992 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9993 "mandatory for Common Encryption");
9999 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10000 if (G_UNLIKELY (!frma)) {
10001 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10005 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10006 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10007 GST_FOURCC_ARGS (*original_fmt));
10009 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10011 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10014 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10015 stream->protection_scheme_version =
10016 QT_UINT32 ((const guint8 *) schm->data + 16);
10018 GST_DEBUG_OBJECT (qtdemux,
10019 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10020 "protection_scheme_version: %#010x",
10021 GST_FOURCC_ARGS (stream->protection_scheme_type),
10022 stream->protection_scheme_version);
10024 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10026 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10029 if (stream->protection_scheme_type != FOURCC_cenc &&
10030 stream->protection_scheme_type != FOURCC_piff) {
10031 GST_ERROR_OBJECT (qtdemux,
10032 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10033 GST_FOURCC_ARGS (stream->protection_scheme_type));
10037 if (G_UNLIKELY (!stream->protection_scheme_info))
10038 stream->protection_scheme_info =
10039 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10041 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10043 if (stream->protection_scheme_type == FOURCC_cenc) {
10044 guint32 is_encrypted;
10046 const guint8 *default_kid;
10048 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10050 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10051 "which is mandatory for Common Encryption");
10054 tenc_data = (const guint8 *) tenc->data + 12;
10055 is_encrypted = QT_UINT24 (tenc_data);
10056 iv_size = QT_UINT8 (tenc_data + 3);
10057 default_kid = (tenc_data + 4);
10058 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10059 is_encrypted, iv_size, default_kid);
10060 } else if (stream->protection_scheme_type == FOURCC_piff) {
10062 static const guint8 piff_track_encryption_uuid[] = {
10063 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10064 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10067 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10069 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10070 "which is mandatory for Common Encryption");
10074 tenc_data = (const guint8 *) tenc->data + 8;
10075 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10076 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10077 GST_ERROR_OBJECT (qtdemux,
10078 "Unsupported track encryption box with uuid: %s", box_uuid);
10082 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10083 gst_byte_reader_init (&br, tenc_data, 20);
10084 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10085 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10088 stream->protection_scheme_type = FOURCC_cenc;
10095 qtdemux_track_id_compare_func (QtDemuxStream * stream1, QtDemuxStream * stream2)
10097 return (gint) stream1->track_id - (gint) stream2->track_id;
10100 /* parse the traks.
10101 * With each track we associate a new QtDemuxStream that contains all the info
10103 * traks that do not decode to something (like strm traks) will not have a pad.
10106 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10108 GstByteReader tkhd;
10123 QtDemuxStream *stream = NULL;
10124 const guint8 *stsd_data;
10125 const guint8 *stsd_entry_data;
10126 guint remaining_stsd_len;
10127 guint stsd_entry_count;
10129 guint16 lang_code; /* quicktime lang code or packed iso code */
10131 guint32 tkhd_flags = 0;
10132 guint8 tkhd_version = 0;
10133 guint32 w = 0, h = 0;
10134 guint value_size, stsd_len, len;
10138 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10140 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10141 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10142 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10145 /* pick between 64 or 32 bits */
10146 value_size = tkhd_version == 1 ? 8 : 4;
10147 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10148 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10151 /* Check if current moov has duplicated track_id */
10152 if (qtdemux_find_stream (qtdemux, track_id))
10153 goto existing_stream;
10155 stream = _create_stream (qtdemux, track_id);
10156 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10158 /* need defaults for fragments */
10159 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10161 if ((tkhd_flags & 1) == 0)
10162 stream->disabled = TRUE;
10164 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10165 tkhd_version, tkhd_flags, stream->track_id);
10167 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10170 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10171 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10172 if (qtdemux->major_brand != FOURCC_mjp2 ||
10173 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10177 len = QT_UINT32 ((guint8 *) mdhd->data);
10178 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10179 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10180 if (version == 0x01000000) {
10183 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10184 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10185 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10189 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10190 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10191 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10194 if (lang_code < 0x400) {
10195 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10196 } else if (lang_code == 0x7fff) {
10197 stream->lang_id[0] = 0; /* unspecified */
10199 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10200 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10201 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10202 stream->lang_id[3] = 0;
10205 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10206 stream->timescale);
10207 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10209 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10210 lang_code, stream->lang_id);
10212 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10215 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10216 /* chapters track reference */
10217 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10219 gsize length = GST_READ_UINT32_BE (chap->data);
10220 if (qtdemux->chapters_track_id)
10221 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10223 if (length >= 12) {
10224 qtdemux->chapters_track_id =
10225 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10230 /* fragmented files may have bogus duration in moov */
10231 if (!qtdemux->fragmented &&
10232 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10233 guint64 tdur1, tdur2;
10235 /* don't overflow */
10236 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10237 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10240 * some of those trailers, nowadays, have prologue images that are
10241 * themselves video tracks as well. I haven't really found a way to
10242 * identify those yet, except for just looking at their duration. */
10243 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10244 GST_WARNING_OBJECT (qtdemux,
10245 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10246 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10247 "found, assuming preview image or something; skipping track",
10248 stream->duration, stream->timescale, qtdemux->duration,
10249 qtdemux->timescale);
10250 gst_qtdemux_stream_free (stream);
10255 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10258 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10259 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10261 len = QT_UINT32 ((guint8 *) hdlr->data);
10263 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10264 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10265 GST_FOURCC_ARGS (stream->subtype));
10267 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10270 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10273 /*parse svmi header if existing */
10274 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10276 len = QT_UINT32 ((guint8 *) svmi->data);
10277 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10279 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10280 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10281 guint8 frame_type, frame_layout;
10283 /* MPEG-A stereo video */
10284 if (qtdemux->major_brand == FOURCC_ss02)
10285 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10287 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10288 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10289 switch (frame_type) {
10291 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10294 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10297 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10300 /* mode 3 is primary/secondary view sequence, ie
10301 * left/right views in separate tracks. See section 7.2
10302 * of ISO/IEC 23000-11:2009 */
10303 GST_FIXME_OBJECT (qtdemux,
10304 "Implement stereo video in separate streams");
10307 if ((frame_layout & 0x1) == 0)
10308 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10310 GST_LOG_OBJECT (qtdemux,
10311 "StereoVideo: composition type: %u, is_left_first: %u",
10312 frame_type, frame_layout);
10313 stream->multiview_mode = mode;
10314 stream->multiview_flags = flags;
10318 /* parse rest of tkhd */
10319 if (stream->subtype == FOURCC_vide) {
10322 /* version 1 uses some 64-bit ints */
10323 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10326 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10329 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10330 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10333 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10334 &stream->stream_tags);
10338 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10340 stsd_data = (const guint8 *) stsd->data;
10342 /* stsd should at least have one entry */
10343 stsd_len = QT_UINT32 (stsd_data);
10344 if (stsd_len < 24) {
10345 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10346 if (stream->subtype == FOURCC_vivo) {
10347 gst_qtdemux_stream_free (stream);
10354 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10355 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10356 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10357 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10359 stsd_entry_data = stsd_data + 16;
10360 remaining_stsd_len = stsd_len - 16;
10361 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10363 gchar *codec = NULL;
10364 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10366 /* and that entry should fit within stsd */
10367 len = QT_UINT32 (stsd_entry_data);
10368 if (len > remaining_stsd_len)
10371 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10372 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10373 GST_FOURCC_ARGS (entry->fourcc));
10374 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10376 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10377 goto error_encrypted;
10379 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10380 /* FIXME this looks wrong, there might be multiple children
10381 * with the same type */
10382 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10383 stream->protected = TRUE;
10384 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10385 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10388 if (stream->subtype == FOURCC_vide) {
10393 gint depth, palette_size, palette_count;
10394 guint32 *palette_data = NULL;
10396 entry->sampled = TRUE;
10398 stream->display_width = w >> 16;
10399 stream->display_height = h >> 16;
10402 if (len < 86) /* TODO verify */
10405 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10406 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10407 entry->fps_n = 0; /* this is filled in later */
10408 entry->fps_d = 0; /* this is filled in later */
10409 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10410 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10412 /* if color_table_id is 0, ctab atom must follow; however some files
10413 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10414 * if color table is not present we'll correct the value */
10415 if (entry->color_table_id == 0 &&
10417 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10418 entry->color_table_id = -1;
10421 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10422 entry->width, entry->height, entry->bits_per_sample,
10423 entry->color_table_id);
10425 depth = entry->bits_per_sample;
10427 /* more than 32 bits means grayscale */
10428 gray = (depth > 32);
10429 /* low 32 bits specify the depth */
10432 /* different number of palette entries is determined by depth. */
10434 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10435 palette_count = (1 << depth);
10436 palette_size = palette_count * 4;
10438 if (entry->color_table_id) {
10439 switch (palette_count) {
10443 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10446 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10451 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10453 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10458 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10460 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10463 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10464 (_("The video in this file might not play correctly.")),
10465 ("unsupported palette depth %d", depth));
10469 gint i, j, start, end;
10475 start = QT_UINT32 (stsd_entry_data + offset + 70);
10476 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10477 end = QT_UINT16 (stsd_entry_data + offset + 76);
10479 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10480 start, end, palette_count);
10487 if (len < 94 + (end - start) * 8)
10490 /* palette is always the same size */
10491 palette_data = g_malloc0 (256 * 4);
10492 palette_size = 256 * 4;
10494 for (j = 0, i = start; i <= end; j++, i++) {
10495 guint32 a, r, g, b;
10497 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10498 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10499 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10500 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10502 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10503 (g & 0xff00) | (b >> 8);
10508 gst_caps_unref (entry->caps);
10511 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10513 if (G_UNLIKELY (!entry->caps)) {
10514 g_free (palette_data);
10515 goto unknown_stream;
10519 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10520 GST_TAG_VIDEO_CODEC, codec, NULL);
10525 if (palette_data) {
10528 if (entry->rgb8_palette)
10529 gst_memory_unref (entry->rgb8_palette);
10530 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10531 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10533 s = gst_caps_get_structure (entry->caps, 0);
10535 /* non-raw video has a palette_data property. raw video has the palette as
10536 * an extra plane that we append to the output buffers before we push
10538 if (!gst_structure_has_name (s, "video/x-raw")) {
10539 GstBuffer *palette;
10541 palette = gst_buffer_new ();
10542 gst_buffer_append_memory (palette, entry->rgb8_palette);
10543 entry->rgb8_palette = NULL;
10545 gst_caps_set_simple (entry->caps, "palette_data",
10546 GST_TYPE_BUFFER, palette, NULL);
10547 gst_buffer_unref (palette);
10549 } else if (palette_count != 0) {
10550 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10551 (NULL), ("Unsupported palette depth %d", depth));
10554 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10555 QT_UINT16 (stsd_entry_data + offset + 32));
10561 /* pick 'the' stsd child */
10562 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10563 if (!stream->protected) {
10564 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10568 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10574 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10575 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10576 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10577 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10581 const guint8 *pasp_data = (const guint8 *) pasp->data;
10582 gint len = QT_UINT32 (pasp_data);
10585 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10586 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10588 CUR_STREAM (stream)->par_w = 0;
10589 CUR_STREAM (stream)->par_h = 0;
10592 CUR_STREAM (stream)->par_w = 0;
10593 CUR_STREAM (stream)->par_h = 0;
10597 const guint8 *fiel_data = (const guint8 *) fiel->data;
10598 gint len = QT_UINT32 (fiel_data);
10601 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10602 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10607 const guint8 *colr_data = (const guint8 *) colr->data;
10608 gint len = QT_UINT32 (colr_data);
10610 if (len == 19 || len == 18) {
10611 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10613 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10614 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10615 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10616 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10617 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10619 switch (primaries) {
10621 CUR_STREAM (stream)->colorimetry.primaries =
10622 GST_VIDEO_COLOR_PRIMARIES_BT709;
10625 CUR_STREAM (stream)->colorimetry.primaries =
10626 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10629 CUR_STREAM (stream)->colorimetry.primaries =
10630 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10633 CUR_STREAM (stream)->colorimetry.primaries =
10634 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10640 switch (transfer_function) {
10642 CUR_STREAM (stream)->colorimetry.transfer =
10643 GST_VIDEO_TRANSFER_BT709;
10646 CUR_STREAM (stream)->colorimetry.transfer =
10647 GST_VIDEO_TRANSFER_SMPTE240M;
10655 CUR_STREAM (stream)->colorimetry.matrix =
10656 GST_VIDEO_COLOR_MATRIX_BT709;
10659 CUR_STREAM (stream)->colorimetry.matrix =
10660 GST_VIDEO_COLOR_MATRIX_BT601;
10663 CUR_STREAM (stream)->colorimetry.matrix =
10664 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10667 CUR_STREAM (stream)->colorimetry.matrix =
10668 GST_VIDEO_COLOR_MATRIX_BT2020;
10674 CUR_STREAM (stream)->colorimetry.range =
10675 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10676 GST_VIDEO_COLOR_RANGE_16_235;
10678 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10681 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10686 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10687 stream->stream_tags);
10694 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10695 const guint8 *avc_data = stsd_entry_data + 0x56;
10698 while (len >= 0x8) {
10701 if (QT_UINT32 (avc_data) <= len)
10702 size = QT_UINT32 (avc_data) - 0x8;
10707 /* No real data, so break out */
10710 switch (QT_FOURCC (avc_data + 0x4)) {
10713 /* parse, if found */
10716 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10718 /* First 4 bytes are the length of the atom, the next 4 bytes
10719 * are the fourcc, the next 1 byte is the version, and the
10720 * subsequent bytes are profile_tier_level structure like data. */
10721 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10722 avc_data + 8 + 1, size - 1);
10723 buf = gst_buffer_new_and_alloc (size);
10724 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10725 gst_caps_set_simple (entry->caps,
10726 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10727 gst_buffer_unref (buf);
10735 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10737 /* First 4 bytes are the length of the atom, the next 4 bytes
10738 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10739 * next 1 byte is the version, and the
10740 * subsequent bytes are sequence parameter set like data. */
10742 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10744 gst_codec_utils_h264_caps_set_level_and_profile
10745 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10747 buf = gst_buffer_new_and_alloc (size);
10748 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10749 gst_caps_set_simple (entry->caps,
10750 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10751 gst_buffer_unref (buf);
10757 guint avg_bitrate, max_bitrate;
10759 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10763 max_bitrate = QT_UINT32 (avc_data + 0xc);
10764 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10766 if (!max_bitrate && !avg_bitrate)
10769 /* Some muxers seem to swap the average and maximum bitrates
10770 * (I'm looking at you, YouTube), so we swap for sanity. */
10771 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10772 guint temp = avg_bitrate;
10774 avg_bitrate = max_bitrate;
10775 max_bitrate = temp;
10778 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10779 gst_tag_list_add (stream->stream_tags,
10780 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10781 max_bitrate, NULL);
10783 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10784 gst_tag_list_add (stream->stream_tags,
10785 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10797 avc_data += size + 8;
10806 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10807 const guint8 *hevc_data = stsd_entry_data + 0x56;
10810 while (len >= 0x8) {
10813 if (QT_UINT32 (hevc_data) <= len)
10814 size = QT_UINT32 (hevc_data) - 0x8;
10819 /* No real data, so break out */
10822 switch (QT_FOURCC (hevc_data + 0x4)) {
10825 /* parse, if found */
10828 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10830 /* First 4 bytes are the length of the atom, the next 4 bytes
10831 * are the fourcc, the next 1 byte is the version, and the
10832 * subsequent bytes are sequence parameter set like data. */
10833 gst_codec_utils_h265_caps_set_level_tier_and_profile
10834 (entry->caps, hevc_data + 8 + 1, size - 1);
10836 buf = gst_buffer_new_and_alloc (size);
10837 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10838 gst_caps_set_simple (entry->caps,
10839 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10840 gst_buffer_unref (buf);
10847 hevc_data += size + 8;
10860 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10861 GST_FOURCC_ARGS (fourcc));
10863 /* codec data might be in glbl extension atom */
10865 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10871 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10873 len = QT_UINT32 (data);
10876 buf = gst_buffer_new_and_alloc (len);
10877 gst_buffer_fill (buf, 0, data + 8, len);
10878 gst_caps_set_simple (entry->caps,
10879 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10880 gst_buffer_unref (buf);
10887 /* see annex I of the jpeg2000 spec */
10888 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10889 const guint8 *data;
10890 const gchar *colorspace = NULL;
10892 guint32 ncomp_map = 0;
10893 gint32 *comp_map = NULL;
10894 guint32 nchan_def = 0;
10895 gint32 *chan_def = NULL;
10897 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10898 /* some required atoms */
10899 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10902 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10906 /* number of components; redundant with info in codestream, but useful
10908 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10909 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10911 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10913 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10916 GST_DEBUG_OBJECT (qtdemux, "found colr");
10917 /* extract colour space info */
10918 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10919 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10921 colorspace = "sRGB";
10924 colorspace = "GRAY";
10927 colorspace = "sYUV";
10935 /* colr is required, and only values 16, 17, and 18 are specified,
10936 so error if we have no colorspace */
10939 /* extract component mapping */
10940 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10942 guint32 cmap_len = 0;
10944 cmap_len = QT_UINT32 (cmap->data);
10945 if (cmap_len >= 8) {
10946 /* normal box, subtract off header */
10948 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10949 if (cmap_len % 4 == 0) {
10950 ncomp_map = (cmap_len / 4);
10951 comp_map = g_new0 (gint32, ncomp_map);
10952 for (i = 0; i < ncomp_map; i++) {
10955 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10956 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10957 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10958 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10963 /* extract channel definitions */
10964 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10966 guint32 cdef_len = 0;
10968 cdef_len = QT_UINT32 (cdef->data);
10969 if (cdef_len >= 10) {
10970 /* normal box, subtract off header and len */
10972 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10973 if (cdef_len % 6 == 0) {
10974 nchan_def = (cdef_len / 6);
10975 chan_def = g_new0 (gint32, nchan_def);
10976 for (i = 0; i < nchan_def; i++)
10978 for (i = 0; i < nchan_def; i++) {
10979 guint16 cn, typ, asoc;
10980 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10981 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10982 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10983 if (cn < nchan_def) {
10986 chan_def[cn] = asoc;
10989 chan_def[cn] = 0; /* alpha */
10992 chan_def[cn] = -typ;
11000 gst_caps_set_simple (entry->caps,
11001 "num-components", G_TYPE_INT, ncomp, NULL);
11002 gst_caps_set_simple (entry->caps,
11003 "colorspace", G_TYPE_STRING, colorspace, NULL);
11006 GValue arr = { 0, };
11007 GValue elt = { 0, };
11009 g_value_init (&arr, GST_TYPE_ARRAY);
11010 g_value_init (&elt, G_TYPE_INT);
11011 for (i = 0; i < ncomp_map; i++) {
11012 g_value_set_int (&elt, comp_map[i]);
11013 gst_value_array_append_value (&arr, &elt);
11015 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11016 "component-map", &arr);
11017 g_value_unset (&elt);
11018 g_value_unset (&arr);
11023 GValue arr = { 0, };
11024 GValue elt = { 0, };
11026 g_value_init (&arr, GST_TYPE_ARRAY);
11027 g_value_init (&elt, G_TYPE_INT);
11028 for (i = 0; i < nchan_def; i++) {
11029 g_value_set_int (&elt, chan_def[i]);
11030 gst_value_array_append_value (&arr, &elt);
11032 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11033 "channel-definitions", &arr);
11034 g_value_unset (&elt);
11035 g_value_unset (&arr);
11039 /* some optional atoms */
11040 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11041 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11043 /* indicate possible fields in caps */
11045 data = (guint8 *) field->data + 8;
11047 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11048 (gint) * data, NULL);
11050 /* add codec_data if provided */
11055 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11056 data = prefix->data;
11057 len = QT_UINT32 (data);
11060 buf = gst_buffer_new_and_alloc (len);
11061 gst_buffer_fill (buf, 0, data + 8, len);
11062 gst_caps_set_simple (entry->caps,
11063 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11064 gst_buffer_unref (buf);
11073 GstBuffer *seqh = NULL;
11074 const guint8 *gamma_data = NULL;
11075 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11077 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11080 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11081 QT_FP32 (gamma_data), NULL);
11084 /* sorry for the bad name, but we don't know what this is, other
11085 * than its own fourcc */
11086 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11088 gst_buffer_unref (seqh);
11091 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11092 buf = gst_buffer_new_and_alloc (len);
11093 gst_buffer_fill (buf, 0, stsd_data, len);
11094 gst_caps_set_simple (entry->caps,
11095 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11096 gst_buffer_unref (buf);
11101 /* https://developer.apple.com/standards/qtff-2001.pdf,
11102 * page 92, "Video Sample Description", under table 3.1 */
11105 const gint compressor_offset =
11106 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11107 const gint min_size = compressor_offset + 32 + 2 + 2;
11110 guint16 color_table_id = 0;
11113 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11115 /* recover information on interlaced/progressive */
11116 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11120 len = QT_UINT32 (jpeg->data);
11121 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11123 if (len >= min_size) {
11124 gst_byte_reader_init (&br, jpeg->data, len);
11126 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11127 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11128 if (color_table_id != 0) {
11129 /* the spec says there can be concatenated chunks in the data, and we want
11130 * to find one called field. Walk through them. */
11131 gint offset = min_size;
11132 while (offset + 8 < len) {
11133 guint32 size = 0, tag;
11134 ok = gst_byte_reader_get_uint32_le (&br, &size);
11135 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11136 if (!ok || size < 8) {
11137 GST_WARNING_OBJECT (qtdemux,
11138 "Failed to walk optional chunk list");
11141 GST_DEBUG_OBJECT (qtdemux,
11142 "Found optional %4.4s chunk, size %u",
11143 (const char *) &tag, size);
11144 if (tag == FOURCC_fiel) {
11145 guint8 n_fields = 0, ordering = 0;
11146 gst_byte_reader_get_uint8 (&br, &n_fields);
11147 gst_byte_reader_get_uint8 (&br, &ordering);
11148 if (n_fields == 1 || n_fields == 2) {
11149 GST_DEBUG_OBJECT (qtdemux,
11150 "Found fiel tag with %u fields, ordering %u",
11151 n_fields, ordering);
11153 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11154 "interlace-mode", G_TYPE_STRING, "interleaved",
11157 GST_WARNING_OBJECT (qtdemux,
11158 "Found fiel tag with invalid fields (%u)", n_fields);
11164 GST_DEBUG_OBJECT (qtdemux,
11165 "Color table ID is 0, not trying to get interlacedness");
11168 GST_WARNING_OBJECT (qtdemux,
11169 "Length of jpeg chunk is too small, not trying to get interlacedness");
11177 gst_caps_set_simple (entry->caps,
11178 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11184 GNode *xith, *xdxt;
11186 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11187 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11191 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11195 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11196 /* collect the headers and store them in a stream list so that we can
11197 * send them out first */
11198 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11208 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11209 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11212 ovc1_data = ovc1->data;
11213 ovc1_len = QT_UINT32 (ovc1_data);
11214 if (ovc1_len <= 198) {
11215 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11218 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11219 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11220 gst_caps_set_simple (entry->caps,
11221 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11222 gst_buffer_unref (buf);
11227 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11228 const guint8 *vc1_data = stsd_entry_data + 0x56;
11234 if (QT_UINT32 (vc1_data) <= len)
11235 size = QT_UINT32 (vc1_data) - 8;
11240 /* No real data, so break out */
11243 switch (QT_FOURCC (vc1_data + 0x4)) {
11244 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11248 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11249 buf = gst_buffer_new_and_alloc (size);
11250 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11251 gst_caps_set_simple (entry->caps,
11252 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11253 gst_buffer_unref (buf);
11260 vc1_data += size + 8;
11266 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11267 const guint8 *av1_data = stsd_entry_data + 0x56;
11270 while (len >= 0x8) {
11273 if (QT_UINT32 (av1_data) <= len)
11274 size = QT_UINT32 (av1_data) - 0x8;
11279 /* No real data, so break out */
11282 switch (QT_FOURCC (av1_data + 0x4)) {
11285 /* parse, if found */
11287 guint8 pres_delay_field;
11289 GST_DEBUG_OBJECT (qtdemux,
11290 "found av1C codec_data in stsd of size %d", size);
11292 /* not enough data, just ignore and hope for the best */
11297 * 4 bytes: atom length
11302 * 1 bits: initial_presentation_delay_present
11303 * 4 bits: initial_presentation_delay (if present else reserved
11307 if (av1_data[9] != 0) {
11308 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11312 /* We skip initial_presentation_delay* for now */
11313 pres_delay_field = *(av1_data + 12);
11314 if (pres_delay_field & (1 << 5)) {
11315 gst_caps_set_simple (entry->caps,
11316 "presentation-delay", G_TYPE_INT,
11317 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11320 buf = gst_buffer_new_and_alloc (size - 5);
11321 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11322 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11323 gst_caps_set_simple (entry->caps,
11324 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11325 gst_buffer_unref (buf);
11334 av1_data += size + 8;
11344 GST_INFO_OBJECT (qtdemux,
11345 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11346 GST_FOURCC_ARGS (fourcc), entry->caps);
11348 } else if (stream->subtype == FOURCC_soun) {
11350 int version, samplesize;
11351 guint16 compression_id;
11352 gboolean amrwb = FALSE;
11355 /* sample description entry (16) + sound sample description v0 (20) */
11359 version = QT_UINT32 (stsd_entry_data + offset);
11360 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11361 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11362 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11363 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11365 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11366 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11367 QT_UINT32 (stsd_entry_data + offset + 4));
11368 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11369 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11370 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11371 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11372 QT_UINT16 (stsd_entry_data + offset + 14));
11373 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11375 if (compression_id == 0xfffe)
11376 entry->sampled = TRUE;
11378 /* first assume uncompressed audio */
11379 entry->bytes_per_sample = samplesize / 8;
11380 entry->samples_per_frame = entry->n_channels;
11381 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11382 entry->samples_per_packet = entry->samples_per_frame;
11383 entry->bytes_per_packet = entry->bytes_per_sample;
11387 /* Yes, these have to be hard-coded */
11390 entry->samples_per_packet = 6;
11391 entry->bytes_per_packet = 1;
11392 entry->bytes_per_frame = 1 * entry->n_channels;
11393 entry->bytes_per_sample = 1;
11394 entry->samples_per_frame = 6 * entry->n_channels;
11399 entry->samples_per_packet = 3;
11400 entry->bytes_per_packet = 1;
11401 entry->bytes_per_frame = 1 * entry->n_channels;
11402 entry->bytes_per_sample = 1;
11403 entry->samples_per_frame = 3 * entry->n_channels;
11408 entry->samples_per_packet = 64;
11409 entry->bytes_per_packet = 34;
11410 entry->bytes_per_frame = 34 * entry->n_channels;
11411 entry->bytes_per_sample = 2;
11412 entry->samples_per_frame = 64 * entry->n_channels;
11418 entry->samples_per_packet = 1;
11419 entry->bytes_per_packet = 1;
11420 entry->bytes_per_frame = 1 * entry->n_channels;
11421 entry->bytes_per_sample = 1;
11422 entry->samples_per_frame = 1 * entry->n_channels;
11427 entry->samples_per_packet = 160;
11428 entry->bytes_per_packet = 33;
11429 entry->bytes_per_frame = 33 * entry->n_channels;
11430 entry->bytes_per_sample = 2;
11431 entry->samples_per_frame = 160 * entry->n_channels;
11438 if (version == 0x00010000) {
11439 /* sample description entry (16) + sound sample description v1 (20+16) */
11451 /* only parse extra decoding config for non-pcm audio */
11452 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11453 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11454 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11455 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11457 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11458 entry->samples_per_packet);
11459 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11460 entry->bytes_per_packet);
11461 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11462 entry->bytes_per_frame);
11463 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11464 entry->bytes_per_sample);
11466 if (!entry->sampled && entry->bytes_per_packet) {
11467 entry->samples_per_frame = (entry->bytes_per_frame /
11468 entry->bytes_per_packet) * entry->samples_per_packet;
11469 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11470 entry->samples_per_frame);
11475 } else if (version == 0x00020000) {
11482 /* sample description entry (16) + sound sample description v2 (56) */
11486 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11487 entry->rate = qtfp.fp;
11488 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11490 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11491 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11492 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11493 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11494 QT_UINT32 (stsd_entry_data + offset + 20));
11495 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11496 QT_UINT32 (stsd_entry_data + offset + 24));
11497 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11498 QT_UINT32 (stsd_entry_data + offset + 28));
11499 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11500 QT_UINT32 (stsd_entry_data + offset + 32));
11501 } else if (version != 0x00000) {
11502 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11507 gst_caps_unref (entry->caps);
11509 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11510 stsd_entry_data + 32, len - 16, &codec);
11518 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11520 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11522 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11524 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11527 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11528 gst_caps_set_simple (entry->caps,
11529 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11536 const guint8 *owma_data;
11537 const gchar *codec_name = NULL;
11541 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11542 /* FIXME this should also be gst_riff_strf_auds,
11543 * but the latter one is actually missing bits-per-sample :( */
11548 gint32 nSamplesPerSec;
11549 gint32 nAvgBytesPerSec;
11550 gint16 nBlockAlign;
11551 gint16 wBitsPerSample;
11554 WAVEFORMATEX *wfex;
11556 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11557 owma_data = stsd_entry_data;
11558 owma_len = QT_UINT32 (owma_data);
11559 if (owma_len <= 54) {
11560 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11563 wfex = (WAVEFORMATEX *) (owma_data + 36);
11564 buf = gst_buffer_new_and_alloc (owma_len - 54);
11565 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11566 if (wfex->wFormatTag == 0x0161) {
11567 codec_name = "Windows Media Audio";
11569 } else if (wfex->wFormatTag == 0x0162) {
11570 codec_name = "Windows Media Audio 9 Pro";
11572 } else if (wfex->wFormatTag == 0x0163) {
11573 codec_name = "Windows Media Audio 9 Lossless";
11574 /* is that correct? gstffmpegcodecmap.c is missing it, but
11575 * fluendo codec seems to support it */
11579 gst_caps_set_simple (entry->caps,
11580 "codec_data", GST_TYPE_BUFFER, buf,
11581 "wmaversion", G_TYPE_INT, version,
11582 "block_align", G_TYPE_INT,
11583 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11584 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11585 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11586 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11587 gst_buffer_unref (buf);
11591 codec = g_strdup (codec_name);
11597 gint len = QT_UINT32 (stsd_entry_data) - offset;
11598 const guint8 *wfex_data = stsd_entry_data + offset;
11599 const gchar *codec_name = NULL;
11601 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11602 /* FIXME this should also be gst_riff_strf_auds,
11603 * but the latter one is actually missing bits-per-sample :( */
11608 gint32 nSamplesPerSec;
11609 gint32 nAvgBytesPerSec;
11610 gint16 nBlockAlign;
11611 gint16 wBitsPerSample;
11616 /* FIXME: unify with similar wavformatex parsing code above */
11617 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11623 if (QT_UINT32 (wfex_data) <= len)
11624 size = QT_UINT32 (wfex_data) - 8;
11629 /* No real data, so break out */
11632 switch (QT_FOURCC (wfex_data + 4)) {
11633 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11635 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11640 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11641 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11642 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11643 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11644 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11645 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11646 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11648 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11649 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11650 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11651 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11652 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11653 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11655 if (wfex.wFormatTag == 0x0161) {
11656 codec_name = "Windows Media Audio";
11658 } else if (wfex.wFormatTag == 0x0162) {
11659 codec_name = "Windows Media Audio 9 Pro";
11661 } else if (wfex.wFormatTag == 0x0163) {
11662 codec_name = "Windows Media Audio 9 Lossless";
11663 /* is that correct? gstffmpegcodecmap.c is missing it, but
11664 * fluendo codec seems to support it */
11668 gst_caps_set_simple (entry->caps,
11669 "wmaversion", G_TYPE_INT, version,
11670 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11671 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11672 "width", G_TYPE_INT, wfex.wBitsPerSample,
11673 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11675 if (size > wfex.cbSize) {
11678 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11679 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11680 size - wfex.cbSize);
11681 gst_caps_set_simple (entry->caps,
11682 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11683 gst_buffer_unref (buf);
11685 GST_WARNING_OBJECT (qtdemux, "no codec data");
11690 codec = g_strdup (codec_name);
11698 wfex_data += size + 8;
11704 const guint8 *opus_data;
11705 guint8 *channel_mapping = NULL;
11708 guint8 channel_mapping_family;
11709 guint8 stream_count;
11710 guint8 coupled_count;
11713 opus_data = stsd_entry_data;
11715 channels = GST_READ_UINT8 (opus_data + 45);
11716 rate = GST_READ_UINT32_LE (opus_data + 48);
11717 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11718 stream_count = GST_READ_UINT8 (opus_data + 55);
11719 coupled_count = GST_READ_UINT8 (opus_data + 56);
11721 if (channels > 0) {
11722 channel_mapping = g_malloc (channels * sizeof (guint8));
11723 for (i = 0; i < channels; i++)
11724 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11727 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11728 channel_mapping_family, stream_count, coupled_count,
11740 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11741 GST_TAG_AUDIO_CODEC, codec, NULL);
11745 /* some bitrate info may have ended up in caps */
11746 s = gst_caps_get_structure (entry->caps, 0);
11747 gst_structure_get_int (s, "bitrate", &bitrate);
11749 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11750 GST_TAG_BITRATE, bitrate, NULL);
11753 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11754 if (!stream->protected) {
11756 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11760 if (stream->protected && fourcc == FOURCC_mp4a) {
11761 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11765 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11773 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11775 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11777 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11781 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11782 16 bits is a byte-swapped wave-style codec identifier,
11783 and we can find a WAVE header internally to a 'wave' atom here.
11784 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11785 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11788 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11789 if (len < offset + 20) {
11790 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11792 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11793 const guint8 *data = stsd_entry_data + offset + 16;
11795 GNode *waveheadernode;
11797 wavenode = g_node_new ((guint8 *) data);
11798 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11799 const guint8 *waveheader;
11802 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11803 if (waveheadernode) {
11804 waveheader = (const guint8 *) waveheadernode->data;
11805 headerlen = QT_UINT32 (waveheader);
11807 if (headerlen > 8) {
11808 gst_riff_strf_auds *header = NULL;
11809 GstBuffer *headerbuf;
11815 headerbuf = gst_buffer_new_and_alloc (headerlen);
11816 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11818 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11819 headerbuf, &header, &extra)) {
11820 gst_caps_unref (entry->caps);
11821 /* FIXME: Need to do something with the channel reorder map */
11823 gst_riff_create_audio_caps (header->format, NULL, header,
11824 extra, NULL, NULL, NULL);
11827 gst_buffer_unref (extra);
11832 GST_DEBUG ("Didn't find waveheadernode for this codec");
11834 g_node_destroy (wavenode);
11837 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11838 stream->stream_tags);
11842 /* FIXME: what is in the chunk? */
11845 gint len = QT_UINT32 (stsd_data);
11847 /* seems to be always = 116 = 0x74 */
11853 gint len = QT_UINT32 (stsd_entry_data);
11856 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11858 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11859 gst_caps_set_simple (entry->caps,
11860 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11861 gst_buffer_unref (buf);
11863 gst_caps_set_simple (entry->caps,
11864 "samplesize", G_TYPE_INT, samplesize, NULL);
11869 GNode *alac, *wave = NULL;
11871 /* apparently, m4a has this atom appended directly in the stsd entry,
11872 * while mov has it in a wave atom */
11873 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11875 /* alac now refers to stsd entry atom */
11876 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11878 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11880 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11883 const guint8 *alac_data = alac->data;
11884 gint len = QT_UINT32 (alac->data);
11888 GST_DEBUG_OBJECT (qtdemux,
11889 "discarding alac atom with unexpected len %d", len);
11891 /* codec-data contains alac atom size and prefix,
11892 * ffmpeg likes it that way, not quite gst-ish though ...*/
11893 buf = gst_buffer_new_and_alloc (len);
11894 gst_buffer_fill (buf, 0, alac->data, len);
11895 gst_caps_set_simple (entry->caps,
11896 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11897 gst_buffer_unref (buf);
11899 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11900 entry->n_channels = QT_UINT8 (alac_data + 21);
11901 entry->rate = QT_UINT32 (alac_data + 32);
11904 gst_caps_set_simple (entry->caps,
11905 "samplesize", G_TYPE_INT, samplesize, NULL);
11910 /* The codingname of the sample entry is 'fLaC' */
11911 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11914 /* The 'dfLa' box is added to the sample entry to convey
11915 initializing information for the decoder. */
11916 const GNode *dfla =
11917 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11920 const guint32 len = QT_UINT32 (dfla->data);
11922 /* Must contain at least dfLa box header (12),
11923 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11925 GST_DEBUG_OBJECT (qtdemux,
11926 "discarding dfla atom with unexpected len %d", len);
11928 /* skip dfLa header to get the METADATA_BLOCKs */
11929 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11930 const guint32 metadata_blocks_len = len - 12;
11932 gchar *stream_marker = g_strdup ("fLaC");
11933 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11934 strlen (stream_marker));
11937 guint32 remainder = 0;
11938 guint32 block_size = 0;
11939 gboolean is_last = FALSE;
11941 GValue array = G_VALUE_INIT;
11942 GValue value = G_VALUE_INIT;
11944 g_value_init (&array, GST_TYPE_ARRAY);
11945 g_value_init (&value, GST_TYPE_BUFFER);
11947 gst_value_set_buffer (&value, block);
11948 gst_value_array_append_value (&array, &value);
11949 g_value_reset (&value);
11951 gst_buffer_unref (block);
11953 /* check there's at least one METADATA_BLOCK_HEADER's worth
11954 * of data, and we haven't already finished parsing */
11955 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11956 remainder = metadata_blocks_len - index;
11958 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11960 (metadata_blocks[index + 1] << 16) +
11961 (metadata_blocks[index + 2] << 8) +
11962 metadata_blocks[index + 3];
11964 /* be careful not to read off end of box */
11965 if (block_size > remainder) {
11969 is_last = metadata_blocks[index] >> 7;
11971 block = gst_buffer_new_and_alloc (block_size);
11973 gst_buffer_fill (block, 0, &metadata_blocks[index],
11976 gst_value_set_buffer (&value, block);
11977 gst_value_array_append_value (&array, &value);
11978 g_value_reset (&value);
11980 gst_buffer_unref (block);
11982 index += block_size;
11985 /* only append the metadata if we successfully read all of it */
11987 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11988 (stream)->caps, 0), "streamheader", &array);
11990 GST_WARNING_OBJECT (qtdemux,
11991 "discarding all METADATA_BLOCKs due to invalid "
11992 "block_size %d at idx %d, rem %d", block_size, index,
11996 g_value_unset (&value);
11997 g_value_unset (&array);
11999 /* The sample rate obtained from the stsd may not be accurate
12000 * since it cannot represent rates greater than 65535Hz, so
12001 * override that value with the sample rate from the
12002 * METADATA_BLOCK_STREAMINFO block */
12003 CUR_STREAM (stream)->rate =
12004 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12015 gint len = QT_UINT32 (stsd_entry_data);
12018 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12021 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12023 /* If we have enough data, let's try to get the 'damr' atom. See
12024 * the 3GPP container spec (26.244) for more details. */
12025 if ((len - 0x34) > 8 &&
12026 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12027 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12028 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12031 gst_caps_set_simple (entry->caps,
12032 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12033 gst_buffer_unref (buf);
12039 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12040 gint len = QT_UINT32 (stsd_entry_data);
12043 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12045 if (sound_version == 1) {
12046 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12047 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12048 guint8 codec_data[2];
12050 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12052 gint sample_rate_index =
12053 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12055 /* build AAC codec data */
12056 codec_data[0] = profile << 3;
12057 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12058 codec_data[1] = (sample_rate_index & 0x01) << 7;
12059 codec_data[1] |= (channels & 0xF) << 3;
12061 buf = gst_buffer_new_and_alloc (2);
12062 gst_buffer_fill (buf, 0, codec_data, 2);
12063 gst_caps_set_simple (entry->caps,
12064 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12065 gst_buffer_unref (buf);
12071 /* Fully handled elsewhere */
12074 GST_INFO_OBJECT (qtdemux,
12075 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12079 GST_INFO_OBJECT (qtdemux,
12080 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12081 GST_FOURCC_ARGS (fourcc), entry->caps);
12083 } else if (stream->subtype == FOURCC_strm) {
12084 if (fourcc == FOURCC_rtsp) {
12085 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12087 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12088 GST_FOURCC_ARGS (fourcc));
12089 goto unknown_stream;
12091 entry->sampled = TRUE;
12092 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12093 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12094 || stream->subtype == FOURCC_clcp) {
12096 entry->sampled = TRUE;
12097 entry->sparse = TRUE;
12100 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12103 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12104 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12109 /* hunt for sort-of codec data */
12113 GNode *mp4s = NULL;
12114 GNode *esds = NULL;
12116 /* look for palette in a stsd->mp4s->esds sub-atom */
12117 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12119 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12120 if (esds == NULL) {
12122 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12126 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12127 stream->stream_tags);
12131 GST_INFO_OBJECT (qtdemux,
12132 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12135 GST_INFO_OBJECT (qtdemux,
12136 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12137 GST_FOURCC_ARGS (fourcc), entry->caps);
12139 /* everything in 1 sample */
12140 entry->sampled = TRUE;
12143 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12146 if (entry->caps == NULL)
12147 goto unknown_stream;
12150 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12151 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12157 /* promote to sampled format */
12158 if (entry->fourcc == FOURCC_samr) {
12159 /* force mono 8000 Hz for AMR */
12160 entry->sampled = TRUE;
12161 entry->n_channels = 1;
12162 entry->rate = 8000;
12163 } else if (entry->fourcc == FOURCC_sawb) {
12164 /* force mono 16000 Hz for AMR-WB */
12165 entry->sampled = TRUE;
12166 entry->n_channels = 1;
12167 entry->rate = 16000;
12168 } else if (entry->fourcc == FOURCC_mp4a) {
12169 entry->sampled = TRUE;
12173 stsd_entry_data += len;
12174 remaining_stsd_len -= len;
12178 /* collect sample information */
12179 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12180 goto samples_failed;
12182 if (qtdemux->fragmented) {
12185 /* need all moov samples as basis; probably not many if any at all */
12186 /* prevent moof parsing taking of at this time */
12187 offset = qtdemux->moof_offset;
12188 qtdemux->moof_offset = 0;
12189 if (stream->n_samples &&
12190 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12191 qtdemux->moof_offset = offset;
12192 goto samples_failed;
12194 qtdemux->moof_offset = 0;
12195 /* movie duration more reliable in this case (e.g. mehd) */
12196 if (qtdemux->segment.duration &&
12197 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12199 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12202 /* configure segments */
12203 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12204 goto segments_failed;
12206 /* add some language tag, if useful */
12207 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12208 strcmp (stream->lang_id, "und")) {
12209 const gchar *lang_code;
12211 /* convert ISO 639-2 code to ISO 639-1 */
12212 lang_code = gst_tag_get_language_code (stream->lang_id);
12213 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12214 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12217 /* Check for UDTA tags */
12218 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12219 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12222 /* Insert and sort new stream in track-id order.
12223 * This will help in comparing old/new streams during stream update check */
12224 qtdemux->active_streams =
12225 g_list_insert_sorted (qtdemux->active_streams, stream,
12226 (GCompareFunc) qtdemux_track_id_compare_func);
12227 qtdemux->n_streams++;
12228 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
12235 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12236 (_("This file is corrupt and cannot be played.")), (NULL));
12238 gst_qtdemux_stream_free (stream);
12243 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12244 gst_qtdemux_stream_free (stream);
12250 /* we posted an error already */
12251 /* free stbl sub-atoms */
12252 gst_qtdemux_stbl_free (stream);
12253 gst_qtdemux_stream_free (stream);
12258 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12264 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12265 GST_FOURCC_ARGS (stream->subtype));
12266 gst_qtdemux_stream_free (stream);
12271 /* If we can estimate the overall bitrate, and don't have information about the
12272 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12273 * the overall bitrate minus the sum of the bitrates of all other streams. This
12274 * should be useful for the common case where we have one audio and one video
12275 * stream and can estimate the bitrate of one, but not the other. */
12277 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12279 QtDemuxStream *stream = NULL;
12280 gint64 size, sys_bitrate, sum_bitrate = 0;
12281 GstClockTime duration;
12285 if (qtdemux->fragmented)
12288 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12290 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12292 GST_DEBUG_OBJECT (qtdemux,
12293 "Size in bytes of the stream not known - bailing");
12297 /* Subtract the header size */
12298 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12299 size, qtdemux->header_size);
12301 if (size < qtdemux->header_size)
12304 size = size - qtdemux->header_size;
12306 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12307 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12311 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12312 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
12313 switch (str->subtype) {
12316 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12317 CUR_STREAM (str)->caps);
12318 /* retrieve bitrate, prefer avg then max */
12320 if (str->stream_tags) {
12321 if (gst_tag_list_get_uint (str->stream_tags,
12322 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12323 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12324 if (gst_tag_list_get_uint (str->stream_tags,
12325 GST_TAG_NOMINAL_BITRATE, &bitrate))
12326 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12327 if (gst_tag_list_get_uint (str->stream_tags,
12328 GST_TAG_BITRATE, &bitrate))
12329 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12332 sum_bitrate += bitrate;
12335 GST_DEBUG_OBJECT (qtdemux,
12336 ">1 stream with unknown bitrate - bailing");
12343 /* For other subtypes, we assume no significant impact on bitrate */
12349 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12353 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12355 if (sys_bitrate < sum_bitrate) {
12356 /* This can happen, since sum_bitrate might be derived from maximum
12357 * bitrates and not average bitrates */
12358 GST_DEBUG_OBJECT (qtdemux,
12359 "System bitrate less than sum bitrate - bailing");
12363 bitrate = sys_bitrate - sum_bitrate;
12364 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12365 ", Stream bitrate = %u", sys_bitrate, bitrate);
12367 if (!stream->stream_tags)
12368 stream->stream_tags = gst_tag_list_new_empty ();
12370 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12372 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12373 GST_TAG_BITRATE, bitrate, NULL);
12376 static GstFlowReturn
12377 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12379 GstFlowReturn ret = GST_FLOW_OK;
12380 GList *iter, *next;
12382 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12384 for (iter = qtdemux->active_streams; ret == GST_FLOW_OK && iter; iter = next) {
12385 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12386 guint32 sample_num = 0;
12390 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12391 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12393 if (qtdemux->fragmented) {
12394 /* need all moov samples first */
12395 GST_OBJECT_LOCK (qtdemux);
12396 while (stream->n_samples == 0)
12397 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12399 GST_OBJECT_UNLOCK (qtdemux);
12401 /* discard any stray moof */
12402 qtdemux->moof_offset = 0;
12405 /* prepare braking */
12406 if (ret != GST_FLOW_ERROR)
12409 /* in pull mode, we should have parsed some sample info by now;
12410 * and quite some code will not handle no samples.
12411 * in push mode, we'll just have to deal with it */
12412 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12413 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12414 gst_qtdemux_remove_stream (qtdemux, stream);
12416 } else if (stream->track_id == qtdemux->chapters_track_id &&
12417 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12418 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12419 so that it doesn't look like a subtitle track */
12420 gst_qtdemux_remove_stream (qtdemux, stream);
12424 /* parse the initial sample for use in setting the frame rate cap */
12425 while (sample_num == 0 && sample_num < stream->n_samples) {
12426 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12436 _stream_in_list (GList * list, QtDemuxStream * stream)
12440 for (iter = list; iter; iter = g_list_next (iter)) {
12441 QtDemuxStream *tmp = QTDEMUX_STREAM (iter->data);
12442 if (!g_strcmp0 (tmp->stream_id, stream->stream_id))
12450 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12454 if (!qtdemux->active_streams)
12457 /* streams in list are sorted in track-id order */
12458 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12459 new = g_list_next (new), old = g_list_next (old)) {
12461 /* Different stream-id, updated */
12462 if (g_strcmp0 (QTDEMUX_STREAM (new->data)->stream_id,
12463 QTDEMUX_STREAM (old->data)->stream_id))
12467 /* Different length, updated */
12468 if (new != NULL || old != NULL)
12475 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12476 QtDemuxStream * oldstream, QtDemuxStream * newstream)
12478 /* Connect old stream's srcpad to new stream */
12479 newstream->pad = oldstream->pad;
12480 oldstream->pad = NULL;
12482 /* unset new_stream to prevent stream-start event */
12483 newstream->new_stream = FALSE;
12485 return gst_qtdemux_configure_stream (qtdemux, newstream);
12489 qtdemux_update_streams (GstQTDemux * qtdemux)
12491 GList *iter, *next;
12492 g_assert (qtdemux->streams_aware);
12494 /* At below, figure out which stream in active_streams has identical stream-id
12495 * with that of in old_streams. If there is matching stream-id,
12496 * corresponding newstream will not be exposed again,
12497 * but demux will reuse srcpad of matched old stream
12499 * active_streams : newly created streams from the latest moov
12500 * old_streams : existing streams (belong to previous moov)
12503 /* Count n_streams again */
12504 qtdemux->n_streams = 0;
12506 for (iter = qtdemux->active_streams; iter; iter = next) {
12508 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12512 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12513 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12515 qtdemux->n_streams++;
12517 if ((tmp = _stream_in_list (qtdemux->old_streams, stream)) != NULL
12518 && QTDEMUX_STREAM (tmp->data)->pad) {
12519 QtDemuxStream *oldstream = QTDEMUX_STREAM (tmp->data);
12521 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12523 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12526 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, oldstream);
12527 gst_qtdemux_stream_free (oldstream);
12531 /* now we have all info and can expose */
12532 list = stream->stream_tags;
12533 stream->stream_tags = NULL;
12534 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12542 /* Must be called with expose lock */
12543 static GstFlowReturn
12544 qtdemux_expose_streams (GstQTDemux * qtdemux)
12546 GList *iter, *next;
12548 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12550 if (!qtdemux_is_streams_update (qtdemux)) {
12553 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12554 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12555 new = g_list_next (new), old = g_list_next (old)) {
12556 if (!qtdemux_reuse_and_configure_stream (qtdemux,
12557 QTDEMUX_STREAM (old->data), QTDEMUX_STREAM (new->data)))
12558 return GST_FLOW_ERROR;
12561 g_list_free_full (qtdemux->old_streams,
12562 (GDestroyNotify) gst_qtdemux_stream_free);
12563 qtdemux->old_streams = NULL;
12565 return GST_FLOW_OK;
12568 if (qtdemux->streams_aware) {
12569 if (!qtdemux_update_streams (qtdemux))
12570 return GST_FLOW_ERROR;
12572 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12573 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12576 /* now we have all info and can expose */
12577 list = stream->stream_tags;
12578 stream->stream_tags = NULL;
12579 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12580 return GST_FLOW_ERROR;
12585 gst_qtdemux_guess_bitrate (qtdemux);
12587 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12589 /* If we have still old_streams, it's no more used stream */
12590 for (iter = qtdemux->old_streams; iter; iter = next) {
12591 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12592 next = g_list_next (iter);
12597 event = gst_event_new_eos ();
12598 if (qtdemux->segment_seqnum)
12599 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12601 gst_pad_push_event (stream->pad, event);
12604 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, stream);
12605 gst_qtdemux_stream_free (stream);
12608 /* check if we should post a redirect in case there is a single trak
12609 * and it is a redirecting trak */
12610 if (qtdemux->n_streams == 1 &&
12611 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri != NULL) {
12614 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12615 "an external content");
12616 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12617 gst_structure_new ("redirect",
12618 "new-location", G_TYPE_STRING,
12619 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri, NULL));
12620 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12621 qtdemux->posted_redirect = TRUE;
12624 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12625 qtdemux_do_allocation (QTDEMUX_STREAM (iter->data), qtdemux);
12628 qtdemux->need_segment = TRUE;
12630 qtdemux->exposed = TRUE;
12631 return GST_FLOW_OK;
12634 /* check if major or compatible brand is 3GP */
12635 static inline gboolean
12636 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12639 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12641 } else if (qtdemux->comp_brands != NULL) {
12645 gboolean res = FALSE;
12647 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12650 while (size >= 4) {
12651 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12656 gst_buffer_unmap (qtdemux->comp_brands, &map);
12663 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12664 static inline gboolean
12665 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12667 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12668 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12669 || fourcc == FOURCC_albm;
12673 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12674 const char *tag, const char *dummy, GNode * node)
12676 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12680 gdouble longitude, latitude, altitude;
12683 len = QT_UINT32 (node->data);
12690 /* TODO: language code skipped */
12692 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12695 /* do not alarm in trivial case, but bail out otherwise */
12696 if (*(data + offset) != 0) {
12697 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12701 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12702 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12703 offset += strlen (name);
12707 if (len < offset + 2 + 4 + 4 + 4)
12710 /* +1 +1 = skip null-terminator and location role byte */
12712 /* table in spec says unsigned, semantics say negative has meaning ... */
12713 longitude = QT_SFP32 (data + offset);
12716 latitude = QT_SFP32 (data + offset);
12719 altitude = QT_SFP32 (data + offset);
12721 /* one invalid means all are invalid */
12722 if (longitude >= -180.0 && longitude <= 180.0 &&
12723 latitude >= -90.0 && latitude <= 90.0) {
12724 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12725 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12726 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12727 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12730 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12737 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12744 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12745 const char *tag, const char *dummy, GNode * node)
12751 len = QT_UINT32 (node->data);
12755 y = QT_UINT16 ((guint8 *) node->data + 12);
12757 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12760 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12762 date = g_date_new_dmy (1, 1, y);
12763 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12764 g_date_free (date);
12768 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12769 const char *tag, const char *dummy, GNode * node)
12772 char *tag_str = NULL;
12777 len = QT_UINT32 (node->data);
12782 entity = (guint8 *) node->data + offset;
12783 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12784 GST_DEBUG_OBJECT (qtdemux,
12785 "classification info: %c%c%c%c invalid classification entity",
12786 entity[0], entity[1], entity[2], entity[3]);
12791 table = QT_UINT16 ((guint8 *) node->data + offset);
12793 /* Language code skipped */
12797 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12798 * XXXX: classification entity, fixed length 4 chars.
12799 * Y[YYYY]: classification table, max 5 chars.
12801 tag_str = g_strdup_printf ("----://%u/%s",
12802 table, (char *) node->data + offset);
12804 /* memcpy To be sure we're preserving byte order */
12805 memcpy (tag_str, entity, 4);
12806 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12808 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12817 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12823 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12824 const char *tag, const char *dummy, GNode * node)
12826 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12832 gboolean ret = TRUE;
12833 const gchar *charset = NULL;
12835 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12837 len = QT_UINT32 (data->data);
12838 type = QT_UINT32 ((guint8 *) data->data + 8);
12839 if (type == 0x00000001 && len > 16) {
12840 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12843 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12844 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12847 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12851 len = QT_UINT32 (node->data);
12852 type = QT_UINT32 ((guint8 *) node->data + 4);
12853 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12857 /* Type starts with the (C) symbol, so the next data is a list
12858 * of (string size(16), language code(16), string) */
12860 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12861 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12863 /* the string + fourcc + size + 2 16bit fields,
12864 * means that there are more tags in this atom */
12865 if (len > str_len + 8 + 4) {
12866 /* TODO how to represent the same tag in different languages? */
12867 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12868 "text alternatives, reading only first one");
12872 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12873 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12875 if (lang_code < 0x800) { /* MAC encoded string */
12878 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12879 QT_FOURCC ((guint8 *) node->data + 4))) {
12880 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12882 /* we go for 3GP style encoding if major brands claims so,
12883 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12884 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12885 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12886 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12888 /* 16-bit Language code is ignored here as well */
12889 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12896 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12897 ret = FALSE; /* may have to fallback */
12900 GError *err = NULL;
12902 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12903 charset, NULL, NULL, &err);
12905 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12906 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12908 g_error_free (err);
12911 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12912 len - offset, env_vars);
12915 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12916 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12920 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12927 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12928 const char *tag, const char *dummy, GNode * node)
12930 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12934 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12935 const char *tag, const char *dummy, GNode * node)
12937 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12939 char *s, *t, *k = NULL;
12944 /* first try normal string tag if major brand not 3GP */
12945 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12946 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12947 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12948 * let's try it 3gpp way after minor safety check */
12950 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12956 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12960 len = QT_UINT32 (data);
12964 count = QT_UINT8 (data + 14);
12966 for (; count; count--) {
12969 if (offset + 1 > len)
12971 slen = QT_UINT8 (data + offset);
12973 if (offset + slen > len)
12975 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12978 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12980 t = g_strjoin (",", k, s, NULL);
12988 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12995 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12996 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
13005 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
13011 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
13012 const char *tag1, const char *tag2, GNode * node)
13019 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13021 len = QT_UINT32 (data->data);
13022 type = QT_UINT32 ((guint8 *) data->data + 8);
13023 if (type == 0x00000000 && len >= 22) {
13024 n1 = QT_UINT16 ((guint8 *) data->data + 18);
13025 n2 = QT_UINT16 ((guint8 *) data->data + 20);
13027 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
13028 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
13031 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
13032 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
13039 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
13040 const char *tag1, const char *dummy, GNode * node)
13047 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13049 len = QT_UINT32 (data->data);
13050 type = QT_UINT32 ((guint8 *) data->data + 8);
13051 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
13052 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13053 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
13054 n1 = QT_UINT16 ((guint8 *) data->data + 16);
13056 /* do not add bpm=0 */
13057 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
13058 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13066 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13067 const char *tag1, const char *dummy, GNode * node)
13074 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13076 len = QT_UINT32 (data->data);
13077 type = QT_UINT32 ((guint8 *) data->data + 8);
13078 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13079 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13080 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13081 num = QT_UINT32 ((guint8 *) data->data + 16);
13083 /* do not add num=0 */
13084 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13085 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13092 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13093 const char *tag1, const char *dummy, GNode * node)
13100 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13102 len = QT_UINT32 (data->data);
13103 type = QT_UINT32 ((guint8 *) data->data + 8);
13104 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13105 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13106 GstTagImageType image_type;
13108 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13109 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13111 image_type = GST_TAG_IMAGE_TYPE_NONE;
13114 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13115 len - 16, image_type))) {
13116 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13117 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13118 gst_sample_unref (sample);
13125 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
13126 const char *tag, const char *dummy, GNode * node)
13129 GstDateTime *datetime = NULL;
13134 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13136 len = QT_UINT32 (data->data);
13137 type = QT_UINT32 ((guint8 *) data->data + 8);
13138 if (type == 0x00000001 && len > 16) {
13139 guint y, m = 1, d = 1;
13142 s = g_strndup ((char *) data->data + 16, len - 16);
13143 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13144 datetime = gst_date_time_new_from_iso8601_string (s);
13145 if (datetime != NULL) {
13146 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13148 gst_date_time_unref (datetime);
13151 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13152 if (ret >= 1 && y > 1500 && y < 3000) {
13155 date = g_date_new_dmy (d, m, y);
13156 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13157 g_date_free (date);
13159 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13167 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13168 const char *tag, const char *dummy, GNode * node)
13172 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13174 /* re-route to normal string tag if major brand says so
13175 * or no data atom and compatible brand suggests so */
13176 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13177 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13178 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13183 guint len, type, n;
13185 len = QT_UINT32 (data->data);
13186 type = QT_UINT32 ((guint8 *) data->data + 8);
13187 if (type == 0x00000000 && len >= 18) {
13188 n = QT_UINT16 ((guint8 *) data->data + 16);
13190 const gchar *genre;
13192 genre = gst_tag_id3_genre_get (n - 1);
13193 if (genre != NULL) {
13194 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13195 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13203 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13204 const gchar * tag, guint8 * data, guint32 datasize)
13209 /* make a copy to have \0 at the end */
13210 datacopy = g_strndup ((gchar *) data, datasize);
13212 /* convert the str to double */
13213 if (sscanf (datacopy, "%lf", &value) == 1) {
13214 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13215 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13217 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13225 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13226 const char *tag, const char *tag_bis, GNode * node)
13235 const gchar *meanstr;
13236 const gchar *namestr;
13238 /* checking the whole ---- atom size for consistency */
13239 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13240 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13244 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13246 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13250 meansize = QT_UINT32 (mean->data);
13251 if (meansize <= 12) {
13252 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13255 meanstr = ((gchar *) mean->data) + 12;
13258 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13260 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13264 namesize = QT_UINT32 (name->data);
13265 if (namesize <= 12) {
13266 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13269 namestr = ((gchar *) name->data) + 12;
13277 * uint24 - data type
13281 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13283 GST_WARNING_OBJECT (demux, "No data atom in this tag");
13286 datasize = QT_UINT32 (data->data);
13287 if (datasize <= 16) {
13288 GST_WARNING_OBJECT (demux, "Data atom too small");
13291 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13293 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13294 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13295 static const struct
13297 const gchar name[28];
13298 const gchar tag[28];
13301 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13302 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13303 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13304 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13305 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13306 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13307 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13308 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13312 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13313 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13314 switch (gst_tag_get_type (tags[i].tag)) {
13315 case G_TYPE_DOUBLE:
13316 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13317 ((guint8 *) data->data) + 16, datasize - 16);
13319 case G_TYPE_STRING:
13320 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13329 if (i == G_N_ELEMENTS (tags))
13339 #ifndef GST_DISABLE_GST_DEBUG
13341 gchar *namestr_dbg;
13342 gchar *meanstr_dbg;
13344 meanstr_dbg = g_strndup (meanstr, meansize);
13345 namestr_dbg = g_strndup (namestr, namesize);
13347 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13348 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13350 g_free (namestr_dbg);
13351 g_free (meanstr_dbg);
13358 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13359 const char *tag_bis, GNode * node)
13364 GstTagList *id32_taglist = NULL;
13366 GST_LOG_OBJECT (demux, "parsing ID32");
13369 len = GST_READ_UINT32_BE (data);
13371 /* need at least full box and language tag */
13375 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13376 gst_buffer_fill (buf, 0, data + 14, len - 14);
13378 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13379 if (id32_taglist) {
13380 GST_LOG_OBJECT (demux, "parsing ok");
13381 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13382 gst_tag_list_unref (id32_taglist);
13384 GST_LOG_OBJECT (demux, "parsing failed");
13387 gst_buffer_unref (buf);
13390 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13391 const char *tag, const char *tag_bis, GNode * node);
13394 FOURCC_pcst -> if media is a podcast -> bool
13395 FOURCC_cpil -> if media is part of a compilation -> bool
13396 FOURCC_pgap -> if media is part of a gapless context -> bool
13397 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13400 static const struct
13403 const gchar *gst_tag;
13404 const gchar *gst_tag_bis;
13405 const GstQTDemuxAddTagFunc func;
13408 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13409 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13410 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13411 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13412 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13413 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13414 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13415 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13416 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13417 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13418 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13419 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13420 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13421 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13422 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13423 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13424 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13425 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13426 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13427 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13428 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13429 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13430 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13431 qtdemux_tag_add_num}, {
13432 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13433 qtdemux_tag_add_num}, {
13434 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13435 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13436 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13437 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13438 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13439 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13440 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13441 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13442 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13443 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13444 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13445 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13446 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13447 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13448 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13449 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13450 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13451 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13452 qtdemux_tag_add_classification}, {
13453 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13454 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13455 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13457 /* This is a special case, some tags are stored in this
13458 * 'reverse dns naming', according to:
13459 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13462 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13463 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13464 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13467 struct _GstQtDemuxTagList
13470 GstTagList *taglist;
13472 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13475 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13481 const gchar *style;
13486 GstQTDemux *demux = qtdemuxtaglist->demux;
13487 GstTagList *taglist = qtdemuxtaglist->taglist;
13490 len = QT_UINT32 (data);
13491 buf = gst_buffer_new_and_alloc (len);
13492 gst_buffer_fill (buf, 0, data, len);
13494 /* heuristic to determine style of tag */
13495 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13496 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13498 else if (demux->major_brand == FOURCC_qt__)
13499 style = "quicktime";
13500 /* fall back to assuming iso/3gp tag style */
13504 /* santize the name for the caps. */
13505 for (i = 0; i < 4; i++) {
13506 guint8 d = data[4 + i];
13507 if (g_ascii_isalnum (d))
13508 ndata[i] = g_ascii_tolower (d);
13513 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13514 ndata[0], ndata[1], ndata[2], ndata[3]);
13515 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13517 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13518 sample = gst_sample_new (buf, NULL, NULL, s);
13519 gst_buffer_unref (buf);
13520 g_free (media_type);
13522 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13525 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13526 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13528 gst_sample_unref (sample);
13532 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13539 GstQtDemuxTagList demuxtaglist;
13541 demuxtaglist.demux = qtdemux;
13542 demuxtaglist.taglist = taglist;
13544 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13545 if (meta != NULL) {
13546 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13547 if (ilst == NULL) {
13548 GST_LOG_OBJECT (qtdemux, "no ilst");
13553 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13557 while (i < G_N_ELEMENTS (add_funcs)) {
13558 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13562 len = QT_UINT32 (node->data);
13564 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13565 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13567 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13568 add_funcs[i].gst_tag_bis, node);
13570 g_node_destroy (node);
13576 /* parsed nodes have been removed, pass along remainder as blob */
13577 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13578 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13580 /* parse up XMP_ node if existing */
13581 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13582 if (xmp_ != NULL) {
13584 GstTagList *xmptaglist;
13586 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13587 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13588 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13589 gst_buffer_unref (buf);
13591 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13593 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13599 GstStructure *structure; /* helper for sort function */
13601 guint min_req_bitrate;
13602 guint min_req_qt_version;
13606 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13608 GstQtReference *ref_a = (GstQtReference *) a;
13609 GstQtReference *ref_b = (GstQtReference *) b;
13611 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13612 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13614 /* known bitrates go before unknown; higher bitrates go first */
13615 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13618 /* sort the redirects and post a message for the application.
13621 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13623 GstQtReference *best;
13626 GValue list_val = { 0, };
13629 g_assert (references != NULL);
13631 references = g_list_sort (references, qtdemux_redirects_sort_func);
13633 best = (GstQtReference *) references->data;
13635 g_value_init (&list_val, GST_TYPE_LIST);
13637 for (l = references; l != NULL; l = l->next) {
13638 GstQtReference *ref = (GstQtReference *) l->data;
13639 GValue struct_val = { 0, };
13641 ref->structure = gst_structure_new ("redirect",
13642 "new-location", G_TYPE_STRING, ref->location, NULL);
13644 if (ref->min_req_bitrate > 0) {
13645 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13646 ref->min_req_bitrate, NULL);
13649 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13650 g_value_set_boxed (&struct_val, ref->structure);
13651 gst_value_list_append_value (&list_val, &struct_val);
13652 g_value_unset (&struct_val);
13653 /* don't free anything here yet, since we need best->structure below */
13656 g_assert (best != NULL);
13657 s = gst_structure_copy (best->structure);
13659 if (g_list_length (references) > 1) {
13660 gst_structure_set_value (s, "locations", &list_val);
13663 g_value_unset (&list_val);
13665 for (l = references; l != NULL; l = l->next) {
13666 GstQtReference *ref = (GstQtReference *) l->data;
13668 gst_structure_free (ref->structure);
13669 g_free (ref->location);
13672 g_list_free (references);
13674 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13675 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13676 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13677 qtdemux->posted_redirect = TRUE;
13680 /* look for redirect nodes, collect all redirect information and
13684 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13686 GNode *rmra, *rmda, *rdrf;
13688 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13690 GList *redirects = NULL;
13692 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13694 GstQtReference ref = { NULL, NULL, 0, 0 };
13695 GNode *rmdr, *rmvc;
13697 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13698 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13699 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13700 ref.min_req_bitrate);
13703 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13704 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13705 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13707 #ifndef GST_DISABLE_GST_DEBUG
13708 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13710 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13712 GST_LOG_OBJECT (qtdemux,
13713 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13714 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13715 bitmask, check_type);
13716 if (package == FOURCC_qtim && check_type == 0) {
13717 ref.min_req_qt_version = version;
13721 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13727 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13728 if (ref_len > 20) {
13729 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13730 ref_data = (guint8 *) rdrf->data + 20;
13731 if (ref_type == FOURCC_alis) {
13732 guint record_len, record_version, fn_len;
13734 if (ref_len > 70) {
13735 /* MacOSX alias record, google for alias-layout.txt */
13736 record_len = QT_UINT16 (ref_data + 4);
13737 record_version = QT_UINT16 (ref_data + 4 + 2);
13738 fn_len = QT_UINT8 (ref_data + 50);
13739 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13740 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13743 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13746 } else if (ref_type == FOURCC_url_) {
13747 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13749 GST_DEBUG_OBJECT (qtdemux,
13750 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13751 GST_FOURCC_ARGS (ref_type));
13753 if (ref.location != NULL) {
13754 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13756 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13758 GST_WARNING_OBJECT (qtdemux,
13759 "Failed to extract redirect location from rdrf atom");
13762 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13766 /* look for others */
13767 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13770 if (redirects != NULL) {
13771 qtdemux_process_redirects (qtdemux, redirects);
13777 static GstTagList *
13778 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13782 if (tags == NULL) {
13783 tags = gst_tag_list_new_empty ();
13784 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13787 if (qtdemux->major_brand == FOURCC_mjp2)
13788 fmt = "Motion JPEG 2000";
13789 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13791 else if (qtdemux->major_brand == FOURCC_qt__)
13793 else if (qtdemux->fragmented)
13796 fmt = "ISO MP4/M4A";
13798 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13799 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13801 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13807 /* we have read the complete moov node now.
13808 * This function parses all of the relevant info, creates the traks and
13809 * prepares all data structures for playback
13812 qtdemux_parse_tree (GstQTDemux * qtdemux)
13819 guint64 creation_time;
13820 GstDateTime *datetime = NULL;
13823 /* make sure we have a usable taglist */
13824 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13826 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13827 if (mvhd == NULL) {
13828 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13829 return qtdemux_parse_redirects (qtdemux);
13832 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13833 if (version == 1) {
13834 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13835 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13836 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13837 } else if (version == 0) {
13838 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13839 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13840 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13842 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13846 /* Moving qt creation time (secs since 1904) to unix time */
13847 if (creation_time != 0) {
13848 /* Try to use epoch first as it should be faster and more commonly found */
13849 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13852 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13853 /* some data cleansing sanity */
13854 g_get_current_time (&now);
13855 if (now.tv_sec + 24 * 3600 < creation_time) {
13856 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13858 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13861 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13862 GDateTime *dt, *dt_local;
13864 dt = g_date_time_add_seconds (base_dt, creation_time);
13865 dt_local = g_date_time_to_local (dt);
13866 datetime = gst_date_time_new_from_g_date_time (dt_local);
13868 g_date_time_unref (base_dt);
13869 g_date_time_unref (dt);
13873 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13874 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13876 gst_date_time_unref (datetime);
13879 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13880 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13882 /* check for fragmented file and get some (default) data */
13883 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13886 GstByteReader mehd_data;
13888 /* let track parsing or anyone know weird stuff might happen ... */
13889 qtdemux->fragmented = TRUE;
13891 /* compensate for total duration */
13892 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13894 qtdemux_parse_mehd (qtdemux, &mehd_data);
13897 /* Update the movie segment duration, unless it was directly given to us
13898 * by upstream. Otherwise let it as is, as we don't want to mangle the
13899 * duration provided by upstream that may come e.g. from a MPD file. */
13900 if (!qtdemux->upstream_format_is_time) {
13901 GstClockTime duration;
13902 /* set duration in the segment info */
13903 gst_qtdemux_get_duration (qtdemux, &duration);
13904 qtdemux->segment.duration = duration;
13905 /* also do not exceed duration; stop is set that way post seek anyway,
13906 * and segment activation falls back to duration,
13907 * whereas loop only checks stop, so let's align this here as well */
13908 qtdemux->segment.stop = duration;
13911 /* parse all traks */
13912 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13914 qtdemux_parse_trak (qtdemux, trak);
13915 /* iterate all siblings */
13916 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13919 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13922 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13924 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13926 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13929 /* maybe also some tags in meta box */
13930 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13932 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13933 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13935 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13938 /* parse any protection system info */
13939 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13941 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13942 qtdemux_parse_pssh (qtdemux, pssh);
13943 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13946 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13951 /* taken from ffmpeg */
13953 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13965 len = (len << 7) | (c & 0x7f);
13974 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13975 gsize codec_data_size)
13977 GList *list = NULL;
13978 guint8 *p = codec_data;
13979 gint i, offset, num_packets;
13980 guint *length, last;
13982 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13984 if (codec_data == NULL || codec_data_size == 0)
13987 /* start of the stream and vorbis audio or theora video, need to
13988 * send the codec_priv data as first three packets */
13989 num_packets = p[0] + 1;
13990 GST_DEBUG_OBJECT (qtdemux,
13991 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13992 (guint) num_packets, codec_data_size);
13994 /* Let's put some limits, Don't think there even is a xiph codec
13995 * with more than 3-4 headers */
13996 if (G_UNLIKELY (num_packets > 16)) {
13997 GST_WARNING_OBJECT (qtdemux,
13998 "Unlikely number of xiph headers, most likely not valid");
14002 length = g_alloca (num_packets * sizeof (guint));
14006 /* first packets, read length values */
14007 for (i = 0; i < num_packets - 1; i++) {
14009 while (offset < codec_data_size) {
14010 length[i] += p[offset];
14011 if (p[offset++] != 0xff)
14016 if (offset + last > codec_data_size)
14019 /* last packet is the remaining size */
14020 length[i] = codec_data_size - offset - last;
14022 for (i = 0; i < num_packets; i++) {
14025 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14027 if (offset + length[i] > codec_data_size)
14030 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
14031 list = g_list_append (list, hdr);
14033 offset += length[i];
14042 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14048 /* this can change the codec originally present in @list */
14050 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14051 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14053 int len = QT_UINT32 (esds->data);
14054 guint8 *ptr = esds->data;
14055 guint8 *end = ptr + len;
14057 guint8 *data_ptr = NULL;
14059 guint8 object_type_id = 0;
14060 guint8 stream_type = 0;
14061 const char *codec_name = NULL;
14062 GstCaps *caps = NULL;
14064 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14066 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14068 while (ptr + 1 < end) {
14069 tag = QT_UINT8 (ptr);
14070 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14072 len = read_descr_size (ptr, end, &ptr);
14073 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14075 /* Check the stated amount of data is available for reading */
14076 if (len < 0 || ptr + len > end)
14080 case ES_DESCRIPTOR_TAG:
14081 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14082 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14085 case DECODER_CONFIG_DESC_TAG:{
14086 guint max_bitrate, avg_bitrate;
14088 object_type_id = QT_UINT8 (ptr);
14089 stream_type = QT_UINT8 (ptr + 1) >> 2;
14090 max_bitrate = QT_UINT32 (ptr + 5);
14091 avg_bitrate = QT_UINT32 (ptr + 9);
14092 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14093 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14094 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14095 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14096 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14097 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14098 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14099 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14101 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14102 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14103 avg_bitrate, NULL);
14108 case DECODER_SPECIFIC_INFO_TAG:
14109 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14110 if (object_type_id == 0xe0 && len == 0x40) {
14116 GST_DEBUG_OBJECT (qtdemux,
14117 "Have VOBSUB palette. Creating palette event");
14118 /* move to decConfigDescr data and read palette */
14120 for (i = 0; i < 16; i++) {
14121 clut[i] = QT_UINT32 (data);
14125 s = gst_structure_new ("application/x-gst-dvd", "event",
14126 G_TYPE_STRING, "dvd-spu-clut-change",
14127 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14128 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14129 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14130 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14131 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14132 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14133 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14134 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14137 /* store event and trigger custom processing */
14138 stream->pending_event =
14139 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14141 /* Generic codec_data handler puts it on the caps */
14148 case SL_CONFIG_DESC_TAG:
14149 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14153 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14155 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14161 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14162 * in use, and should also be used to override some other parameters for some
14164 switch (object_type_id) {
14165 case 0x20: /* MPEG-4 */
14166 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14167 * profile_and_level_indication */
14168 if (data_ptr != NULL && data_len >= 5 &&
14169 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14170 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14171 data_ptr + 4, data_len - 4);
14173 break; /* Nothing special needed here */
14174 case 0x21: /* H.264 */
14175 codec_name = "H.264 / AVC";
14176 caps = gst_caps_new_simple ("video/x-h264",
14177 "stream-format", G_TYPE_STRING, "avc",
14178 "alignment", G_TYPE_STRING, "au", NULL);
14180 case 0x40: /* AAC (any) */
14181 case 0x66: /* AAC Main */
14182 case 0x67: /* AAC LC */
14183 case 0x68: /* AAC SSR */
14184 /* Override channels and rate based on the codec_data, as it's often
14186 /* Only do so for basic setup without HE-AAC extension */
14187 if (data_ptr && data_len == 2) {
14188 guint channels, rate;
14190 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14192 entry->n_channels = channels;
14194 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14196 entry->rate = rate;
14199 /* Set level and profile if possible */
14200 if (data_ptr != NULL && data_len >= 2) {
14201 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14202 data_ptr, data_len);
14204 const gchar *profile_str = NULL;
14207 guint8 *codec_data;
14208 gint rate_idx, profile;
14210 /* No codec_data, let's invent something.
14211 * FIXME: This is wrong for SBR! */
14213 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14215 buffer = gst_buffer_new_and_alloc (2);
14216 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14217 codec_data = map.data;
14220 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14223 switch (object_type_id) {
14225 profile_str = "main";
14229 profile_str = "lc";
14233 profile_str = "ssr";
14241 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14243 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14245 gst_buffer_unmap (buffer, &map);
14246 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14247 GST_TYPE_BUFFER, buffer, NULL);
14248 gst_buffer_unref (buffer);
14251 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14252 G_TYPE_STRING, profile_str, NULL);
14256 case 0x60: /* MPEG-2, various profiles */
14262 codec_name = "MPEG-2 video";
14263 caps = gst_caps_new_simple ("video/mpeg",
14264 "mpegversion", G_TYPE_INT, 2,
14265 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14267 case 0x69: /* MPEG-2 BC audio */
14268 case 0x6B: /* MPEG-1 audio */
14269 caps = gst_caps_new_simple ("audio/mpeg",
14270 "mpegversion", G_TYPE_INT, 1, NULL);
14271 codec_name = "MPEG-1 audio";
14273 case 0x6A: /* MPEG-1 */
14274 codec_name = "MPEG-1 video";
14275 caps = gst_caps_new_simple ("video/mpeg",
14276 "mpegversion", G_TYPE_INT, 1,
14277 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14279 case 0x6C: /* MJPEG */
14281 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14283 codec_name = "Motion-JPEG";
14285 case 0x6D: /* PNG */
14287 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14289 codec_name = "PNG still images";
14291 case 0x6E: /* JPEG2000 */
14292 codec_name = "JPEG-2000";
14293 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14295 case 0xA4: /* Dirac */
14296 codec_name = "Dirac";
14297 caps = gst_caps_new_empty_simple ("video/x-dirac");
14299 case 0xA5: /* AC3 */
14300 codec_name = "AC-3 audio";
14301 caps = gst_caps_new_simple ("audio/x-ac3",
14302 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14304 case 0xA9: /* AC3 */
14305 codec_name = "DTS audio";
14306 caps = gst_caps_new_simple ("audio/x-dts",
14307 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14310 if (stream_type == 0x05 && data_ptr) {
14312 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14315 GValue arr_val = G_VALUE_INIT;
14316 GValue buf_val = G_VALUE_INIT;
14319 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14320 codec_name = "Vorbis";
14321 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14322 g_value_init (&arr_val, GST_TYPE_ARRAY);
14323 g_value_init (&buf_val, GST_TYPE_BUFFER);
14324 for (tmp = headers; tmp; tmp = tmp->next) {
14325 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14326 gst_value_array_append_value (&arr_val, &buf_val);
14328 s = gst_caps_get_structure (caps, 0);
14329 gst_structure_take_value (s, "streamheader", &arr_val);
14330 g_value_unset (&buf_val);
14331 g_list_free (headers);
14338 case 0xE1: /* QCELP */
14339 /* QCELP, the codec_data is a riff tag (little endian) with
14340 * 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). */
14341 caps = gst_caps_new_empty_simple ("audio/qcelp");
14342 codec_name = "QCELP";
14348 /* If we have a replacement caps, then change our caps for this stream */
14350 gst_caps_unref (entry->caps);
14351 entry->caps = caps;
14354 if (codec_name && list)
14355 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14356 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14358 /* Add the codec_data attribute to caps, if we have it */
14362 buffer = gst_buffer_new_and_alloc (data_len);
14363 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14365 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14366 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14368 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14370 gst_buffer_unref (buffer);
14375 static inline GstCaps *
14376 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14380 char *s, fourstr[5];
14382 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14383 for (i = 0; i < 4; i++) {
14384 if (!g_ascii_isalnum (fourstr[i]))
14387 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14388 caps = gst_caps_new_empty_simple (s);
14393 #define _codec(name) \
14395 if (codec_name) { \
14396 *codec_name = g_strdup (name); \
14401 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14402 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14403 const guint8 * stsd_entry_data, gchar ** codec_name)
14405 GstCaps *caps = NULL;
14406 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14410 _codec ("PNG still images");
14411 caps = gst_caps_new_empty_simple ("image/png");
14414 _codec ("JPEG still images");
14416 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14419 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14420 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14421 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14422 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14423 _codec ("Motion-JPEG");
14425 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14428 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14429 _codec ("Motion-JPEG format B");
14430 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14433 _codec ("JPEG-2000");
14434 /* override to what it should be according to spec, avoid palette_data */
14435 entry->bits_per_sample = 24;
14436 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14439 _codec ("Sorensen video v.3");
14440 caps = gst_caps_new_simple ("video/x-svq",
14441 "svqversion", G_TYPE_INT, 3, NULL);
14443 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14444 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14445 _codec ("Sorensen video v.1");
14446 caps = gst_caps_new_simple ("video/x-svq",
14447 "svqversion", G_TYPE_INT, 1, NULL);
14449 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14450 caps = gst_caps_new_empty_simple ("video/x-raw");
14451 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14452 _codec ("Windows Raw RGB");
14453 stream->alignment = 32;
14459 bps = QT_UINT16 (stsd_entry_data + 82);
14462 format = GST_VIDEO_FORMAT_RGB15;
14465 format = GST_VIDEO_FORMAT_RGB16;
14468 format = GST_VIDEO_FORMAT_RGB;
14471 format = GST_VIDEO_FORMAT_ARGB;
14479 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14480 format = GST_VIDEO_FORMAT_I420;
14482 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14483 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14484 format = GST_VIDEO_FORMAT_I420;
14487 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14488 format = GST_VIDEO_FORMAT_UYVY;
14490 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14491 format = GST_VIDEO_FORMAT_v308;
14493 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14494 format = GST_VIDEO_FORMAT_v216;
14497 format = GST_VIDEO_FORMAT_v210;
14499 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14500 format = GST_VIDEO_FORMAT_r210;
14502 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14503 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14504 format = GST_VIDEO_FORMAT_v410;
14507 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14508 * but different order than AYUV
14509 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14510 format = GST_VIDEO_FORMAT_v408;
14513 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14514 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14515 _codec ("MPEG-1 video");
14516 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14517 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14519 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14520 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14521 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14522 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14523 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14524 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14525 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14526 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14527 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14528 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14529 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14530 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14531 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14532 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14533 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14534 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14535 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14536 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14537 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14538 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14539 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14540 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14541 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14542 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14543 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14544 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14545 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14546 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14547 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14548 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14549 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14550 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14551 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14552 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14553 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14554 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14555 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14556 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14557 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14558 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14559 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14560 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14561 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14562 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14563 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14564 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14565 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14566 _codec ("MPEG-2 video");
14567 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14568 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14570 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14571 _codec ("GIF still images");
14572 caps = gst_caps_new_empty_simple ("image/gif");
14575 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14577 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14579 /* ffmpeg uses the height/width props, don't know why */
14580 caps = gst_caps_new_simple ("video/x-h263",
14581 "variant", G_TYPE_STRING, "itu", NULL);
14585 _codec ("MPEG-4 video");
14586 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14587 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14589 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14590 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14591 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14592 caps = gst_caps_new_simple ("video/x-msmpeg",
14593 "msmpegversion", G_TYPE_INT, 43, NULL);
14595 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14597 caps = gst_caps_new_simple ("video/x-divx",
14598 "divxversion", G_TYPE_INT, 3, NULL);
14600 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14601 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14603 caps = gst_caps_new_simple ("video/x-divx",
14604 "divxversion", G_TYPE_INT, 4, NULL);
14606 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14608 caps = gst_caps_new_simple ("video/x-divx",
14609 "divxversion", G_TYPE_INT, 5, NULL);
14612 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14614 caps = gst_caps_new_simple ("video/x-ffv",
14615 "ffvversion", G_TYPE_INT, 1, NULL);
14618 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14619 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14624 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14625 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14626 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14630 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14631 _codec ("Cinepak");
14632 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14634 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14635 _codec ("Apple QuickDraw");
14636 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14638 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14639 _codec ("Apple video");
14640 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14644 _codec ("H.264 / AVC");
14645 caps = gst_caps_new_simple ("video/x-h264",
14646 "stream-format", G_TYPE_STRING, "avc",
14647 "alignment", G_TYPE_STRING, "au", NULL);
14650 _codec ("H.264 / AVC");
14651 caps = gst_caps_new_simple ("video/x-h264",
14652 "stream-format", G_TYPE_STRING, "avc3",
14653 "alignment", G_TYPE_STRING, "au", NULL);
14657 _codec ("H.265 / HEVC");
14658 caps = gst_caps_new_simple ("video/x-h265",
14659 "stream-format", G_TYPE_STRING, "hvc1",
14660 "alignment", G_TYPE_STRING, "au", NULL);
14663 _codec ("H.265 / HEVC");
14664 caps = gst_caps_new_simple ("video/x-h265",
14665 "stream-format", G_TYPE_STRING, "hev1",
14666 "alignment", G_TYPE_STRING, "au", NULL);
14669 _codec ("Run-length encoding");
14670 caps = gst_caps_new_simple ("video/x-rle",
14671 "layout", G_TYPE_STRING, "quicktime", NULL);
14674 _codec ("Run-length encoding");
14675 caps = gst_caps_new_simple ("video/x-rle",
14676 "layout", G_TYPE_STRING, "microsoft", NULL);
14678 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14679 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14680 _codec ("Indeo Video 3");
14681 caps = gst_caps_new_simple ("video/x-indeo",
14682 "indeoversion", G_TYPE_INT, 3, NULL);
14684 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14685 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14686 _codec ("Intel Video 4");
14687 caps = gst_caps_new_simple ("video/x-indeo",
14688 "indeoversion", G_TYPE_INT, 4, NULL);
14692 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14693 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14694 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14695 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14696 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14697 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14698 _codec ("DV Video");
14699 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14700 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14702 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14703 case FOURCC_dv5p: /* DVCPRO50 PAL */
14704 _codec ("DVCPro50 Video");
14705 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14706 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14708 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14709 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14710 _codec ("DVCProHD Video");
14711 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14712 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14714 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14715 _codec ("Apple Graphics (SMC)");
14716 caps = gst_caps_new_empty_simple ("video/x-smc");
14718 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14720 caps = gst_caps_new_empty_simple ("video/x-vp3");
14722 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14723 _codec ("VP6 Flash");
14724 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14728 caps = gst_caps_new_empty_simple ("video/x-theora");
14729 /* theora uses one byte of padding in the data stream because it does not
14730 * allow 0 sized packets while theora does */
14731 entry->padding = 1;
14735 caps = gst_caps_new_empty_simple ("video/x-dirac");
14737 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14738 _codec ("TIFF still images");
14739 caps = gst_caps_new_empty_simple ("image/tiff");
14741 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14742 _codec ("Apple Intermediate Codec");
14743 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14745 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14746 _codec ("AVID DNxHD");
14747 caps = gst_caps_from_string ("video/x-dnxhd");
14751 _codec ("On2 VP8");
14752 caps = gst_caps_from_string ("video/x-vp8");
14755 _codec ("Google VP9");
14756 caps = gst_caps_from_string ("video/x-vp9");
14759 _codec ("Apple ProRes LT");
14761 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14765 _codec ("Apple ProRes HQ");
14767 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14771 _codec ("Apple ProRes");
14773 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14777 _codec ("Apple ProRes Proxy");
14779 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14783 _codec ("Apple ProRes 4444");
14785 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14789 _codec ("Apple ProRes 4444 XQ");
14791 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14795 _codec ("GoPro CineForm");
14796 caps = gst_caps_from_string ("video/x-cineform");
14801 caps = gst_caps_new_simple ("video/x-wmv",
14802 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14806 caps = gst_caps_new_empty_simple ("video/x-av1");
14808 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14811 caps = _get_unknown_codec_name ("video", fourcc);
14816 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14819 gst_video_info_init (&info);
14820 gst_video_info_set_format (&info, format, entry->width, entry->height);
14822 caps = gst_video_info_to_caps (&info);
14823 *codec_name = gst_pb_utils_get_codec_description (caps);
14825 /* enable clipping for raw video streams */
14826 stream->need_clip = TRUE;
14827 stream->alignment = 32;
14834 round_up_pow2 (guint n)
14846 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14847 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14848 int len, gchar ** codec_name)
14851 const GstStructure *s;
14854 GstAudioFormat format = 0;
14857 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14859 depth = entry->bytes_per_packet * 8;
14862 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14864 /* 8-bit audio is unsigned */
14866 format = GST_AUDIO_FORMAT_U8;
14867 /* otherwise it's signed and big-endian just like 'twos' */
14869 endian = G_BIG_ENDIAN;
14876 endian = G_LITTLE_ENDIAN;
14879 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14881 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14885 caps = gst_caps_new_simple ("audio/x-raw",
14886 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14887 "layout", G_TYPE_STRING, "interleaved", NULL);
14888 stream->alignment = GST_ROUND_UP_8 (depth);
14889 stream->alignment = round_up_pow2 (stream->alignment);
14892 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14893 _codec ("Raw 64-bit floating-point audio");
14894 caps = gst_caps_new_simple ("audio/x-raw",
14895 "format", G_TYPE_STRING, "F64BE",
14896 "layout", G_TYPE_STRING, "interleaved", NULL);
14897 stream->alignment = 8;
14899 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14900 _codec ("Raw 32-bit floating-point audio");
14901 caps = gst_caps_new_simple ("audio/x-raw",
14902 "format", G_TYPE_STRING, "F32BE",
14903 "layout", G_TYPE_STRING, "interleaved", NULL);
14904 stream->alignment = 4;
14907 _codec ("Raw 24-bit PCM audio");
14908 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14910 caps = gst_caps_new_simple ("audio/x-raw",
14911 "format", G_TYPE_STRING, "S24BE",
14912 "layout", G_TYPE_STRING, "interleaved", NULL);
14913 stream->alignment = 4;
14915 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14916 _codec ("Raw 32-bit PCM audio");
14917 caps = gst_caps_new_simple ("audio/x-raw",
14918 "format", G_TYPE_STRING, "S32BE",
14919 "layout", G_TYPE_STRING, "interleaved", NULL);
14920 stream->alignment = 4;
14922 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14923 _codec ("Raw 16-bit PCM audio");
14924 caps = gst_caps_new_simple ("audio/x-raw",
14925 "format", G_TYPE_STRING, "S16LE",
14926 "layout", G_TYPE_STRING, "interleaved", NULL);
14927 stream->alignment = 2;
14930 _codec ("Mu-law audio");
14931 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14934 _codec ("A-law audio");
14935 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14939 _codec ("Microsoft ADPCM");
14940 /* Microsoft ADPCM-ACM code 2 */
14941 caps = gst_caps_new_simple ("audio/x-adpcm",
14942 "layout", G_TYPE_STRING, "microsoft", NULL);
14946 _codec ("DVI/IMA ADPCM");
14947 caps = gst_caps_new_simple ("audio/x-adpcm",
14948 "layout", G_TYPE_STRING, "dvi", NULL);
14952 _codec ("DVI/Intel IMA ADPCM");
14953 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14954 caps = gst_caps_new_simple ("audio/x-adpcm",
14955 "layout", G_TYPE_STRING, "quicktime", NULL);
14959 /* MPEG layer 3, CBR only (pre QT4.1) */
14961 _codec ("MPEG-1 layer 3");
14962 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14963 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14964 "mpegversion", G_TYPE_INT, 1, NULL);
14966 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14967 _codec ("MPEG-1 layer 2");
14969 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14970 "mpegversion", G_TYPE_INT, 1, NULL);
14973 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14974 _codec ("EAC-3 audio");
14975 caps = gst_caps_new_simple ("audio/x-eac3",
14976 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14977 entry->sampled = TRUE;
14979 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14981 _codec ("AC-3 audio");
14982 caps = gst_caps_new_simple ("audio/x-ac3",
14983 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14984 entry->sampled = TRUE;
14986 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14987 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14988 _codec ("DTS audio");
14989 caps = gst_caps_new_simple ("audio/x-dts",
14990 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14991 entry->sampled = TRUE;
14993 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14994 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14995 _codec ("DTS-HD audio");
14996 caps = gst_caps_new_simple ("audio/x-dts",
14997 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14998 entry->sampled = TRUE;
15002 caps = gst_caps_new_simple ("audio/x-mace",
15003 "maceversion", G_TYPE_INT, 3, NULL);
15007 caps = gst_caps_new_simple ("audio/x-mace",
15008 "maceversion", G_TYPE_INT, 6, NULL);
15010 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15012 caps = gst_caps_new_empty_simple ("application/ogg");
15014 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15015 _codec ("DV audio");
15016 caps = gst_caps_new_empty_simple ("audio/x-dv");
15019 _codec ("MPEG-4 AAC audio");
15020 caps = gst_caps_new_simple ("audio/mpeg",
15021 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15022 "stream-format", G_TYPE_STRING, "raw", NULL);
15024 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15025 _codec ("QDesign Music");
15026 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15029 _codec ("QDesign Music v.2");
15030 /* FIXME: QDesign music version 2 (no constant) */
15031 if (FALSE && data) {
15032 caps = gst_caps_new_simple ("audio/x-qdm2",
15033 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15034 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15035 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15037 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15041 _codec ("GSM audio");
15042 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15045 _codec ("AMR audio");
15046 caps = gst_caps_new_empty_simple ("audio/AMR");
15049 _codec ("AMR-WB audio");
15050 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15053 _codec ("Quicktime IMA ADPCM");
15054 caps = gst_caps_new_simple ("audio/x-adpcm",
15055 "layout", G_TYPE_STRING, "quicktime", NULL);
15058 _codec ("Apple lossless audio");
15059 caps = gst_caps_new_empty_simple ("audio/x-alac");
15062 _codec ("Free Lossless Audio Codec");
15063 caps = gst_caps_new_simple ("audio/x-flac",
15064 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15066 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15067 _codec ("QualComm PureVoice");
15068 caps = gst_caps_from_string ("audio/qcelp");
15073 caps = gst_caps_new_empty_simple ("audio/x-wma");
15077 caps = gst_caps_new_empty_simple ("audio/x-opus");
15084 GstAudioFormat format;
15087 FLAG_IS_FLOAT = 0x1,
15088 FLAG_IS_BIG_ENDIAN = 0x2,
15089 FLAG_IS_SIGNED = 0x4,
15090 FLAG_IS_PACKED = 0x8,
15091 FLAG_IS_ALIGNED_HIGH = 0x10,
15092 FLAG_IS_NON_INTERLEAVED = 0x20
15094 _codec ("Raw LPCM audio");
15096 if (data && len >= 36) {
15097 depth = QT_UINT32 (data + 24);
15098 flags = QT_UINT32 (data + 28);
15099 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15101 if ((flags & FLAG_IS_FLOAT) == 0) {
15106 if ((flags & FLAG_IS_ALIGNED_HIGH))
15109 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15110 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15111 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15112 caps = gst_caps_new_simple ("audio/x-raw",
15113 "format", G_TYPE_STRING,
15115 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15116 "UNKNOWN", "layout", G_TYPE_STRING,
15117 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15118 "interleaved", NULL);
15119 stream->alignment = GST_ROUND_UP_8 (depth);
15120 stream->alignment = round_up_pow2 (stream->alignment);
15125 if (flags & FLAG_IS_BIG_ENDIAN)
15126 format = GST_AUDIO_FORMAT_F64BE;
15128 format = GST_AUDIO_FORMAT_F64LE;
15130 if (flags & FLAG_IS_BIG_ENDIAN)
15131 format = GST_AUDIO_FORMAT_F32BE;
15133 format = GST_AUDIO_FORMAT_F32LE;
15135 caps = gst_caps_new_simple ("audio/x-raw",
15136 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15137 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15138 "non-interleaved" : "interleaved", NULL);
15139 stream->alignment = width / 8;
15143 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15147 caps = _get_unknown_codec_name ("audio", fourcc);
15153 GstCaps *templ_caps =
15154 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15155 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15156 gst_caps_unref (caps);
15157 gst_caps_unref (templ_caps);
15158 caps = intersection;
15161 /* enable clipping for raw audio streams */
15162 s = gst_caps_get_structure (caps, 0);
15163 name = gst_structure_get_name (s);
15164 if (g_str_has_prefix (name, "audio/x-raw")) {
15165 stream->need_clip = TRUE;
15166 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15167 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15173 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15174 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15175 const guint8 * stsd_entry_data, gchar ** codec_name)
15179 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15183 _codec ("DVD subtitle");
15184 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15185 stream->need_process = TRUE;
15188 _codec ("Quicktime timed text");
15191 _codec ("3GPP timed text");
15193 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15195 /* actual text piece needs to be extracted */
15196 stream->need_process = TRUE;
15199 _codec ("XML subtitles");
15200 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15203 _codec ("CEA 608 Closed Caption");
15205 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15206 G_TYPE_STRING, "cc_data", NULL);
15207 stream->need_process = TRUE;
15210 _codec ("CEA 708 Closed Caption");
15212 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15213 G_TYPE_STRING, "cdp", NULL);
15214 stream->need_process = TRUE;
15219 caps = _get_unknown_codec_name ("text", fourcc);
15227 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15228 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15229 const guint8 * stsd_entry_data, gchar ** codec_name)
15235 _codec ("MPEG 1 video");
15236 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15237 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15247 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15248 const gchar * system_id)
15252 if (!qtdemux->protection_system_ids)
15253 qtdemux->protection_system_ids =
15254 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15255 /* Check whether we already have an entry for this system ID. */
15256 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15257 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15258 if (g_ascii_strcasecmp (system_id, id) == 0) {
15262 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15263 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,