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 (GstQTDemux * qtdemux,
585 QtDemuxStream * stream);
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_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2751 QtDemuxStream *stream;
2752 GstStructure *structure;
2753 QtDemuxCencSampleSetInfo *ss_info = NULL;
2754 const gchar *system_id;
2755 gboolean uses_sub_sample_encryption = FALSE;
2756 guint32 sample_count;
2758 stream = QTDEMUX_FIRST_STREAM (qtdemux);
2762 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2763 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2764 GST_WARNING_OBJECT (qtdemux,
2765 "Attempting PIFF box parsing on an unencrypted stream.");
2769 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2770 G_TYPE_STRING, &system_id, NULL);
2771 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2773 stream->protected = TRUE;
2774 stream->protection_scheme_type = FOURCC_cenc;
2776 if (!stream->protection_scheme_info)
2777 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2779 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2781 if (ss_info->default_properties)
2782 gst_structure_free (ss_info->default_properties);
2784 ss_info->default_properties =
2785 gst_structure_new ("application/x-cenc",
2786 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2788 if (ss_info->crypto_info) {
2789 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2790 g_ptr_array_free (ss_info->crypto_info, TRUE);
2791 ss_info->crypto_info = NULL;
2795 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2797 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2798 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2802 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2803 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2807 if ((flags & 0x000001)) {
2808 guint32 algorithm_id = 0;
2811 gboolean is_encrypted = TRUE;
2813 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2814 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2819 if (algorithm_id == 0) {
2820 is_encrypted = FALSE;
2821 } else if (algorithm_id == 1) {
2822 /* FIXME: maybe store this in properties? */
2823 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2824 } else if (algorithm_id == 2) {
2825 /* FIXME: maybe store this in properties? */
2826 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2829 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2832 if (!gst_byte_reader_get_data (&br, 16, &kid))
2835 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2836 gst_buffer_fill (kid_buf, 0, kid, 16);
2837 if (ss_info->default_properties)
2838 gst_structure_free (ss_info->default_properties);
2839 ss_info->default_properties =
2840 gst_structure_new ("application/x-cenc",
2841 "iv_size", G_TYPE_UINT, iv_size,
2842 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2843 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2844 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2845 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2846 gst_buffer_unref (kid_buf);
2847 } else if ((flags & 0x000002)) {
2848 uses_sub_sample_encryption = TRUE;
2851 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2852 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2856 ss_info->crypto_info =
2857 g_ptr_array_new_full (sample_count,
2858 (GDestroyNotify) qtdemux_gst_structure_free);
2860 for (i = 0; i < sample_count; ++i) {
2861 GstStructure *properties;
2865 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2866 if (properties == NULL) {
2867 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2868 qtdemux->cenc_aux_sample_count = i;
2872 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2873 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2874 gst_structure_free (properties);
2875 qtdemux->cenc_aux_sample_count = i;
2878 buf = gst_buffer_new_wrapped (data, iv_size);
2879 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2880 gst_buffer_unref (buf);
2882 if (uses_sub_sample_encryption) {
2883 guint16 n_subsamples;
2885 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2886 || n_subsamples == 0) {
2887 GST_ERROR_OBJECT (qtdemux,
2888 "failed to get subsample count for sample %u", i);
2889 gst_structure_free (properties);
2890 qtdemux->cenc_aux_sample_count = i;
2893 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2894 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2895 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2897 gst_structure_free (properties);
2898 qtdemux->cenc_aux_sample_count = i;
2901 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2902 gst_structure_set (properties,
2903 "subsample_count", G_TYPE_UINT, n_subsamples,
2904 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2905 gst_buffer_unref (buf);
2907 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2910 g_ptr_array_add (ss_info->crypto_info, properties);
2913 qtdemux->cenc_aux_sample_count = sample_count;
2917 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2919 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2920 0x97, 0xA9, 0x42, 0xE8,
2921 0x9C, 0x71, 0x99, 0x94,
2922 0x91, 0xE3, 0xAF, 0xAC
2924 static const guint8 playready_uuid[] = {
2925 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2926 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2929 static const guint8 piff_sample_encryption_uuid[] = {
2930 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2931 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2936 /* counts as header data */
2937 qtdemux->header_size += length;
2939 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2941 if (length <= offset + 16) {
2942 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2946 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2948 GstTagList *taglist;
2950 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2951 length - offset - 16, NULL);
2952 taglist = gst_tag_list_from_xmp_buffer (buf);
2953 gst_buffer_unref (buf);
2955 /* make sure we have a usable taglist */
2956 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2958 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2960 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2962 const gunichar2 *s_utf16;
2965 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2966 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2967 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2968 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2972 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2973 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2975 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
2976 qtdemux_parse_piff (qtdemux, buffer, length, offset);
2978 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2979 GST_READ_UINT32_LE (buffer + offset),
2980 GST_READ_UINT32_LE (buffer + offset + 4),
2981 GST_READ_UINT32_LE (buffer + offset + 8),
2982 GST_READ_UINT32_LE (buffer + offset + 12));
2987 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2989 GstSidxParser sidx_parser;
2990 GstIsoffParserResult res;
2993 gst_isoff_qt_sidx_parser_init (&sidx_parser);
2996 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
2998 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
2999 if (res == GST_ISOFF_QT_PARSER_DONE) {
3000 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3002 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3005 /* caller verifies at least 8 bytes in buf */
3007 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3008 guint64 * plength, guint32 * pfourcc)
3013 length = QT_UINT32 (data);
3014 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3015 fourcc = QT_FOURCC (data + 4);
3016 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3019 length = G_MAXUINT64;
3020 } else if (length == 1 && size >= 16) {
3021 /* this means we have an extended size, which is the 64 bit value of
3022 * the next 8 bytes */
3023 length = QT_UINT64 (data + 8);
3024 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3034 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3036 guint32 version = 0;
3037 GstClockTime duration = 0;
3039 if (!gst_byte_reader_get_uint32_be (br, &version))
3044 if (!gst_byte_reader_get_uint64_be (br, &duration))
3049 if (!gst_byte_reader_get_uint32_be (br, &dur))
3054 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3055 qtdemux->duration = duration;
3061 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3067 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3068 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3070 if (!stream->parsed_trex && qtdemux->moov_node) {
3072 GstByteReader trex_data;
3074 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3076 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3079 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3081 /* skip version/flags */
3082 if (!gst_byte_reader_skip (&trex_data, 4))
3084 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3086 if (id != stream->track_id)
3088 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3090 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3092 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3094 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3097 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3098 "duration %d, size %d, flags 0x%x", stream->track_id,
3101 stream->parsed_trex = TRUE;
3102 stream->def_sample_description_index = sdi;
3103 stream->def_sample_duration = dur;
3104 stream->def_sample_size = size;
3105 stream->def_sample_flags = flags;
3108 /* iterate all siblings */
3109 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3115 *ds_duration = stream->def_sample_duration;
3116 *ds_size = stream->def_sample_size;
3117 *ds_flags = stream->def_sample_flags;
3119 /* even then, above values are better than random ... */
3120 if (G_UNLIKELY (!stream->parsed_trex)) {
3121 GST_WARNING_OBJECT (qtdemux,
3122 "failed to find fragment defaults for stream %d", stream->track_id);
3129 /* This method should be called whenever a more accurate duration might
3130 * have been found. It will update all relevant variables if/where needed
3133 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3137 GstClockTime prevdur;
3140 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3142 if (movdur > qtdemux->duration) {
3143 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3144 GST_DEBUG_OBJECT (qtdemux,
3145 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3146 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3147 qtdemux->duration = movdur;
3148 GST_DEBUG_OBJECT (qtdemux,
3149 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3150 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3151 GST_TIME_ARGS (qtdemux->segment.stop));
3152 if (qtdemux->segment.duration == prevdur) {
3153 /* If the current segment has duration/stop identical to previous duration
3154 * update them also (because they were set at that point in time with
3155 * the wrong duration */
3156 /* We convert the value *from* the timescale version to avoid rounding errors */
3157 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3158 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3159 qtdemux->segment.duration = fixeddur;
3160 qtdemux->segment.stop = fixeddur;
3163 for (iter = qtdemux->active_streams, i = 0; iter;
3164 iter = g_list_next (iter), i++) {
3165 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3167 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3168 if (movdur > stream->duration) {
3169 GST_DEBUG_OBJECT (qtdemux,
3170 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3171 GST_TIME_ARGS (duration));
3172 stream->duration = movdur;
3173 /* internal duration tracking state has been updated above, so */
3174 /* preserve an open-ended dummy segment rather than repeatedly updating
3175 * it and spamming downstream accordingly with segment events */
3176 if (stream->dummy_segment &&
3177 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3178 /* Update all dummy values to new duration */
3179 stream->segments[0].stop_time = duration;
3180 stream->segments[0].duration = duration;
3181 stream->segments[0].media_stop = duration;
3183 /* let downstream know we possibly have a new stop time */
3184 if (stream->segment_index != -1) {
3187 if (qtdemux->segment.rate >= 0) {
3188 pos = stream->segment.start;
3190 pos = stream->segment.stop;
3193 gst_qtdemux_stream_update_segment (qtdemux, stream,
3194 stream->segment_index, pos, NULL, NULL);
3202 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3203 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3204 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3205 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3208 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3210 gint32 data_offset = 0;
3211 guint32 flags = 0, first_flags = 0, samples_count = 0;
3214 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3215 QtDemuxSample *sample;
3216 gboolean ismv = FALSE;
3217 gint64 initial_offset;
3219 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3220 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3221 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3222 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3224 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3225 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3229 /* presence of stss or not can't really tell us much,
3230 * and flags and so on tend to be marginally reliable in these files */
3231 if (stream->subtype == FOURCC_soun) {
3232 GST_DEBUG_OBJECT (qtdemux,
3233 "sound track in fragmented file; marking all keyframes");
3234 stream->all_keyframe = TRUE;
3237 if (!gst_byte_reader_skip (trun, 1) ||
3238 !gst_byte_reader_get_uint24_be (trun, &flags))
3241 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3244 if (flags & TR_DATA_OFFSET) {
3245 /* note this is really signed */
3246 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3248 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3249 /* default base offset = first byte of moof */
3250 if (*base_offset == -1) {
3251 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3252 *base_offset = moof_offset;
3254 *running_offset = *base_offset + data_offset;
3256 /* if no offset at all, that would mean data starts at moof start,
3257 * which is a bit wrong and is ismv crappy way, so compensate
3258 * assuming data is in mdat following moof */
3259 if (*base_offset == -1) {
3260 *base_offset = moof_offset + moof_length + 8;
3261 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3264 if (*running_offset == -1)
3265 *running_offset = *base_offset;
3268 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3270 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3271 data_offset, flags, samples_count);
3273 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3274 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3275 GST_DEBUG_OBJECT (qtdemux,
3276 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3277 flags ^= TR_FIRST_SAMPLE_FLAGS;
3279 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3281 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3285 /* FIXME ? spec says other bits should also be checked to determine
3286 * entry size (and prefix size for that matter) */
3288 dur_offset = size_offset = 0;
3289 if (flags & TR_SAMPLE_DURATION) {
3290 GST_LOG_OBJECT (qtdemux, "entry duration present");
3291 dur_offset = entry_size;
3294 if (flags & TR_SAMPLE_SIZE) {
3295 GST_LOG_OBJECT (qtdemux, "entry size present");
3296 size_offset = entry_size;
3299 if (flags & TR_SAMPLE_FLAGS) {
3300 GST_LOG_OBJECT (qtdemux, "entry flags present");
3301 flags_offset = entry_size;
3304 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3305 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3306 ct_offset = entry_size;
3310 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3312 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3314 if (stream->n_samples + samples_count >=
3315 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3318 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3319 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3320 (stream->n_samples + samples_count) *
3321 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3323 /* create a new array of samples if it's the first sample parsed */
3324 if (stream->n_samples == 0) {
3325 g_assert (stream->samples == NULL);
3326 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3327 /* or try to reallocate it with space enough to insert the new samples */
3329 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3330 stream->n_samples + samples_count);
3331 if (stream->samples == NULL)
3334 if (qtdemux->fragment_start != -1) {
3335 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3336 qtdemux->fragment_start = -1;
3338 if (stream->n_samples == 0) {
3339 if (decode_ts > 0) {
3340 timestamp = decode_ts;
3341 } else if (stream->pending_seek != NULL) {
3342 /* if we don't have a timestamp from a tfdt box, we'll use the one
3343 * from the mfra seek table */
3344 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3345 GST_TIME_ARGS (stream->pending_seek->ts));
3347 /* FIXME: this is not fully correct, the timestamp refers to the random
3348 * access sample refered to in the tfra entry, which may not necessarily
3349 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3350 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3355 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3356 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3357 GST_TIME_ARGS (gst_ts));
3359 /* subsequent fragments extend stream */
3361 stream->samples[stream->n_samples - 1].timestamp +
3362 stream->samples[stream->n_samples - 1].duration;
3364 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3365 * difference (1 sec.) between decode_ts and timestamp, prefer the
3367 if (has_tfdt && !qtdemux->upstream_format_is_time
3368 && ABSDIFF (decode_ts, timestamp) >
3369 MAX (stream->duration_last_moof / 2,
3370 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3371 GST_INFO_OBJECT (qtdemux,
3372 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3373 ") are significantly different (more than %" GST_TIME_FORMAT
3374 "), using decode_ts",
3375 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3376 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3377 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3378 MAX (stream->duration_last_moof / 2,
3379 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3380 timestamp = decode_ts;
3383 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3384 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3385 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3389 initial_offset = *running_offset;
3391 sample = stream->samples + stream->n_samples;
3392 for (i = 0; i < samples_count; i++) {
3393 guint32 dur, size, sflags, ct;
3395 /* first read sample data */
3396 if (flags & TR_SAMPLE_DURATION) {
3397 dur = QT_UINT32 (data + dur_offset);
3399 dur = d_sample_duration;
3401 if (flags & TR_SAMPLE_SIZE) {
3402 size = QT_UINT32 (data + size_offset);
3404 size = d_sample_size;
3406 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3408 sflags = first_flags;
3410 sflags = d_sample_flags;
3412 } else if (flags & TR_SAMPLE_FLAGS) {
3413 sflags = QT_UINT32 (data + flags_offset);
3415 sflags = d_sample_flags;
3417 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3418 ct = QT_UINT32 (data + ct_offset);
3424 /* fill the sample information */
3425 sample->offset = *running_offset;
3426 sample->pts_offset = ct;
3427 sample->size = size;
3428 sample->timestamp = timestamp;
3429 sample->duration = dur;
3430 /* sample-is-difference-sample */
3431 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3432 * now idea how it relates to bitfield other than massive LE/BE confusion */
3433 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3434 *running_offset += size;
3436 stream->duration_moof += dur;
3440 /* Update total duration if needed */
3441 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3443 /* Pre-emptively figure out size of mdat based on trun information.
3444 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3445 * size, else we will still be able to use this when dealing with gap'ed
3447 qtdemux->mdatleft = *running_offset - initial_offset;
3448 qtdemux->mdatoffset = initial_offset;
3449 qtdemux->mdatsize = qtdemux->mdatleft;
3451 stream->n_samples += samples_count;
3452 stream->n_samples_moof += samples_count;
3454 if (stream->pending_seek != NULL)
3455 stream->pending_seek = NULL;
3461 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3466 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3472 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3473 "be larger than %uMB (broken file?)", stream->n_samples,
3474 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3479 /* find stream with @id */
3480 static inline QtDemuxStream *
3481 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3483 QtDemuxStream *stream;
3487 if (G_UNLIKELY (!id)) {
3488 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3492 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3493 stream = QTDEMUX_STREAM (iter->data);
3494 if (stream->track_id == id)
3497 if (qtdemux->mss_mode) {
3498 /* mss should have only 1 stream anyway */
3499 return QTDEMUX_FIRST_STREAM (qtdemux);
3506 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3507 guint32 * fragment_number)
3509 if (!gst_byte_reader_skip (mfhd, 4))
3511 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3516 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3522 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3523 QtDemuxStream ** stream, guint32 * default_sample_duration,
3524 guint32 * default_sample_size, guint32 * default_sample_flags,
3525 gint64 * base_offset)
3528 guint32 track_id = 0;
3530 if (!gst_byte_reader_skip (tfhd, 1) ||
3531 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3534 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3537 *stream = qtdemux_find_stream (qtdemux, track_id);
3538 if (G_UNLIKELY (!*stream))
3539 goto unknown_stream;
3541 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3542 *base_offset = qtdemux->moof_offset;
3544 if (flags & TF_BASE_DATA_OFFSET)
3545 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3548 /* obtain stream defaults */
3549 qtdemux_parse_trex (qtdemux, *stream,
3550 default_sample_duration, default_sample_size, default_sample_flags);
3552 (*stream)->stsd_sample_description_id =
3553 (*stream)->def_sample_description_index - 1;
3555 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3556 guint32 sample_description_index;
3557 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3559 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3562 if (qtdemux->mss_mode) {
3563 /* mss has no stsd entry */
3564 (*stream)->stsd_sample_description_id = 0;
3567 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3568 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3571 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3572 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3575 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3576 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3583 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3588 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3594 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3595 guint64 * decode_time)
3597 guint32 version = 0;
3599 if (!gst_byte_reader_get_uint32_be (br, &version))
3604 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3607 guint32 dec_time = 0;
3608 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3610 *decode_time = dec_time;
3613 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3620 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3625 /* Returns a pointer to a GstStructure containing the properties of
3626 * the stream sample identified by @sample_index. The caller must unref
3627 * the returned object after use. Returns NULL if unsuccessful. */
3628 static GstStructure *
3629 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3630 QtDemuxStream * stream, guint sample_index)
3632 QtDemuxCencSampleSetInfo *info = NULL;
3634 g_return_val_if_fail (stream != NULL, NULL);
3635 g_return_val_if_fail (stream->protected, NULL);
3636 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3638 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3640 /* Currently, cenc properties for groups of samples are not supported, so
3641 * simply return a copy of the default sample properties */
3642 return gst_structure_copy (info->default_properties);
3645 /* Parses the sizes of sample auxiliary information contained within a stream,
3646 * as given in a saiz box. Returns array of sample_count guint8 size values,
3647 * or NULL on failure */
3649 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3650 GstByteReader * br, guint32 * sample_count)
3654 guint8 default_info_size;
3656 g_return_val_if_fail (qtdemux != NULL, NULL);
3657 g_return_val_if_fail (stream != NULL, NULL);
3658 g_return_val_if_fail (br != NULL, NULL);
3659 g_return_val_if_fail (sample_count != NULL, NULL);
3661 if (!gst_byte_reader_get_uint32_be (br, &flags))
3665 /* aux_info_type and aux_info_type_parameter are ignored */
3666 if (!gst_byte_reader_skip (br, 8))
3670 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3672 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3674 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3676 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3679 if (default_info_size == 0) {
3680 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3684 info_sizes = g_new (guint8, *sample_count);
3685 memset (info_sizes, default_info_size, *sample_count);
3691 /* Parses the offset of sample auxiliary information contained within a stream,
3692 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3694 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3695 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3700 guint32 aux_info_type = 0;
3701 guint32 aux_info_type_parameter = 0;
3702 guint32 entry_count;
3705 const guint8 *aux_info_type_data = NULL;
3707 g_return_val_if_fail (qtdemux != NULL, FALSE);
3708 g_return_val_if_fail (stream != NULL, FALSE);
3709 g_return_val_if_fail (br != NULL, FALSE);
3710 g_return_val_if_fail (offset != NULL, FALSE);
3712 if (!gst_byte_reader_get_uint8 (br, &version))
3715 if (!gst_byte_reader_get_uint24_be (br, &flags))
3720 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3722 aux_info_type = QT_FOURCC (aux_info_type_data);
3724 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3726 } else if (stream->protected) {
3727 aux_info_type = stream->protection_scheme_type;
3729 aux_info_type = CUR_STREAM (stream)->fourcc;
3733 *info_type = aux_info_type;
3734 if (info_type_parameter)
3735 *info_type_parameter = aux_info_type_parameter;
3737 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3738 "aux_info_type_parameter: %#06x",
3739 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3741 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3744 if (entry_count != 1) {
3745 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3750 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3752 *offset = (guint64) off_32;
3754 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3759 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3764 qtdemux_gst_structure_free (GstStructure * gststructure)
3767 gst_structure_free (gststructure);
3771 /* Parses auxiliary information relating to samples protected using Common
3772 * Encryption (cenc); the format of this information is defined in
3773 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3775 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3776 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3778 QtDemuxCencSampleSetInfo *ss_info = NULL;
3781 GPtrArray *old_crypto_info = NULL;
3782 guint old_entries = 0;
3784 g_return_val_if_fail (qtdemux != NULL, FALSE);
3785 g_return_val_if_fail (stream != NULL, FALSE);
3786 g_return_val_if_fail (br != NULL, FALSE);
3787 g_return_val_if_fail (stream->protected, FALSE);
3788 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3790 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3792 if (ss_info->crypto_info) {
3793 old_crypto_info = ss_info->crypto_info;
3794 /* Count number of non-null entries remaining at the tail end */
3795 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3796 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3802 ss_info->crypto_info =
3803 g_ptr_array_new_full (sample_count + old_entries,
3804 (GDestroyNotify) qtdemux_gst_structure_free);
3806 /* We preserve old entries because we parse the next moof in advance
3807 * of consuming all samples from the previous moof, and otherwise
3808 * we'd discard the corresponding crypto info for the samples
3809 * from the previous fragment. */
3811 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3813 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3814 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3816 g_ptr_array_index (old_crypto_info, i) = NULL;
3820 if (old_crypto_info) {
3821 /* Everything now belongs to the new array */
3822 g_ptr_array_free (old_crypto_info, TRUE);
3825 for (i = 0; i < sample_count; ++i) {
3826 GstStructure *properties;
3827 guint16 n_subsamples = 0;
3832 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3833 if (properties == NULL) {
3834 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3837 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3838 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3839 gst_structure_free (properties);
3842 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3843 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3844 gst_structure_free (properties);
3847 buf = gst_buffer_new_wrapped (data, iv_size);
3848 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3849 gst_buffer_unref (buf);
3850 size = info_sizes[i];
3851 if (size > iv_size) {
3852 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3853 || !(n_subsamples > 0)) {
3854 gst_structure_free (properties);
3855 GST_ERROR_OBJECT (qtdemux,
3856 "failed to get subsample count for sample %u", i);
3859 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3860 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3861 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3863 gst_structure_free (properties);
3866 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3868 gst_structure_free (properties);
3871 gst_structure_set (properties,
3872 "subsample_count", G_TYPE_UINT, n_subsamples,
3873 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3874 gst_buffer_unref (buf);
3876 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3878 g_ptr_array_add (ss_info->crypto_info, properties);
3883 /* Converts a UUID in raw byte form to a string representation, as defined in
3884 * RFC 4122. The caller takes ownership of the returned string and is
3885 * responsible for freeing it after use. */
3887 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3889 const guint8 *uuid = (const guint8 *) uuid_bytes;
3891 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3892 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3893 uuid[0], uuid[1], uuid[2], uuid[3],
3894 uuid[4], uuid[5], uuid[6], uuid[7],
3895 uuid[8], uuid[9], uuid[10], uuid[11],
3896 uuid[12], uuid[13], uuid[14], uuid[15]);
3899 /* Parses a Protection System Specific Header box (pssh), as defined in the
3900 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3901 * information needed by a specific content protection system in order to
3902 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3905 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3907 gchar *sysid_string;
3908 guint32 pssh_size = QT_UINT32 (node->data);
3909 GstBuffer *pssh = NULL;
3910 GstEvent *event = NULL;
3911 guint32 parent_box_type;
3914 if (G_UNLIKELY (pssh_size < 32U)) {
3915 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3920 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3922 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3924 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3925 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3926 gst_buffer_get_size (pssh));
3928 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3930 /* Push an event containing the pssh box onto the queues of all streams. */
3931 event = gst_event_new_protection (sysid_string, pssh,
3932 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3933 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3934 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3935 GST_TRACE_OBJECT (qtdemux,
3936 "adding protection event for stream %s and system %s",
3937 stream->stream_id, sysid_string);
3938 g_queue_push_tail (&stream->protection_scheme_event_queue,
3939 gst_event_ref (event));
3941 g_free (sysid_string);
3942 gst_event_unref (event);
3943 gst_buffer_unref (pssh);
3948 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3949 guint64 moof_offset, QtDemuxStream * stream)
3951 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3953 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3954 GNode *saiz_node, *saio_node, *pssh_node;
3955 GstByteReader saiz_data, saio_data;
3956 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3957 gint64 base_offset, running_offset;
3959 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
3961 /* NOTE @stream ignored */
3963 moof_node = g_node_new ((guint8 *) buffer);
3964 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3965 qtdemux_node_dump (qtdemux, moof_node);
3967 /* Get fragment number from mfhd and check it's valid */
3969 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3970 if (mfhd_node == NULL)
3972 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3974 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3976 /* unknown base_offset to start with */
3977 base_offset = running_offset = -1;
3978 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3980 guint64 decode_time = 0;
3982 /* Fragment Header node */
3984 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3988 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3989 &ds_size, &ds_flags, &base_offset))
3992 /* The following code assumes at most a single set of sample auxiliary
3993 * data in the fragment (consisting of a saiz box and a corresponding saio
3994 * box); in theory, however, there could be multiple sets of sample
3995 * auxiliary data in a fragment. */
3997 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4000 guint32 info_type = 0;
4002 guint32 info_type_parameter = 0;
4004 g_free (qtdemux->cenc_aux_info_sizes);
4006 qtdemux->cenc_aux_info_sizes =
4007 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4008 &qtdemux->cenc_aux_sample_count);
4009 if (qtdemux->cenc_aux_info_sizes == NULL) {
4010 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4014 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4017 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4018 g_free (qtdemux->cenc_aux_info_sizes);
4019 qtdemux->cenc_aux_info_sizes = NULL;
4023 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4024 &info_type, &info_type_parameter, &offset))) {
4025 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4026 g_free (qtdemux->cenc_aux_info_sizes);
4027 qtdemux->cenc_aux_info_sizes = NULL;
4030 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4031 offset += (guint64) (base_offset - qtdemux->moof_offset);
4032 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4034 if (offset > length) {
4035 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4036 qtdemux->cenc_aux_info_offset = offset;
4038 gst_byte_reader_init (&br, buffer + offset, length - offset);
4039 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4040 qtdemux->cenc_aux_info_sizes,
4041 qtdemux->cenc_aux_sample_count)) {
4042 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4043 g_free (qtdemux->cenc_aux_info_sizes);
4044 qtdemux->cenc_aux_info_sizes = NULL;
4052 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4055 /* We'll use decode_time to interpolate timestamps
4056 * in case the input timestamps are missing */
4057 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4059 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4060 " (%" GST_TIME_FORMAT ")", decode_time,
4061 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4062 decode_time) : GST_CLOCK_TIME_NONE));
4064 /* Discard the fragment buffer timestamp info to avoid using it.
4065 * Rely on tfdt instead as it is more accurate than the timestamp
4066 * that is fetched from a manifest/playlist and is usually
4068 qtdemux->fragment_start = -1;
4071 if (G_UNLIKELY (!stream)) {
4072 /* we lost track of offset, we'll need to regain it,
4073 * but can delay complaining until later or avoid doing so altogether */
4077 if (G_UNLIKELY (base_offset < -1))
4080 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4082 if (!qtdemux->pullbased) {
4083 /* Sample tables can grow enough to be problematic if the system memory
4084 * is very low (e.g. embedded devices) and the videos very long
4085 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4086 * Fortunately, we can easily discard them for each new fragment when
4087 * we know qtdemux will not receive seeks outside of the current fragment.
4088 * adaptivedemux honors this assumption.
4089 * This optimization is also useful for applications that use qtdemux as
4090 * a push-based simple demuxer, like Media Source Extensions. */
4091 gst_qtdemux_stream_flush_samples_data (stream);
4094 /* initialise moof sample data */
4095 stream->n_samples_moof = 0;
4096 stream->duration_last_moof = stream->duration_moof;
4097 stream->duration_moof = 0;
4099 /* Track Run node */
4101 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4104 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4105 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4106 &running_offset, decode_time, (tfdt_node != NULL));
4107 /* iterate all siblings */
4108 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4112 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4114 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4115 guint32 box_length = QT_UINT32 (uuid_buffer);
4117 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4120 /* if no new base_offset provided for next traf,
4121 * base is end of current traf */
4122 base_offset = running_offset;
4123 running_offset = -1;
4125 if (stream->n_samples_moof && stream->duration_moof)
4126 stream->new_caps = TRUE;
4129 /* iterate all siblings */
4130 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4133 /* parse any protection system info */
4134 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4136 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4137 qtdemux_parse_pssh (qtdemux, pssh_node);
4138 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4141 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4142 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4144 /* Unless the user has explictly requested another seek, perform an
4145 * internal seek to the time specified in the tfdt.
4147 * This way if the user opens a file where the first tfdt is 1 hour
4148 * into the presentation, they will not have to wait 1 hour for run
4149 * time to catch up and actual playback to start. */
4152 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4153 "performing an internal seek to %" GST_TIME_FORMAT,
4154 GST_TIME_ARGS (min_dts));
4156 qtdemux->segment.start = min_dts;
4157 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4159 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4160 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
4161 stream->time_position = min_dts;
4164 /* Before this code was run a segment was already sent when the moov was
4165 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4166 * be emitted after a moov, and we can emit a second segment anyway for
4167 * special cases like this. */
4168 qtdemux->need_segment = TRUE;
4171 qtdemux->first_moof_already_parsed = TRUE;
4173 g_node_destroy (moof_node);
4178 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4183 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4188 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4193 g_node_destroy (moof_node);
4194 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4195 (_("This file is corrupt and cannot be played.")), (NULL));
4201 /* might be used if some day we actually use mfra & co
4202 * for random access to fragments,
4203 * but that will require quite some modifications and much less relying
4204 * on a sample array */
4208 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4210 QtDemuxStream *stream;
4211 guint32 ver_flags, track_id, len, num_entries, i;
4212 guint value_size, traf_size, trun_size, sample_size;
4213 guint64 time = 0, moof_offset = 0;
4215 GstBuffer *buf = NULL;
4220 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4222 if (!gst_byte_reader_skip (&tfra, 8))
4225 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4228 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4229 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4230 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4233 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4235 stream = qtdemux_find_stream (qtdemux, track_id);
4237 goto unknown_trackid;
4239 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4240 sample_size = (len & 3) + 1;
4241 trun_size = ((len & 12) >> 2) + 1;
4242 traf_size = ((len & 48) >> 4) + 1;
4244 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4245 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4247 if (num_entries == 0)
4250 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4251 value_size + value_size + traf_size + trun_size + sample_size))
4254 g_free (stream->ra_entries);
4255 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4256 stream->n_ra_entries = num_entries;
4258 for (i = 0; i < num_entries; i++) {
4259 qt_atom_parser_get_offset (&tfra, value_size, &time);
4260 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4261 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4262 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4263 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4265 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4267 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4268 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4270 stream->ra_entries[i].ts = time;
4271 stream->ra_entries[i].moof_offset = moof_offset;
4273 /* don't want to go through the entire file and read all moofs at startup */
4275 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4276 if (ret != GST_FLOW_OK)
4278 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4279 moof_offset, stream);
4280 gst_buffer_unref (buf);
4284 check_update_duration (qtdemux, time);
4291 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4296 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4301 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4307 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4309 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4310 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4311 GstBuffer *mfro = NULL, *mfra = NULL;
4313 gboolean ret = FALSE;
4314 GNode *mfra_node, *tfra_node;
4315 guint64 mfra_offset = 0;
4316 guint32 fourcc, mfra_size;
4319 /* query upstream size in bytes */
4320 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4321 goto size_query_failed;
4323 /* mfro box should be at the very end of the file */
4324 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4325 if (flow != GST_FLOW_OK)
4328 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4330 fourcc = QT_FOURCC (mfro_map.data + 4);
4331 if (fourcc != FOURCC_mfro)
4334 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4335 if (mfro_map.size < 16)
4336 goto invalid_mfro_size;
4338 mfra_size = QT_UINT32 (mfro_map.data + 12);
4339 if (mfra_size >= len)
4340 goto invalid_mfra_size;
4342 mfra_offset = len - mfra_size;
4344 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4345 mfra_offset, mfra_size);
4347 /* now get and parse mfra box */
4348 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4349 if (flow != GST_FLOW_OK)
4352 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4354 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4355 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4357 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4360 qtdemux_parse_tfra (qtdemux, tfra_node);
4361 /* iterate all siblings */
4362 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4364 g_node_destroy (mfra_node);
4366 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4372 if (mfro_map.memory != NULL)
4373 gst_buffer_unmap (mfro, &mfro_map);
4374 gst_buffer_unref (mfro);
4377 if (mfra_map.memory != NULL)
4378 gst_buffer_unmap (mfra, &mfra_map);
4379 gst_buffer_unref (mfra);
4386 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4391 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4396 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4401 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4407 add_offset (guint64 offset, guint64 advance)
4409 /* Avoid 64-bit overflow by clamping */
4410 if (offset > G_MAXUINT64 - advance)
4412 return offset + advance;
4415 static GstFlowReturn
4416 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4420 GstBuffer *buf = NULL;
4421 GstFlowReturn ret = GST_FLOW_OK;
4422 guint64 cur_offset = qtdemux->offset;
4425 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4426 if (G_UNLIKELY (ret != GST_FLOW_OK))
4428 gst_buffer_map (buf, &map, GST_MAP_READ);
4429 if (G_LIKELY (map.size >= 8))
4430 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4431 gst_buffer_unmap (buf, &map);
4432 gst_buffer_unref (buf);
4434 /* maybe we already got most we needed, so only consider this eof */
4435 if (G_UNLIKELY (length == 0)) {
4436 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4437 (_("Invalid atom size.")),
4438 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4439 GST_FOURCC_ARGS (fourcc)));
4446 /* record for later parsing when needed */
4447 if (!qtdemux->moof_offset) {
4448 qtdemux->moof_offset = qtdemux->offset;
4450 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4453 qtdemux->offset += length; /* skip moof and keep going */
4455 if (qtdemux->got_moov) {
4456 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4468 GST_LOG_OBJECT (qtdemux,
4469 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4470 GST_FOURCC_ARGS (fourcc), cur_offset);
4471 qtdemux->offset = add_offset (qtdemux->offset, length);
4476 GstBuffer *moov = NULL;
4478 if (qtdemux->got_moov) {
4479 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4480 qtdemux->offset = add_offset (qtdemux->offset, length);
4484 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4485 if (ret != GST_FLOW_OK)
4487 gst_buffer_map (moov, &map, GST_MAP_READ);
4489 if (length != map.size) {
4490 /* Some files have a 'moov' atom at the end of the file which contains
4491 * a terminal 'free' atom where the body of the atom is missing.
4492 * Check for, and permit, this special case.
4494 if (map.size >= 8) {
4495 guint8 *final_data = map.data + (map.size - 8);
4496 guint32 final_length = QT_UINT32 (final_data);
4497 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4499 if (final_fourcc == FOURCC_free
4500 && map.size + final_length - 8 == length) {
4501 /* Ok, we've found that special case. Allocate a new buffer with
4502 * that free atom actually present. */
4503 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4504 gst_buffer_fill (newmoov, 0, map.data, map.size);
4505 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4506 gst_buffer_unmap (moov, &map);
4507 gst_buffer_unref (moov);
4509 gst_buffer_map (moov, &map, GST_MAP_READ);
4514 if (length != map.size) {
4515 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4516 (_("This file is incomplete and cannot be played.")),
4517 ("We got less than expected (received %" G_GSIZE_FORMAT
4518 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4519 (guint) length, cur_offset));
4520 gst_buffer_unmap (moov, &map);
4521 gst_buffer_unref (moov);
4522 ret = GST_FLOW_ERROR;
4525 qtdemux->offset += length;
4527 qtdemux_parse_moov (qtdemux, map.data, length);
4528 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4530 qtdemux_parse_tree (qtdemux);
4531 if (qtdemux->moov_node_compressed) {
4532 g_node_destroy (qtdemux->moov_node_compressed);
4533 g_free (qtdemux->moov_node->data);
4535 qtdemux->moov_node_compressed = NULL;
4536 g_node_destroy (qtdemux->moov_node);
4537 qtdemux->moov_node = NULL;
4538 gst_buffer_unmap (moov, &map);
4539 gst_buffer_unref (moov);
4540 qtdemux->got_moov = TRUE;
4546 GstBuffer *ftyp = NULL;
4548 /* extract major brand; might come in handy for ISO vs QT issues */
4549 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4550 if (ret != GST_FLOW_OK)
4552 qtdemux->offset += length;
4553 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4554 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4555 gst_buffer_unmap (ftyp, &map);
4556 gst_buffer_unref (ftyp);
4561 GstBuffer *uuid = NULL;
4563 /* uuid are extension atoms */
4564 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4565 if (ret != GST_FLOW_OK)
4567 qtdemux->offset += length;
4568 gst_buffer_map (uuid, &map, GST_MAP_READ);
4569 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4570 gst_buffer_unmap (uuid, &map);
4571 gst_buffer_unref (uuid);
4576 GstBuffer *sidx = NULL;
4577 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4578 if (ret != GST_FLOW_OK)
4580 qtdemux->offset += length;
4581 gst_buffer_map (sidx, &map, GST_MAP_READ);
4582 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4583 gst_buffer_unmap (sidx, &map);
4584 gst_buffer_unref (sidx);
4589 GstBuffer *unknown = NULL;
4591 GST_LOG_OBJECT (qtdemux,
4592 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4593 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4595 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4596 if (ret != GST_FLOW_OK)
4598 gst_buffer_map (unknown, &map, GST_MAP_READ);
4599 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4600 gst_buffer_unmap (unknown, &map);
4601 gst_buffer_unref (unknown);
4602 qtdemux->offset += length;
4608 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4609 /* digested all data, show what we have */
4610 qtdemux_prepare_streams (qtdemux);
4611 QTDEMUX_EXPOSE_LOCK (qtdemux);
4612 ret = qtdemux_expose_streams (qtdemux);
4613 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4615 qtdemux->state = QTDEMUX_STATE_MOVIE;
4616 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4623 /* Seeks to the previous keyframe of the indexed stream and
4624 * aligns other streams with respect to the keyframe timestamp
4625 * of indexed stream. Only called in case of Reverse Playback
4627 static GstFlowReturn
4628 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4630 guint32 seg_idx = 0, k_index = 0;
4631 guint32 ref_seg_idx, ref_k_index;
4632 GstClockTime k_pos = 0, last_stop = 0;
4633 QtDemuxSegment *seg = NULL;
4634 QtDemuxStream *ref_str = NULL;
4635 guint64 seg_media_start_mov; /* segment media start time in mov format */
4639 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4640 * and finally align all the other streams on that timestamp with their
4641 * respective keyframes */
4642 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4643 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4645 /* No candidate yet, take the first stream */
4651 /* So that stream has a segment, we prefer video streams */
4652 if (str->subtype == FOURCC_vide) {
4658 if (G_UNLIKELY (!ref_str)) {
4659 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4663 if (G_UNLIKELY (!ref_str->from_sample)) {
4664 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4668 /* So that stream has been playing from from_sample to to_sample. We will
4669 * get the timestamp of the previous sample and search for a keyframe before
4670 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4671 if (ref_str->subtype == FOURCC_vide) {
4672 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4673 ref_str->from_sample - 1, FALSE);
4675 if (ref_str->from_sample >= 10)
4676 k_index = ref_str->from_sample - 10;
4682 ref_str->samples[k_index].timestamp +
4683 ref_str->samples[k_index].pts_offset;
4685 /* get current segment for that stream */
4686 seg = &ref_str->segments[ref_str->segment_index];
4687 /* Use segment start in original timescale for comparisons */
4688 seg_media_start_mov = seg->trak_media_start;
4690 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4691 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4692 k_index, target_ts, seg_media_start_mov,
4693 GST_TIME_ARGS (seg->media_start));
4695 /* Crawl back through segments to find the one containing this I frame */
4696 while (target_ts < seg_media_start_mov) {
4697 GST_DEBUG_OBJECT (qtdemux,
4698 "keyframe position (sample %u) is out of segment %u " " target %"
4699 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4700 ref_str->segment_index, target_ts, seg_media_start_mov);
4702 if (G_UNLIKELY (!ref_str->segment_index)) {
4703 /* Reached first segment, let's consider it's EOS */
4706 ref_str->segment_index--;
4707 seg = &ref_str->segments[ref_str->segment_index];
4708 /* Use segment start in original timescale for comparisons */
4709 seg_media_start_mov = seg->trak_media_start;
4711 /* Calculate time position of the keyframe and where we should stop */
4713 QTSTREAMTIME_TO_GSTTIME (ref_str,
4714 target_ts - seg->trak_media_start) + seg->time;
4716 QTSTREAMTIME_TO_GSTTIME (ref_str,
4717 ref_str->samples[ref_str->from_sample].timestamp -
4718 seg->trak_media_start) + seg->time;
4720 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4721 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4722 k_index, GST_TIME_ARGS (k_pos));
4724 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4725 qtdemux->segment.position = last_stop;
4726 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4727 GST_TIME_ARGS (last_stop));
4729 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4730 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4734 ref_seg_idx = ref_str->segment_index;
4735 ref_k_index = k_index;
4737 /* Align them all on this */
4738 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4740 GstClockTime seg_time = 0;
4741 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4743 /* aligning reference stream again might lead to backing up to yet another
4744 * keyframe (due to timestamp rounding issues),
4745 * potentially putting more load on downstream; so let's try to avoid */
4746 if (str == ref_str) {
4747 seg_idx = ref_seg_idx;
4748 seg = &str->segments[seg_idx];
4749 k_index = ref_k_index;
4750 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4751 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4753 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4754 GST_DEBUG_OBJECT (qtdemux,
4755 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4756 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4758 /* get segment and time in the segment */
4759 seg = &str->segments[seg_idx];
4760 seg_time = k_pos - seg->time;
4762 /* get the media time in the segment.
4763 * No adjustment for empty "filler" segments */
4764 if (seg->media_start != GST_CLOCK_TIME_NONE)
4765 seg_time += seg->media_start;
4767 /* get the index of the sample with media time */
4768 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4769 GST_DEBUG_OBJECT (qtdemux,
4770 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4771 GST_TIME_ARGS (seg_time), index);
4773 /* find previous keyframe */
4774 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4777 /* Remember until where we want to go */
4778 str->to_sample = str->from_sample - 1;
4779 /* Define our time position */
4781 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4782 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4783 if (seg->media_start != GST_CLOCK_TIME_NONE)
4784 str->time_position -= seg->media_start;
4786 /* Now seek back in time */
4787 gst_qtdemux_move_stream (qtdemux, str, k_index);
4788 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4789 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4790 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4796 return GST_FLOW_EOS;
4800 * Gets the current qt segment start, stop and position for the
4801 * given time offset. This is used in update_segment()
4804 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4805 QtDemuxStream * stream, GstClockTime offset,
4806 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4808 GstClockTime seg_time;
4809 GstClockTime start, stop, time;
4810 QtDemuxSegment *segment;
4812 segment = &stream->segments[stream->segment_index];
4814 /* get time in this segment */
4815 seg_time = (offset - segment->time) * segment->rate;
4817 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4818 GST_TIME_ARGS (seg_time));
4820 if (G_UNLIKELY (seg_time > segment->duration)) {
4821 GST_LOG_OBJECT (stream->pad,
4822 "seg_time > segment->duration %" GST_TIME_FORMAT,
4823 GST_TIME_ARGS (segment->duration));
4824 seg_time = segment->duration;
4827 /* qtdemux->segment.stop is in outside-time-realm, whereas
4828 * segment->media_stop is in track-time-realm.
4830 * In order to compare the two, we need to bring segment.stop
4831 * into the track-time-realm
4833 * FIXME - does this comment still hold? Don't see any conversion here */
4835 stop = qtdemux->segment.stop;
4836 if (stop == GST_CLOCK_TIME_NONE)
4837 stop = qtdemux->segment.duration;
4838 if (stop == GST_CLOCK_TIME_NONE)
4839 stop = segment->media_stop;
4842 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4844 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4845 start = segment->time + seg_time;
4847 stop = start - seg_time + segment->duration;
4848 } else if (qtdemux->segment.rate >= 0) {
4849 start = MIN (segment->media_start + seg_time, stop);
4852 if (segment->media_start >= qtdemux->segment.start) {
4853 time = segment->time;
4855 time = segment->time + (qtdemux->segment.start - segment->media_start);
4858 start = MAX (segment->media_start, qtdemux->segment.start);
4859 stop = MIN (segment->media_start + seg_time, stop);
4868 * Updates the qt segment used for the stream and pushes a new segment event
4869 * downstream on this stream's pad.
4872 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4873 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4874 GstClockTime * _stop)
4876 QtDemuxSegment *segment;
4877 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4881 /* update the current segment */
4882 stream->segment_index = seg_idx;
4884 /* get the segment */
4885 segment = &stream->segments[seg_idx];
4887 if (G_UNLIKELY (offset < segment->time)) {
4888 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4889 GST_TIME_ARGS (segment->time));
4893 /* segment lies beyond total indicated duration */
4894 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4895 segment->time > qtdemux->segment.duration)) {
4896 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4897 " < segment->time %" GST_TIME_FORMAT,
4898 GST_TIME_ARGS (qtdemux->segment.duration),
4899 GST_TIME_ARGS (segment->time));
4903 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4904 &start, &stop, &time);
4906 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4907 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4908 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4910 /* combine global rate with that of the segment */
4911 rate = segment->rate * qtdemux->segment.rate;
4913 /* Copy flags from main segment */
4914 stream->segment.flags = qtdemux->segment.flags;
4916 /* update the segment values used for clipping */
4917 stream->segment.offset = qtdemux->segment.offset;
4918 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4919 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4920 stream->segment.rate = rate;
4921 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4922 stream->cslg_shift);
4923 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4924 stream->cslg_shift);
4925 stream->segment.time = time;
4926 stream->segment.position = stream->segment.start;
4928 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4931 /* now prepare and send the segment */
4933 event = gst_event_new_segment (&stream->segment);
4934 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4935 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4937 gst_pad_push_event (stream->pad, event);
4938 /* assume we can send more data now */
4939 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4940 /* clear to send tags on this pad now */
4941 gst_qtdemux_push_tags (qtdemux, stream);
4952 /* activate the given segment number @seg_idx of @stream at time @offset.
4953 * @offset is an absolute global position over all the segments.
4955 * This will push out a NEWSEGMENT event with the right values and
4956 * position the stream index to the first decodable sample before
4960 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4961 guint32 seg_idx, GstClockTime offset)
4963 QtDemuxSegment *segment;
4964 guint32 index, kf_index;
4965 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4967 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4968 seg_idx, GST_TIME_ARGS (offset));
4970 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4974 segment = &stream->segments[stream->segment_index];
4976 /* in the fragmented case, we pick a fragment that starts before our
4977 * desired position and rely on downstream to wait for a keyframe
4978 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4979 * tfra entries tells us which trun/sample the key unit is in, but we don't
4980 * make use of this additional information at the moment) */
4981 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4982 stream->to_sample = G_MAXUINT32;
4985 /* well, it will be taken care of below */
4986 qtdemux->fragmented_seek_pending = FALSE;
4987 /* FIXME ideally the do_fragmented_seek can be done right here,
4988 * rather than at loop level
4989 * (which might even allow handling edit lists in a fragmented file) */
4992 /* We don't need to look for a sample in push-based */
4993 if (!qtdemux->pullbased)
4996 /* and move to the keyframe before the indicated media time of the
4998 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4999 if (qtdemux->segment.rate >= 0) {
5000 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5001 stream->to_sample = G_MAXUINT32;
5002 GST_DEBUG_OBJECT (stream->pad,
5003 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5004 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5005 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5007 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5008 stream->to_sample = index;
5009 GST_DEBUG_OBJECT (stream->pad,
5010 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5011 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5012 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5015 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5016 "this is an empty segment");
5020 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5021 * encountered an error and printed a message so we return appropriately */
5025 /* we're at the right spot */
5026 if (index == stream->sample_index) {
5027 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5031 /* find keyframe of the target index */
5032 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5035 /* indent does stupid stuff with stream->samples[].timestamp */
5037 /* if we move forwards, we don't have to go back to the previous
5038 * keyframe since we already sent that. We can also just jump to
5039 * the keyframe right before the target index if there is one. */
5040 if (index > stream->sample_index) {
5041 /* moving forwards check if we move past a keyframe */
5042 if (kf_index > stream->sample_index) {
5043 GST_DEBUG_OBJECT (stream->pad,
5044 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5045 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5046 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5047 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5049 GST_DEBUG_OBJECT (stream->pad,
5050 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5051 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5052 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5055 GST_DEBUG_OBJECT (stream->pad,
5056 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5057 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5058 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5059 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5067 /* prepare to get the current sample of @stream, getting essential values.
5069 * This function will also prepare and send the segment when needed.
5071 * Return FALSE if the stream is EOS.
5076 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5077 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5078 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5079 gboolean * keyframe)
5081 QtDemuxSample *sample;
5082 GstClockTime time_position;
5085 g_return_val_if_fail (stream != NULL, FALSE);
5087 time_position = stream->time_position;
5088 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5091 seg_idx = stream->segment_index;
5092 if (G_UNLIKELY (seg_idx == -1)) {
5093 /* find segment corresponding to time_position if we are looking
5095 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5098 /* different segment, activate it, sample_index will be set. */
5099 if (G_UNLIKELY (stream->segment_index != seg_idx))
5100 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5102 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5104 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5106 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5107 " prepare empty sample");
5110 *pts = *dts = time_position;
5111 *duration = seg->duration - (time_position - seg->time);
5118 if (stream->sample_index == -1)
5119 stream->sample_index = 0;
5121 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5122 stream->sample_index, stream->n_samples);
5124 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5125 if (!qtdemux->fragmented)
5128 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5132 GST_OBJECT_LOCK (qtdemux);
5133 flow = qtdemux_add_fragmented_samples (qtdemux);
5134 GST_OBJECT_UNLOCK (qtdemux);
5136 if (flow != GST_FLOW_OK)
5139 while (stream->sample_index >= stream->n_samples);
5142 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5143 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5144 stream->sample_index);
5148 /* now get the info for the sample we're at */
5149 sample = &stream->samples[stream->sample_index];
5151 *dts = QTSAMPLE_DTS (stream, sample);
5152 *pts = QTSAMPLE_PTS (stream, sample);
5153 *offset = sample->offset;
5154 *size = sample->size;
5155 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5156 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5163 stream->time_position = GST_CLOCK_TIME_NONE;
5168 /* move to the next sample in @stream.
5170 * Moves to the next segment when needed.
5173 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5175 QtDemuxSample *sample;
5176 QtDemuxSegment *segment;
5178 /* get current segment */
5179 segment = &stream->segments[stream->segment_index];
5181 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5182 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5186 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5187 /* Mark the stream as EOS */
5188 GST_DEBUG_OBJECT (qtdemux,
5189 "reached max allowed sample %u, mark EOS", stream->to_sample);
5190 stream->time_position = GST_CLOCK_TIME_NONE;
5194 /* move to next sample */
5195 stream->sample_index++;
5196 stream->offset_in_sample = 0;
5198 /* reached the last sample, we need the next segment */
5199 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5202 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5203 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5204 stream->sample_index);
5208 /* get next sample */
5209 sample = &stream->samples[stream->sample_index];
5211 /* see if we are past the segment */
5212 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5215 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5216 /* inside the segment, update time_position, looks very familiar to
5217 * GStreamer segments, doesn't it? */
5218 stream->time_position =
5219 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5221 /* not yet in segment, time does not yet increment. This means
5222 * that we are still prerolling keyframes to the decoder so it can
5223 * decode the first sample of the segment. */
5224 stream->time_position = segment->time;
5228 /* move to the next segment */
5231 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5233 if (stream->segment_index == stream->n_segments - 1) {
5234 /* are we at the end of the last segment, we're EOS */
5235 stream->time_position = GST_CLOCK_TIME_NONE;
5237 /* else we're only at the end of the current segment */
5238 stream->time_position = segment->stop_time;
5240 /* make sure we select a new segment */
5242 /* accumulate previous segments */
5243 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5244 stream->accumulated_base +=
5245 (stream->segment.stop -
5246 stream->segment.start) / ABS (stream->segment.rate);
5248 stream->segment_index = -1;
5253 gst_qtdemux_sync_streams (GstQTDemux * demux)
5257 if (demux->n_streams <= 1)
5260 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
5261 QtDemuxStream *stream;
5262 GstClockTime end_time;
5264 stream = QTDEMUX_STREAM (iter->data);
5269 /* TODO advance time on subtitle streams here, if any some day */
5271 /* some clips/trailers may have unbalanced streams at the end,
5272 * so send EOS on shorter stream to prevent stalling others */
5274 /* do not mess with EOS if SEGMENT seeking */
5275 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5278 if (demux->pullbased) {
5279 /* loop mode is sample time based */
5280 if (!STREAM_IS_EOS (stream))
5283 /* push mode is byte position based */
5284 if (stream->n_samples &&
5285 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5289 if (stream->sent_eos)
5292 /* only act if some gap */
5293 end_time = stream->segments[stream->n_segments - 1].stop_time;
5294 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5295 ", stream end: %" GST_TIME_FORMAT,
5296 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5297 if (GST_CLOCK_TIME_IS_VALID (end_time)
5298 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5301 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5302 GST_PAD_NAME (stream->pad));
5303 stream->sent_eos = TRUE;
5304 event = gst_event_new_eos ();
5305 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5306 gst_event_set_seqnum (event, demux->segment_seqnum);
5307 gst_pad_push_event (stream->pad, event);
5312 /* EOS and NOT_LINKED need to be combined. This means that we return:
5314 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5315 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5317 static GstFlowReturn
5318 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5321 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5324 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5327 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5329 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5333 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5334 * completely clipped
5336 * Should be used only with raw buffers */
5338 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5341 guint64 start, stop, cstart, cstop, diff;
5342 GstClockTime pts, duration;
5344 gint num_rate, denom_rate;
5349 osize = size = gst_buffer_get_size (buf);
5352 /* depending on the type, setup the clip parameters */
5353 if (stream->subtype == FOURCC_soun) {
5354 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5355 num_rate = GST_SECOND;
5356 denom_rate = (gint) CUR_STREAM (stream)->rate;
5358 } else if (stream->subtype == FOURCC_vide) {
5360 num_rate = CUR_STREAM (stream)->fps_n;
5361 denom_rate = CUR_STREAM (stream)->fps_d;
5366 if (frame_size <= 0)
5367 goto bad_frame_size;
5369 /* we can only clip if we have a valid pts */
5370 pts = GST_BUFFER_PTS (buf);
5371 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5374 duration = GST_BUFFER_DURATION (buf);
5376 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5378 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5382 stop = start + duration;
5384 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5385 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5388 /* see if some clipping happened */
5389 diff = cstart - start;
5395 /* bring clipped time to samples and to bytes */
5396 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5399 GST_DEBUG_OBJECT (qtdemux,
5400 "clipping start to %" GST_TIME_FORMAT " %"
5401 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5407 diff = stop - cstop;
5412 /* bring clipped time to samples and then to bytes */
5413 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5415 GST_DEBUG_OBJECT (qtdemux,
5416 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5417 " bytes", GST_TIME_ARGS (cstop), diff);
5422 if (offset != 0 || size != osize)
5423 gst_buffer_resize (buf, offset, size);
5425 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5426 GST_BUFFER_PTS (buf) = pts;
5427 GST_BUFFER_DURATION (buf) = duration;
5431 /* dropped buffer */
5434 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5439 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5444 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5449 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5450 gst_buffer_unref (buf);
5456 gst_qtdemux_align_buffer (GstQTDemux * demux,
5457 GstBuffer * buffer, gsize alignment)
5461 gst_buffer_map (buffer, &map, GST_MAP_READ);
5463 if (map.size < sizeof (guintptr)) {
5464 gst_buffer_unmap (buffer, &map);
5468 if (((guintptr) map.data) & (alignment - 1)) {
5469 GstBuffer *new_buffer;
5470 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5472 new_buffer = gst_buffer_new_allocate (NULL,
5473 gst_buffer_get_size (buffer), ¶ms);
5475 /* Copy data "by hand", so ensure alignment is kept: */
5476 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5478 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5479 GST_DEBUG_OBJECT (demux,
5480 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5483 gst_buffer_unmap (buffer, &map);
5484 gst_buffer_unref (buffer);
5489 gst_buffer_unmap (buffer, &map);
5494 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5500 /* We are converting from pairs to triplets */
5501 *res = ccpair_size / 2 * 3;
5502 storage = g_malloc (*res);
5503 for (i = 0; i * 2 < ccpair_size; i += 1) {
5505 storage[i * 3] = 0xfc;
5507 storage[i * 3] = 0xfd;
5508 storage[i * 3 + 1] = ccpair[i * 2];
5509 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5516 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5520 guint32 atom_length, fourcc;
5521 QtDemuxStreamStsdEntry *stsd_entry;
5523 GST_MEMDUMP ("caption atom", data, size);
5525 /* There might be multiple atoms */
5530 atom_length = QT_UINT32 (data);
5531 fourcc = QT_FOURCC (data + 4);
5532 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5535 GST_DEBUG_OBJECT (stream->pad, "here");
5537 /* Check if we have somethig compatible */
5538 stsd_entry = CUR_STREAM (stream);
5539 switch (stsd_entry->fourcc) {
5541 guint8 *cdat = NULL, *cdt2 = NULL;
5542 gsize cdat_size = 0, cdt2_size = 0;
5543 /* Should be cdat or cdt2 */
5544 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5545 GST_WARNING_OBJECT (stream->pad,
5546 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5547 GST_FOURCC_ARGS (fourcc));
5551 /* Convert to cc_data triplet */
5552 if (fourcc == FOURCC_cdat)
5553 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5555 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5556 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5559 /* Check for another atom ? */
5560 if (size > atom_length + 8) {
5561 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5562 if (size >= atom_length + new_atom_length) {
5563 fourcc = QT_FOURCC (data + atom_length + 4);
5564 if (fourcc == FOURCC_cdat) {
5567 convert_to_ccdata (data + atom_length + 8,
5568 new_atom_length - 8, 1, &cdat_size);
5570 GST_WARNING_OBJECT (stream->pad,
5571 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5575 convert_to_ccdata (data + atom_length + 8,
5576 new_atom_length - 8, 2, &cdt2_size);
5578 GST_WARNING_OBJECT (stream->pad,
5579 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5584 *cclen = cdat_size + cdt2_size;
5585 res = g_malloc (*cclen);
5587 memcpy (res, cdat, cdat_size);
5589 memcpy (res + cdat_size, cdt2, cdt2_size);
5595 if (fourcc != FOURCC_ccdp) {
5596 GST_WARNING_OBJECT (stream->pad,
5597 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5598 GST_FOURCC_ARGS (fourcc));
5601 *cclen = atom_length - 8;
5602 res = g_memdup (data + 8, *cclen);
5605 /* Keep this here in case other closed caption formats are added */
5606 g_assert_not_reached ();
5610 GST_MEMDUMP ("Output", res, *cclen);
5615 GST_WARNING ("[cdat] atom is too small or invalid");
5619 /* the input buffer metadata must be writable,
5620 * but time/duration etc not yet set and need not be preserved */
5622 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5629 /* not many cases for now */
5630 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5631 /* send a one time dvd clut event */
5632 if (stream->pending_event && stream->pad)
5633 gst_pad_push_event (stream->pad, stream->pending_event);
5634 stream->pending_event = NULL;
5637 if (G_UNLIKELY (stream->subtype != FOURCC_text
5638 && stream->subtype != FOURCC_sbtl &&
5639 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5643 gst_buffer_map (buf, &map, GST_MAP_READ);
5645 /* empty buffer is sent to terminate previous subtitle */
5646 if (map.size <= 2) {
5647 gst_buffer_unmap (buf, &map);
5648 gst_buffer_unref (buf);
5651 if (stream->subtype == FOURCC_subp) {
5652 /* That's all the processing needed for subpictures */
5653 gst_buffer_unmap (buf, &map);
5657 if (stream->subtype == FOURCC_clcp) {
5660 /* For closed caption, we need to extract the information from the
5661 * [cdat],[cdt2] or [ccdp] atom */
5662 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5663 gst_buffer_unmap (buf, &map);
5664 gst_buffer_unref (buf);
5666 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5668 /* Conversion failed or there's nothing */
5674 nsize = GST_READ_UINT16_BE (map.data);
5675 nsize = MIN (nsize, map.size - 2);
5677 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5680 /* takes care of UTF-8 validation or UTF-16 recognition,
5681 * no other encoding expected */
5682 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5683 gst_buffer_unmap (buf, &map);
5685 gst_buffer_unref (buf);
5686 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5688 /* this should not really happen unless the subtitle is corrupted */
5689 gst_buffer_unref (buf);
5693 /* FIXME ? convert optional subsequent style info to markup */
5698 /* Sets a buffer's attributes properly and pushes it downstream.
5699 * Also checks for additional actions and custom processing that may
5700 * need to be done first.
5702 static GstFlowReturn
5703 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5704 QtDemuxStream * stream, GstBuffer * buf,
5705 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5706 gboolean keyframe, GstClockTime position, guint64 byte_position)
5708 GstFlowReturn ret = GST_FLOW_OK;
5710 /* offset the timestamps according to the edit list */
5712 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5716 gst_buffer_map (buf, &map, GST_MAP_READ);
5717 url = g_strndup ((gchar *) map.data, map.size);
5718 gst_buffer_unmap (buf, &map);
5719 if (url != NULL && strlen (url) != 0) {
5720 /* we have RTSP redirect now */
5721 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5722 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5723 gst_structure_new ("redirect",
5724 "new-location", G_TYPE_STRING, url, NULL)));
5725 qtdemux->posted_redirect = TRUE;
5727 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5733 /* position reporting */
5734 if (qtdemux->segment.rate >= 0) {
5735 qtdemux->segment.position = position;
5736 gst_qtdemux_sync_streams (qtdemux);
5739 if (G_UNLIKELY (!stream->pad)) {
5740 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5741 gst_buffer_unref (buf);
5745 /* send out pending buffers */
5746 while (stream->buffers) {
5747 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5749 if (G_UNLIKELY (stream->discont)) {
5750 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5751 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5752 stream->discont = FALSE;
5754 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5757 if (stream->alignment > 1)
5758 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5759 gst_pad_push (stream->pad, buffer);
5761 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5764 /* we're going to modify the metadata */
5765 buf = gst_buffer_make_writable (buf);
5767 if (G_UNLIKELY (stream->need_process))
5768 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5774 GST_BUFFER_DTS (buf) = dts;
5775 GST_BUFFER_PTS (buf) = pts;
5776 GST_BUFFER_DURATION (buf) = duration;
5777 GST_BUFFER_OFFSET (buf) = -1;
5778 GST_BUFFER_OFFSET_END (buf) = -1;
5780 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5781 gst_buffer_append_memory (buf,
5782 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5784 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5785 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5788 if (G_UNLIKELY (qtdemux->element_index)) {
5789 GstClockTime stream_time;
5792 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5794 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5795 GST_LOG_OBJECT (qtdemux,
5796 "adding association %" GST_TIME_FORMAT "-> %"
5797 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5798 gst_index_add_association (qtdemux->element_index,
5800 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5801 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5802 GST_FORMAT_BYTES, byte_position, NULL);
5807 if (stream->need_clip)
5808 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5810 if (G_UNLIKELY (buf == NULL))
5813 if (G_UNLIKELY (stream->discont)) {
5814 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5815 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5816 stream->discont = FALSE;
5818 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5822 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5823 stream->on_keyframe = FALSE;
5825 stream->on_keyframe = TRUE;
5829 GST_LOG_OBJECT (qtdemux,
5830 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5831 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5832 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5833 GST_PAD_NAME (stream->pad));
5835 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5836 GstStructure *crypto_info;
5837 QtDemuxCencSampleSetInfo *info =
5838 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5842 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5843 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5844 GST_PTR_FORMAT, event);
5845 gst_pad_push_event (stream->pad, event);
5848 if (info->crypto_info == NULL) {
5849 GST_DEBUG_OBJECT (qtdemux,
5850 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5852 /* The end of the crypto_info array matches our n_samples position,
5853 * so count backward from there */
5854 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5855 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5856 /* steal structure from array */
5857 crypto_info = g_ptr_array_index (info->crypto_info, index);
5858 g_ptr_array_index (info->crypto_info, index) = NULL;
5859 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5860 info->crypto_info->len);
5861 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5862 GST_ERROR_OBJECT (qtdemux,
5863 "failed to attach cenc metadata to buffer");
5865 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5866 index, stream->sample_index);
5871 if (stream->alignment > 1)
5872 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5874 ret = gst_pad_push (stream->pad, buf);
5876 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5877 /* mark position in stream, we'll need this to know when to send GAP event */
5878 stream->segment.position = pts + duration;
5885 static const QtDemuxRandomAccessEntry *
5886 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5887 GstClockTime pos, gboolean after)
5889 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5890 guint n_entries = stream->n_ra_entries;
5893 /* we assume the table is sorted */
5894 for (i = 0; i < n_entries; ++i) {
5895 if (entries[i].ts > pos)
5899 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5900 * probably okay to assume that the index lists the very first fragment */
5907 return &entries[i - 1];
5911 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5913 const QtDemuxRandomAccessEntry *best_entry = NULL;
5916 GST_OBJECT_LOCK (qtdemux);
5918 g_assert (qtdemux->n_streams > 0);
5920 /* first see if we can determine where to go to using mfra,
5921 * before we start clearing things */
5922 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5923 const QtDemuxRandomAccessEntry *entry;
5924 QtDemuxStream *stream;
5925 gboolean is_audio_or_video;
5927 stream = QTDEMUX_STREAM (iter->data);
5929 if (stream->ra_entries == NULL)
5932 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5933 is_audio_or_video = TRUE;
5935 is_audio_or_video = FALSE;
5938 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5939 stream->time_position, !is_audio_or_video);
5941 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5942 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5944 stream->pending_seek = entry;
5946 /* decide position to jump to just based on audio/video tracks, not subs */
5947 if (!is_audio_or_video)
5950 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5954 /* no luck, will handle seek otherwise */
5955 if (best_entry == NULL) {
5956 GST_OBJECT_UNLOCK (qtdemux);
5960 /* ok, now we can prepare for processing as of located moof */
5961 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5962 QtDemuxStream *stream;
5964 stream = QTDEMUX_STREAM (iter->data);
5966 g_free (stream->samples);
5967 stream->samples = NULL;
5968 stream->n_samples = 0;
5969 stream->stbl_index = -1; /* no samples have yet been parsed */
5970 stream->sample_index = -1;
5972 if (stream->protection_scheme_info) {
5973 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5974 if (stream->protection_scheme_type == FOURCC_cenc) {
5975 QtDemuxCencSampleSetInfo *info =
5976 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5977 if (info->crypto_info) {
5978 g_ptr_array_free (info->crypto_info, TRUE);
5979 info->crypto_info = NULL;
5985 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5986 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5987 GST_TIME_ARGS (QTDEMUX_FIRST_STREAM (qtdemux)->time_position),
5988 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5990 qtdemux->moof_offset = best_entry->moof_offset;
5992 qtdemux_add_fragmented_samples (qtdemux);
5994 GST_OBJECT_UNLOCK (qtdemux);
5998 static GstFlowReturn
5999 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6001 GstFlowReturn ret = GST_FLOW_OK;
6002 GstBuffer *buf = NULL;
6003 QtDemuxStream *stream, *target_stream = NULL;
6004 GstClockTime min_time;
6006 GstClockTime dts = GST_CLOCK_TIME_NONE;
6007 GstClockTime pts = GST_CLOCK_TIME_NONE;
6008 GstClockTime duration = 0;
6009 gboolean keyframe = FALSE;
6010 guint sample_size = 0;
6015 if (qtdemux->fragmented_seek_pending) {
6016 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6017 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6018 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6019 qtdemux->fragmented_seek_pending = FALSE;
6021 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6025 /* Figure out the next stream sample to output, min_time is expressed in
6026 * global time and runs over the edit list segments. */
6027 min_time = G_MAXUINT64;
6028 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6029 GstClockTime position;
6031 stream = QTDEMUX_STREAM (iter->data);
6032 position = stream->time_position;
6034 /* position of -1 is EOS */
6035 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6036 min_time = position;
6037 target_stream = stream;
6041 if (G_UNLIKELY (target_stream == NULL)) {
6042 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6046 /* check for segment end */
6047 if (G_UNLIKELY (qtdemux->segment.stop != -1
6048 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6049 || (qtdemux->segment.rate < 0
6050 && qtdemux->segment.start > min_time))
6051 && target_stream->on_keyframe)) {
6052 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6053 target_stream->time_position = GST_CLOCK_TIME_NONE;
6057 /* gap events for subtitle streams */
6058 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6059 stream = QTDEMUX_STREAM (iter->data);
6060 if (stream->pad && (stream->subtype == FOURCC_subp
6061 || stream->subtype == FOURCC_text
6062 || stream->subtype == FOURCC_sbtl)) {
6063 /* send one second gap events until the stream catches up */
6064 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6065 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6066 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6067 stream->segment.position + GST_SECOND < min_time) {
6069 gst_event_new_gap (stream->segment.position, GST_SECOND);
6070 gst_pad_push_event (stream->pad, gap);
6071 stream->segment.position += GST_SECOND;
6076 stream = target_stream;
6077 /* fetch info for the current sample of this stream */
6078 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6079 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6082 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6083 if (stream->new_caps) {
6084 gst_qtdemux_configure_stream (qtdemux, stream);
6085 qtdemux_do_allocation (qtdemux, stream);
6088 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6089 if (G_UNLIKELY (qtdemux->
6090 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6091 if (stream->subtype == FOURCC_vide && !keyframe) {
6092 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6098 GST_DEBUG_OBJECT (qtdemux,
6099 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6100 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6101 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6102 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6103 GST_TIME_ARGS (duration));
6105 if (G_UNLIKELY (empty)) {
6106 /* empty segment, push a gap if there's a second or more
6107 * difference and move to the next one */
6108 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6109 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6110 stream->segment.position = pts + duration;
6114 /* hmm, empty sample, skip and move to next sample */
6115 if (G_UNLIKELY (sample_size <= 0))
6118 /* last pushed sample was out of boundary, goto next sample */
6119 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6122 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6125 GST_DEBUG_OBJECT (qtdemux,
6126 "size %d larger than stream max_buffer_size %d, trimming",
6127 sample_size, stream->max_buffer_size);
6129 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6132 if (qtdemux->cenc_aux_info_offset > 0) {
6135 GstBuffer *aux_info = NULL;
6137 /* pull the data stored before the sample */
6139 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6140 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6141 if (G_UNLIKELY (ret != GST_FLOW_OK))
6143 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6144 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6145 gst_byte_reader_init (&br, map.data + 8, map.size);
6146 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6147 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6148 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6149 gst_buffer_unmap (aux_info, &map);
6150 gst_buffer_unref (aux_info);
6151 ret = GST_FLOW_ERROR;
6154 gst_buffer_unmap (aux_info, &map);
6155 gst_buffer_unref (aux_info);
6158 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6161 if (stream->use_allocator) {
6162 /* if we have a per-stream allocator, use it */
6163 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6166 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6168 if (G_UNLIKELY (ret != GST_FLOW_OK))
6171 if (size != sample_size) {
6172 pts += gst_util_uint64_scale_int (GST_SECOND,
6173 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6176 gst_util_uint64_scale_int (GST_SECOND,
6177 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6180 gst_util_uint64_scale_int (GST_SECOND,
6181 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6184 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6185 dts, pts, duration, keyframe, min_time, offset);
6187 if (size != sample_size) {
6188 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6189 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6191 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6193 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6194 if (time_position >= segment->media_start) {
6195 /* inside the segment, update time_position, looks very familiar to
6196 * GStreamer segments, doesn't it? */
6197 stream->time_position = (time_position - segment->media_start) +
6200 /* not yet in segment, time does not yet increment. This means
6201 * that we are still prerolling keyframes to the decoder so it can
6202 * decode the first sample of the segment. */
6203 stream->time_position = segment->time;
6208 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6209 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6210 * we have no more data for the pad to push */
6211 if (ret == GST_FLOW_EOS)
6214 stream->offset_in_sample += size;
6215 if (stream->offset_in_sample >= sample_size) {
6216 gst_qtdemux_advance_sample (qtdemux, stream);
6221 gst_qtdemux_advance_sample (qtdemux, stream);
6229 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6235 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6236 /* EOS will be raised if all are EOS */
6243 gst_qtdemux_loop (GstPad * pad)
6245 GstQTDemux *qtdemux;
6249 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6251 cur_offset = qtdemux->offset;
6252 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6253 cur_offset, qt_demux_state_string (qtdemux->state));
6255 switch (qtdemux->state) {
6256 case QTDEMUX_STATE_INITIAL:
6257 case QTDEMUX_STATE_HEADER:
6258 ret = gst_qtdemux_loop_state_header (qtdemux);
6260 case QTDEMUX_STATE_MOVIE:
6261 ret = gst_qtdemux_loop_state_movie (qtdemux);
6262 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6263 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6271 /* if something went wrong, pause */
6272 if (ret != GST_FLOW_OK)
6276 gst_object_unref (qtdemux);
6282 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6283 (NULL), ("streaming stopped, invalid state"));
6284 gst_pad_pause_task (pad);
6285 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6290 const gchar *reason = gst_flow_get_name (ret);
6292 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6294 gst_pad_pause_task (pad);
6296 /* fatal errors need special actions */
6298 if (ret == GST_FLOW_EOS) {
6299 if (qtdemux->n_streams == 0) {
6300 /* we have no streams, post an error */
6301 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6303 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6306 if ((stop = qtdemux->segment.stop) == -1)
6307 stop = qtdemux->segment.duration;
6309 if (qtdemux->segment.rate >= 0) {
6310 GstMessage *message;
6313 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6314 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6315 GST_FORMAT_TIME, stop);
6316 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6317 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6318 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6319 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6321 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6322 gst_qtdemux_push_event (qtdemux, event);
6324 GstMessage *message;
6327 /* For Reverse Playback */
6328 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6329 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6330 GST_FORMAT_TIME, qtdemux->segment.start);
6331 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6332 qtdemux->segment.start);
6333 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6334 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6335 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6337 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6338 gst_qtdemux_push_event (qtdemux, event);
6343 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6344 event = gst_event_new_eos ();
6345 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6346 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6347 gst_qtdemux_push_event (qtdemux, event);
6349 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6350 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6351 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6360 * Returns if there are samples to be played.
6363 has_next_entry (GstQTDemux * demux)
6365 QtDemuxStream *stream;
6368 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6370 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6371 stream = QTDEMUX_STREAM (iter->data);
6373 if (stream->sample_index == -1) {
6374 stream->sample_index = 0;
6375 stream->offset_in_sample = 0;
6378 if (stream->sample_index >= stream->n_samples) {
6379 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6382 GST_DEBUG_OBJECT (demux, "Found a sample");
6386 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6393 * Returns the size of the first entry at the current offset.
6394 * If -1, there are none (which means EOS or empty file).
6397 next_entry_size (GstQTDemux * demux)
6399 QtDemuxStream *stream, *target_stream = NULL;
6400 guint64 smalloffs = (guint64) - 1;
6401 QtDemuxSample *sample;
6404 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6407 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6408 stream = QTDEMUX_STREAM (iter->data);
6410 if (stream->sample_index == -1) {
6411 stream->sample_index = 0;
6412 stream->offset_in_sample = 0;
6415 if (stream->sample_index >= stream->n_samples) {
6416 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6420 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6421 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6422 stream->sample_index);
6426 sample = &stream->samples[stream->sample_index];
6428 GST_LOG_OBJECT (demux,
6429 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6430 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6431 stream->sample_index, sample->offset, sample->size);
6433 if (((smalloffs == -1)
6434 || (sample->offset < smalloffs)) && (sample->size)) {
6435 smalloffs = sample->offset;
6436 target_stream = stream;
6443 GST_LOG_OBJECT (demux,
6444 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6445 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6447 stream = target_stream;
6448 sample = &stream->samples[stream->sample_index];
6450 if (sample->offset >= demux->offset) {
6451 demux->todrop = sample->offset - demux->offset;
6452 return sample->size + demux->todrop;
6455 GST_DEBUG_OBJECT (demux,
6456 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6461 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6463 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6465 gst_element_post_message (GST_ELEMENT_CAST (demux),
6466 gst_message_new_element (GST_OBJECT_CAST (demux),
6467 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6471 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6476 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6479 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6480 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6481 GST_SEEK_TYPE_NONE, -1);
6483 /* store seqnum to drop flush events, they don't need to reach downstream */
6484 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6485 res = gst_pad_push_event (demux->sinkpad, event);
6486 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6491 /* check for seekable upstream, above and beyond a mere query */
6493 gst_qtdemux_check_seekability (GstQTDemux * demux)
6496 gboolean seekable = FALSE;
6497 gint64 start = -1, stop = -1;
6499 if (demux->upstream_size)
6502 if (demux->upstream_format_is_time)
6505 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6506 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6507 GST_DEBUG_OBJECT (demux, "seeking query failed");
6511 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6513 /* try harder to query upstream size if we didn't get it the first time */
6514 if (seekable && stop == -1) {
6515 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6516 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6519 /* if upstream doesn't know the size, it's likely that it's not seekable in
6520 * practice even if it technically may be seekable */
6521 if (seekable && (start != 0 || stop <= start)) {
6522 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6527 gst_query_unref (query);
6529 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6530 G_GUINT64_FORMAT ")", seekable, start, stop);
6531 demux->upstream_seekable = seekable;
6532 demux->upstream_size = seekable ? stop : -1;
6536 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6538 g_return_if_fail (bytes <= demux->todrop);
6540 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6541 gst_adapter_flush (demux->adapter, bytes);
6542 demux->neededbytes -= bytes;
6543 demux->offset += bytes;
6544 demux->todrop -= bytes;
6547 /* PUSH-MODE only: Send a segment, if not done already. */
6549 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6551 if (G_UNLIKELY (demux->need_segment)) {
6555 if (!demux->upstream_format_is_time) {
6556 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6558 GstEvent *segment_event;
6559 segment_event = gst_event_new_segment (&demux->segment);
6560 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6561 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6562 gst_qtdemux_push_event (demux, segment_event);
6565 demux->need_segment = FALSE;
6567 /* clear to send tags on all streams */
6568 for (iter = demux->active_streams, i = 0; iter;
6569 iter = g_list_next (iter), i++) {
6570 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6571 gst_qtdemux_push_tags (demux, stream);
6572 if (CUR_STREAM (stream)->sparse) {
6573 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6574 gst_pad_push_event (stream->pad,
6575 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6581 /* Used for push mode only. */
6583 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6584 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6586 GstClockTime ts, dur;
6590 stream->segments[segment_index].duration - (pos -
6591 stream->segments[segment_index].time);
6592 stream->time_position += dur;
6594 /* Only gaps with a duration of at least one second are propagated.
6595 * Same workaround as in pull mode.
6596 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6597 if (dur >= GST_SECOND) {
6599 gap = gst_event_new_gap (ts, dur);
6601 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6602 "segment: %" GST_PTR_FORMAT, gap);
6603 gst_pad_push_event (stream->pad, gap);
6607 static GstFlowReturn
6608 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6612 demux = GST_QTDEMUX (parent);
6614 GST_DEBUG_OBJECT (demux,
6615 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6616 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6617 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6618 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6619 gst_buffer_get_size (inbuf), demux->offset);
6621 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6622 gboolean is_gap_input = FALSE;
6625 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6627 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6628 QTDEMUX_STREAM (iter->data)->discont = TRUE;
6631 /* Check if we can land back on our feet in the case where upstream is
6632 * handling the seeking/pushing of samples with gaps in between (like
6633 * in the case of trick-mode DASH for example) */
6634 if (demux->upstream_format_is_time
6635 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6636 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6638 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6639 GST_LOG_OBJECT (demux,
6640 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6641 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6643 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6644 stream, GST_BUFFER_OFFSET (inbuf));
6646 QtDemuxSample *sample = &stream->samples[res];
6647 GST_LOG_OBJECT (demux,
6648 "Checking if sample %d from track-id %u is valid (offset:%"
6649 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6650 stream->track_id, sample->offset, sample->size);
6651 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6652 GST_LOG_OBJECT (demux,
6653 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6655 is_gap_input = TRUE;
6656 /* We can go back to standard playback mode */
6657 demux->state = QTDEMUX_STATE_MOVIE;
6658 /* Remember which sample this stream is at */
6659 stream->sample_index = res;
6660 /* Finally update all push-based values to the expected values */
6661 demux->neededbytes = stream->samples[res].size;
6662 demux->offset = GST_BUFFER_OFFSET (inbuf);
6664 demux->mdatsize - demux->offset + demux->mdatoffset;
6669 if (!is_gap_input) {
6670 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6671 /* Reset state if it's a real discont */
6672 demux->neededbytes = 16;
6673 demux->state = QTDEMUX_STATE_INITIAL;
6674 demux->offset = GST_BUFFER_OFFSET (inbuf);
6675 gst_adapter_clear (demux->adapter);
6678 /* Reverse fragmented playback, need to flush all we have before
6679 * consuming a new fragment.
6680 * The samples array have the timestamps calculated by accumulating the
6681 * durations but this won't work for reverse playback of fragments as
6682 * the timestamps of a subsequent fragment should be smaller than the
6683 * previously received one. */
6684 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6685 gst_qtdemux_process_adapter (demux, TRUE);
6686 g_list_foreach (demux->active_streams,
6687 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6691 gst_adapter_push (demux->adapter, inbuf);
6693 GST_DEBUG_OBJECT (demux,
6694 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6695 demux->neededbytes, gst_adapter_available (demux->adapter));
6697 return gst_qtdemux_process_adapter (demux, FALSE);
6700 static GstFlowReturn
6701 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6703 GstFlowReturn ret = GST_FLOW_OK;
6705 /* we never really mean to buffer that much */
6706 if (demux->neededbytes == -1) {
6710 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6711 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6713 #ifndef GST_DISABLE_GST_DEBUG
6715 guint64 discont_offset, distance_from_discont;
6717 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6718 distance_from_discont =
6719 gst_adapter_distance_from_discont (demux->adapter);
6721 GST_DEBUG_OBJECT (demux,
6722 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6723 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6724 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6725 demux->offset, discont_offset, distance_from_discont);
6729 switch (demux->state) {
6730 case QTDEMUX_STATE_INITIAL:{
6735 gst_qtdemux_check_seekability (demux);
6737 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6739 /* get fourcc/length, set neededbytes */
6740 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6742 gst_adapter_unmap (demux->adapter);
6744 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6745 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6747 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6748 (_("This file is invalid and cannot be played.")),
6749 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6750 GST_FOURCC_ARGS (fourcc)));
6751 ret = GST_FLOW_ERROR;
6754 if (fourcc == FOURCC_mdat) {
6755 gint next_entry = next_entry_size (demux);
6756 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6757 /* we have the headers, start playback */
6758 demux->state = QTDEMUX_STATE_MOVIE;
6759 demux->neededbytes = next_entry;
6760 demux->mdatleft = size;
6761 demux->mdatsize = demux->mdatleft;
6763 /* no headers yet, try to get them */
6766 guint64 old, target;
6769 old = demux->offset;
6770 target = old + size;
6772 /* try to jump over the atom with a seek */
6773 /* only bother if it seems worth doing so,
6774 * and avoids possible upstream/server problems */
6775 if (demux->upstream_seekable &&
6776 demux->upstream_size > 4 * (1 << 20)) {
6777 res = qtdemux_seek_offset (demux, target);
6779 GST_DEBUG_OBJECT (demux, "skipping seek");
6784 GST_DEBUG_OBJECT (demux, "seek success");
6785 /* remember the offset fo the first mdat so we can seek back to it
6786 * after we have the headers */
6787 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6788 demux->first_mdat = old;
6789 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6792 /* seek worked, continue reading */
6793 demux->offset = target;
6794 demux->neededbytes = 16;
6795 demux->state = QTDEMUX_STATE_INITIAL;
6797 /* seek failed, need to buffer */
6798 demux->offset = old;
6799 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6800 /* there may be multiple mdat (or alike) buffers */
6802 if (demux->mdatbuffer)
6803 bs = gst_buffer_get_size (demux->mdatbuffer);
6806 if (size + bs > 10 * (1 << 20))
6808 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6809 demux->neededbytes = size;
6810 if (!demux->mdatbuffer)
6811 demux->mdatoffset = demux->offset;
6814 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6815 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6816 (_("This file is invalid and cannot be played.")),
6817 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6818 GST_FOURCC_ARGS (fourcc), size));
6819 ret = GST_FLOW_ERROR;
6822 /* this means we already started buffering and still no moov header,
6823 * let's continue buffering everything till we get moov */
6824 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6825 || fourcc == FOURCC_moof))
6827 demux->neededbytes = size;
6828 demux->state = QTDEMUX_STATE_HEADER;
6832 case QTDEMUX_STATE_HEADER:{
6836 GST_DEBUG_OBJECT (demux, "In header");
6838 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6840 /* parse the header */
6841 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6843 if (fourcc == FOURCC_moov) {
6844 /* in usual fragmented setup we could try to scan for more
6845 * and end up at the the moov (after mdat) again */
6846 if (demux->got_moov && demux->n_streams > 0 &&
6848 || demux->last_moov_offset == demux->offset)) {
6849 GST_DEBUG_OBJECT (demux,
6850 "Skipping moov atom as we have (this) one already");
6852 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6854 if (demux->got_moov && demux->fragmented) {
6855 GST_DEBUG_OBJECT (demux,
6856 "Got a second moov, clean up data from old one");
6857 if (demux->moov_node_compressed) {
6858 g_node_destroy (demux->moov_node_compressed);
6859 if (demux->moov_node)
6860 g_free (demux->moov_node->data);
6862 demux->moov_node_compressed = NULL;
6863 if (demux->moov_node)
6864 g_node_destroy (demux->moov_node);
6865 demux->moov_node = NULL;
6868 demux->last_moov_offset = demux->offset;
6870 /* Update streams with new moov */
6871 demux->old_streams =
6872 g_list_concat (demux->old_streams, demux->active_streams);
6873 demux->active_streams = NULL;
6875 qtdemux_parse_moov (demux, data, demux->neededbytes);
6876 qtdemux_node_dump (demux, demux->moov_node);
6877 qtdemux_parse_tree (demux);
6878 qtdemux_prepare_streams (demux);
6879 QTDEMUX_EXPOSE_LOCK (demux);
6880 qtdemux_expose_streams (demux);
6881 QTDEMUX_EXPOSE_UNLOCK (demux);
6883 demux->got_moov = TRUE;
6885 gst_qtdemux_check_send_pending_segment (demux);
6887 if (demux->moov_node_compressed) {
6888 g_node_destroy (demux->moov_node_compressed);
6889 g_free (demux->moov_node->data);
6891 demux->moov_node_compressed = NULL;
6892 g_node_destroy (demux->moov_node);
6893 demux->moov_node = NULL;
6894 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6896 } else if (fourcc == FOURCC_moof) {
6897 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6899 GstClockTime prev_pts;
6900 guint64 prev_offset;
6901 guint64 adapter_discont_offset, adapter_discont_dist;
6903 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6906 * The timestamp of the moof buffer is relevant as some scenarios
6907 * won't have the initial timestamp in the atoms. Whenever a new
6908 * buffer has started, we get that buffer's PTS and use it as a base
6909 * timestamp for the trun entries.
6911 * To keep track of the current buffer timestamp and starting point
6912 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6913 * from the beggining of the buffer, with the distance and demux->offset
6914 * we know if it is still the same buffer or not.
6916 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6917 prev_offset = demux->offset - dist;
6918 if (demux->fragment_start_offset == -1
6919 || prev_offset > demux->fragment_start_offset) {
6920 demux->fragment_start_offset = prev_offset;
6921 demux->fragment_start = prev_pts;
6922 GST_DEBUG_OBJECT (demux,
6923 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6924 GST_TIME_FORMAT, demux->fragment_start_offset,
6925 GST_TIME_ARGS (demux->fragment_start));
6928 /* We can't use prev_offset() here because this would require
6929 * upstream to set consistent and correct offsets on all buffers
6930 * since the discont. Nothing ever did that in the past and we
6931 * would break backwards compatibility here then.
6932 * Instead take the offset we had at the last discont and count
6933 * the bytes from there. This works with old code as there would
6934 * be no discont between moov and moof, and also works with
6935 * adaptivedemux which correctly sets offset and will set the
6936 * DISCONT flag accordingly when needed.
6938 * We also only do this for upstream TIME segments as otherwise
6939 * there are potential backwards compatibility problems with
6940 * seeking in PUSH mode and upstream providing inconsistent
6942 adapter_discont_offset =
6943 gst_adapter_offset_at_discont (demux->adapter);
6944 adapter_discont_dist =
6945 gst_adapter_distance_from_discont (demux->adapter);
6947 GST_DEBUG_OBJECT (demux,
6948 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6949 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6950 demux->offset, adapter_discont_offset, adapter_discont_dist);
6952 if (demux->upstream_format_is_time) {
6953 demux->moof_offset = adapter_discont_offset;
6954 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6955 demux->moof_offset += adapter_discont_dist;
6956 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6957 demux->moof_offset = demux->offset;
6959 demux->moof_offset = demux->offset;
6962 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6963 demux->moof_offset, NULL)) {
6964 gst_adapter_unmap (demux->adapter);
6965 ret = GST_FLOW_ERROR;
6969 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6970 if (demux->mss_mode && !demux->exposed) {
6971 QTDEMUX_EXPOSE_LOCK (demux);
6972 qtdemux_expose_streams (demux);
6973 QTDEMUX_EXPOSE_UNLOCK (demux);
6976 gst_qtdemux_check_send_pending_segment (demux);
6978 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6980 } else if (fourcc == FOURCC_ftyp) {
6981 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6982 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6983 } else if (fourcc == FOURCC_uuid) {
6984 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6985 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6986 } else if (fourcc == FOURCC_sidx) {
6987 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6988 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6992 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6996 /* [free] and [skip] are padding atoms */
6997 GST_DEBUG_OBJECT (demux,
6998 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6999 GST_FOURCC_ARGS (fourcc));
7002 GST_WARNING_OBJECT (demux,
7003 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7004 GST_FOURCC_ARGS (fourcc));
7005 /* Let's jump that one and go back to initial state */
7009 gst_adapter_unmap (demux->adapter);
7012 if (demux->mdatbuffer && demux->n_streams) {
7013 gsize remaining_data_size = 0;
7015 /* the mdat was before the header */
7016 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7017 demux->n_streams, demux->mdatbuffer);
7018 /* restore our adapter/offset view of things with upstream;
7019 * put preceding buffered data ahead of current moov data.
7020 * This should also handle evil mdat, moov, mdat cases and alike */
7021 gst_adapter_flush (demux->adapter, demux->neededbytes);
7023 /* Store any remaining data after the mdat for later usage */
7024 remaining_data_size = gst_adapter_available (demux->adapter);
7025 if (remaining_data_size > 0) {
7026 g_assert (demux->restoredata_buffer == NULL);
7027 demux->restoredata_buffer =
7028 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7029 demux->restoredata_offset = demux->offset + demux->neededbytes;
7030 GST_DEBUG_OBJECT (demux,
7031 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7032 G_GUINT64_FORMAT, remaining_data_size,
7033 demux->restoredata_offset);
7036 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7037 demux->mdatbuffer = NULL;
7038 demux->offset = demux->mdatoffset;
7039 demux->neededbytes = next_entry_size (demux);
7040 demux->state = QTDEMUX_STATE_MOVIE;
7041 demux->mdatleft = gst_adapter_available (demux->adapter);
7042 demux->mdatsize = demux->mdatleft;
7044 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7045 gst_adapter_flush (demux->adapter, demux->neededbytes);
7047 /* only go back to the mdat if there are samples to play */
7048 if (demux->got_moov && demux->first_mdat != -1
7049 && has_next_entry (demux)) {
7052 /* we need to seek back */
7053 res = qtdemux_seek_offset (demux, demux->first_mdat);
7055 demux->offset = demux->first_mdat;
7057 GST_DEBUG_OBJECT (demux, "Seek back failed");
7060 demux->offset += demux->neededbytes;
7062 demux->neededbytes = 16;
7063 demux->state = QTDEMUX_STATE_INITIAL;
7068 case QTDEMUX_STATE_BUFFER_MDAT:{
7072 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7074 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7075 gst_buffer_extract (buf, 0, fourcc, 4);
7076 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7077 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7078 if (demux->mdatbuffer)
7079 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7081 demux->mdatbuffer = buf;
7082 demux->offset += demux->neededbytes;
7083 demux->neededbytes = 16;
7084 demux->state = QTDEMUX_STATE_INITIAL;
7085 gst_qtdemux_post_progress (demux, 1, 1);
7089 case QTDEMUX_STATE_MOVIE:{
7090 QtDemuxStream *stream = NULL;
7091 QtDemuxSample *sample;
7092 GstClockTime dts, pts, duration;
7096 GST_DEBUG_OBJECT (demux,
7097 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7099 if (demux->fragmented) {
7100 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7102 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7103 /* if needed data starts within this atom,
7104 * then it should not exceed this atom */
7105 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7106 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7107 (_("This file is invalid and cannot be played.")),
7108 ("sample data crosses atom boundary"));
7109 ret = GST_FLOW_ERROR;
7112 demux->mdatleft -= demux->neededbytes;
7114 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7115 /* so we are dropping more than left in this atom */
7116 gst_qtdemux_drop_data (demux, demux->mdatleft);
7117 demux->mdatleft = 0;
7119 /* need to resume atom parsing so we do not miss any other pieces */
7120 demux->state = QTDEMUX_STATE_INITIAL;
7121 demux->neededbytes = 16;
7123 /* check if there was any stored post mdat data from previous buffers */
7124 if (demux->restoredata_buffer) {
7125 g_assert (gst_adapter_available (demux->adapter) == 0);
7127 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7128 demux->restoredata_buffer = NULL;
7129 demux->offset = demux->restoredata_offset;
7136 if (demux->todrop) {
7137 if (demux->cenc_aux_info_offset > 0) {
7141 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7142 data = gst_adapter_map (demux->adapter, demux->todrop);
7143 gst_byte_reader_init (&br, data + 8, demux->todrop);
7144 if (!qtdemux_parse_cenc_aux_info (demux,
7145 QTDEMUX_FIRST_STREAM (demux), &br,
7146 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7147 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7148 ret = GST_FLOW_ERROR;
7149 gst_adapter_unmap (demux->adapter);
7150 g_free (demux->cenc_aux_info_sizes);
7151 demux->cenc_aux_info_sizes = NULL;
7154 demux->cenc_aux_info_offset = 0;
7155 g_free (demux->cenc_aux_info_sizes);
7156 demux->cenc_aux_info_sizes = NULL;
7157 gst_adapter_unmap (demux->adapter);
7159 gst_qtdemux_drop_data (demux, demux->todrop);
7163 /* initial newsegment sent here after having added pads,
7164 * possible others in sink_event */
7165 gst_qtdemux_check_send_pending_segment (demux);
7167 /* Figure out which stream this packet belongs to */
7168 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7169 stream = QTDEMUX_STREAM (iter->data);
7170 if (stream->sample_index >= stream->n_samples) {
7171 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7175 GST_LOG_OBJECT (demux,
7176 "Checking track-id %u (sample_index:%d / offset:%"
7177 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7178 stream->sample_index,
7179 stream->samples[stream->sample_index].offset,
7180 stream->samples[stream->sample_index].size);
7182 if (stream->samples[stream->sample_index].offset == demux->offset)
7186 if (G_UNLIKELY (stream == NULL))
7187 goto unknown_stream;
7189 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7191 if (stream->new_caps) {
7192 gst_qtdemux_configure_stream (demux, stream);
7195 /* Put data in a buffer, set timestamps, caps, ... */
7196 sample = &stream->samples[stream->sample_index];
7198 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7199 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7200 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7202 dts = QTSAMPLE_DTS (stream, sample);
7203 pts = QTSAMPLE_PTS (stream, sample);
7204 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7205 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7207 /* check for segment end */
7208 if (G_UNLIKELY (demux->segment.stop != -1
7209 && demux->segment.stop <= pts && stream->on_keyframe)
7210 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7211 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7212 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7214 /* skip this data, stream is EOS */
7215 gst_adapter_flush (demux->adapter, demux->neededbytes);
7216 demux->offset += demux->neededbytes;
7218 /* check if all streams are eos */
7220 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7221 if (!STREAM_IS_EOS (QTDEMUX_STREAM (iter->data))) {
7230 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7232 /* FIXME: should either be an assert or a plain check */
7233 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7235 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7236 dts, pts, duration, keyframe, dts, demux->offset);
7240 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7242 /* skip this data, stream is EOS */
7243 gst_adapter_flush (demux->adapter, demux->neededbytes);
7246 stream->sample_index++;
7247 stream->offset_in_sample = 0;
7249 /* update current offset and figure out size of next buffer */
7250 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7251 demux->offset, demux->neededbytes);
7252 demux->offset += demux->neededbytes;
7253 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7257 if (ret == GST_FLOW_EOS) {
7258 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7259 demux->neededbytes = -1;
7263 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7264 if (demux->fragmented) {
7265 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7266 /* there may be more to follow, only finish this atom */
7267 demux->todrop = demux->mdatleft;
7268 demux->neededbytes = demux->todrop;
7273 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7274 goto non_ok_unlinked_flow;
7283 /* when buffering movie data, at least show user something is happening */
7284 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7285 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7286 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7287 demux->neededbytes);
7294 non_ok_unlinked_flow:
7296 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7297 gst_flow_get_name (ret));
7302 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7303 ret = GST_FLOW_ERROR;
7308 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7314 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7315 (NULL), ("qtdemuxer invalid state %d", demux->state));
7316 ret = GST_FLOW_ERROR;
7321 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7322 (NULL), ("no 'moov' atom within the first 10 MB"));
7323 ret = GST_FLOW_ERROR;
7329 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7334 query = gst_query_new_scheduling ();
7336 if (!gst_pad_peer_query (sinkpad, query)) {
7337 gst_query_unref (query);
7341 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7342 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7343 gst_query_unref (query);
7348 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7349 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7353 GST_DEBUG_OBJECT (sinkpad, "activating push");
7354 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7359 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7360 GstPadMode mode, gboolean active)
7363 GstQTDemux *demux = GST_QTDEMUX (parent);
7366 case GST_PAD_MODE_PUSH:
7367 demux->pullbased = FALSE;
7370 case GST_PAD_MODE_PULL:
7372 demux->pullbased = TRUE;
7373 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7376 res = gst_pad_stop_task (sinkpad);
7388 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7394 memset (&z, 0, sizeof (z));
7399 if ((ret = inflateInit (&z)) != Z_OK) {
7400 GST_ERROR ("inflateInit() returned %d", ret);
7404 z.next_in = z_buffer;
7405 z.avail_in = z_length;
7407 buffer = (guint8 *) g_malloc (*length);
7408 z.avail_out = *length;
7409 z.next_out = (Bytef *) buffer;
7411 ret = inflate (&z, Z_NO_FLUSH);
7412 if (ret == Z_STREAM_END) {
7414 } else if (ret != Z_OK) {
7415 GST_WARNING ("inflate() returned %d", ret);
7420 buffer = (guint8 *) g_realloc (buffer, *length);
7421 z.next_out = (Bytef *) (buffer + z.total_out);
7422 z.avail_out += 4096;
7423 } while (z.avail_in > 0);
7425 if (ret != Z_STREAM_END) {
7430 *length = z.total_out;
7437 #endif /* HAVE_ZLIB */
7440 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7444 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7446 /* counts as header data */
7447 qtdemux->header_size += length;
7449 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7450 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7452 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7459 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7460 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7461 if (dcom == NULL || cmvd == NULL)
7462 goto invalid_compression;
7464 dcom_len = QT_UINT32 (dcom->data);
7466 goto invalid_compression;
7468 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7472 guint uncompressed_length;
7473 guint compressed_length;
7477 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7479 goto invalid_compression;
7481 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7482 compressed_length = cmvd_len - 12;
7483 GST_LOG ("length = %u", uncompressed_length);
7486 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7487 compressed_length, &uncompressed_length);
7490 qtdemux->moov_node_compressed = qtdemux->moov_node;
7491 qtdemux->moov_node = g_node_new (buf);
7493 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7494 uncompressed_length);
7498 #endif /* HAVE_ZLIB */
7500 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7501 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7508 invalid_compression:
7510 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7516 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7519 while (G_UNLIKELY (buf < end)) {
7523 if (G_UNLIKELY (buf + 4 > end)) {
7524 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7527 len = QT_UINT32 (buf);
7528 if (G_UNLIKELY (len == 0)) {
7529 GST_LOG_OBJECT (qtdemux, "empty container");
7532 if (G_UNLIKELY (len < 8)) {
7533 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7536 if (G_UNLIKELY (len > (end - buf))) {
7537 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7538 (gint) (end - buf));
7542 child = g_node_new ((guint8 *) buf);
7543 g_node_append (node, child);
7544 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7545 qtdemux_parse_node (qtdemux, child, buf, len);
7553 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7556 int len = QT_UINT32 (xdxt->data);
7557 guint8 *buf = xdxt->data;
7558 guint8 *end = buf + len;
7561 /* skip size and type */
7569 size = QT_UINT32 (buf);
7570 type = QT_FOURCC (buf + 4);
7572 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7574 if (buf + size > end || size <= 0)
7580 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7581 GST_FOURCC_ARGS (type));
7585 buffer = gst_buffer_new_and_alloc (size);
7586 gst_buffer_fill (buffer, 0, buf, size);
7587 stream->buffers = g_slist_append (stream->buffers, buffer);
7588 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7591 buffer = gst_buffer_new_and_alloc (size);
7592 gst_buffer_fill (buffer, 0, buf, size);
7593 stream->buffers = g_slist_append (stream->buffers, buffer);
7594 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7597 buffer = gst_buffer_new_and_alloc (size);
7598 gst_buffer_fill (buffer, 0, buf, size);
7599 stream->buffers = g_slist_append (stream->buffers, buffer);
7600 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7603 GST_WARNING_OBJECT (qtdemux,
7604 "unknown theora cookie %" GST_FOURCC_FORMAT,
7605 GST_FOURCC_ARGS (type));
7614 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7618 guint32 node_length = 0;
7619 const QtNodeType *type;
7622 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7624 if (G_UNLIKELY (length < 8))
7625 goto not_enough_data;
7627 node_length = QT_UINT32 (buffer);
7628 fourcc = QT_FOURCC (buffer + 4);
7630 /* ignore empty nodes */
7631 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7634 type = qtdemux_type_get (fourcc);
7636 end = buffer + length;
7638 GST_LOG_OBJECT (qtdemux,
7639 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7640 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7642 if (node_length > length)
7643 goto broken_atom_size;
7645 if (type->flags & QT_FLAG_CONTAINER) {
7646 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7651 if (node_length < 20) {
7652 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7655 GST_DEBUG_OBJECT (qtdemux,
7656 "parsing stsd (sample table, sample description) atom");
7657 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7658 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7669 /* also read alac (or whatever) in stead of mp4a in the following,
7670 * since a similar layout is used in other cases as well */
7671 if (fourcc == FOURCC_mp4a)
7673 else if (fourcc == FOURCC_fLaC)
7678 /* There are two things we might encounter here: a true mp4a atom, and
7679 an mp4a entry in an stsd atom. The latter is what we're interested
7680 in, and it looks like an atom, but isn't really one. The true mp4a
7681 atom is short, so we detect it based on length here. */
7682 if (length < min_size) {
7683 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7684 GST_FOURCC_ARGS (fourcc));
7688 /* 'version' here is the sound sample description version. Types 0 and
7689 1 are documented in the QTFF reference, but type 2 is not: it's
7690 described in Apple header files instead (struct SoundDescriptionV2
7692 version = QT_UINT16 (buffer + 16);
7694 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7695 GST_FOURCC_ARGS (fourcc), version);
7697 /* parse any esds descriptors */
7709 GST_WARNING_OBJECT (qtdemux,
7710 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7711 GST_FOURCC_ARGS (fourcc), version);
7716 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7742 /* codec_data is contained inside these atoms, which all have
7743 * the same format. */
7744 /* video sample description size is 86 bytes without extension.
7745 * node_length have to be bigger than 86 bytes because video sample
7746 * description can include extenstions such as esds, fiel, glbl, etc. */
7747 if (node_length < 86) {
7748 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7749 " sample description length too short (%u < 86)",
7750 GST_FOURCC_ARGS (fourcc), node_length);
7754 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7755 GST_FOURCC_ARGS (fourcc));
7757 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7759 * revision level (2 bytes) : must be set to 0. */
7760 version = QT_UINT32 (buffer + 16);
7761 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7763 /* compressor name : PASCAL string and informative purposes
7764 * first byte : the number of bytes to be displayed.
7765 * it has to be less than 32 because it is reserved
7766 * space of 32 bytes total including itself. */
7767 str_len = QT_UINT8 (buffer + 50);
7769 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7770 (char *) buffer + 51);
7772 GST_WARNING_OBJECT (qtdemux,
7773 "compressorname length too big (%u > 31)", str_len);
7775 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7777 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7782 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7784 /* You are reading this correctly. QTFF specifies that the
7785 * metadata atom is a short atom, whereas ISO BMFF specifies
7786 * it's a full atom. But since so many people are doing things
7787 * differently, we actually peek into the atom to see which
7790 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7791 GST_FOURCC_ARGS (fourcc));
7794 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7795 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7796 * starts with a 'hdlr' atom */
7797 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7798 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7799 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7800 * with version/flags both set to zero */
7801 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7803 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7808 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7809 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7810 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7819 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7820 GST_FOURCC_ARGS (fourcc));
7824 version = QT_UINT32 (buffer + 12);
7825 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7832 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7837 if (length < offset) {
7838 GST_WARNING_OBJECT (qtdemux,
7839 "skipping too small %" GST_FOURCC_FORMAT " box",
7840 GST_FOURCC_ARGS (fourcc));
7843 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7849 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7854 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7859 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7863 if (!strcmp (type->name, "unknown"))
7864 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7868 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7869 GST_FOURCC_ARGS (fourcc));
7875 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7876 (_("This file is corrupt and cannot be played.")),
7877 ("Not enough data for an atom header, got only %u bytes", length));
7882 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7883 (_("This file is corrupt and cannot be played.")),
7884 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7885 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7892 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7896 guint32 child_fourcc;
7898 for (child = g_node_first_child (node); child;
7899 child = g_node_next_sibling (child)) {
7900 buffer = (guint8 *) child->data;
7902 child_fourcc = QT_FOURCC (buffer + 4);
7904 if (G_UNLIKELY (child_fourcc == fourcc)) {
7912 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7913 GstByteReader * parser)
7917 guint32 child_fourcc, child_len;
7919 for (child = g_node_first_child (node); child;
7920 child = g_node_next_sibling (child)) {
7921 buffer = (guint8 *) child->data;
7923 child_len = QT_UINT32 (buffer);
7924 child_fourcc = QT_FOURCC (buffer + 4);
7926 if (G_UNLIKELY (child_fourcc == fourcc)) {
7927 if (G_UNLIKELY (child_len < (4 + 4)))
7929 /* FIXME: must verify if atom length < parent atom length */
7930 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7938 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7940 return g_node_nth_child (node, index);
7944 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7945 GstByteReader * parser)
7949 guint32 child_fourcc, child_len;
7951 for (child = g_node_next_sibling (node); child;
7952 child = g_node_next_sibling (child)) {
7953 buffer = (guint8 *) child->data;
7955 child_fourcc = QT_FOURCC (buffer + 4);
7957 if (child_fourcc == fourcc) {
7959 child_len = QT_UINT32 (buffer);
7960 if (G_UNLIKELY (child_len < (4 + 4)))
7962 /* FIXME: must verify if atom length < parent atom length */
7963 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7972 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7974 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7978 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7980 /* FIXME: This can only reliably work if demuxers have a
7981 * separate streaming thread per srcpad. This should be
7982 * done in a demuxer base class, which integrates parts
7985 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7990 query = gst_query_new_allocation (stream->caps, FALSE);
7992 if (!gst_pad_peer_query (stream->pad, query)) {
7993 /* not a problem, just debug a little */
7994 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7997 if (stream->allocator)
7998 gst_object_unref (stream->allocator);
8000 if (gst_query_get_n_allocation_params (query) > 0) {
8001 /* try the allocator */
8002 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8004 stream->use_allocator = TRUE;
8006 stream->allocator = NULL;
8007 gst_allocation_params_init (&stream->params);
8008 stream->use_allocator = FALSE;
8010 gst_query_unref (query);
8015 pad_query (const GValue * item, GValue * value, gpointer user_data)
8017 GstPad *pad = g_value_get_object (item);
8018 GstQuery *query = user_data;
8021 res = gst_pad_peer_query (pad, query);
8024 g_value_set_boolean (value, TRUE);
8028 GST_INFO_OBJECT (pad, "pad peer query failed");
8033 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8034 GstPadDirection direction)
8037 GstIteratorFoldFunction func = pad_query;
8038 GValue res = { 0, };
8040 g_value_init (&res, G_TYPE_BOOLEAN);
8041 g_value_set_boolean (&res, FALSE);
8044 if (direction == GST_PAD_SRC)
8045 it = gst_element_iterate_src_pads (element);
8047 it = gst_element_iterate_sink_pads (element);
8049 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8050 gst_iterator_resync (it);
8052 gst_iterator_free (it);
8054 return g_value_get_boolean (&res);
8058 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8059 QtDemuxStream * stream)
8063 GstElement *element = GST_ELEMENT (qtdemux);
8065 gchar **filtered_sys_ids;
8066 GValue event_list = G_VALUE_INIT;
8069 /* 1. Check if we already have the context. */
8070 if (qtdemux->preferred_protection_system_id != NULL) {
8071 GST_LOG_OBJECT (element,
8072 "already have the protection context, no need to request it again");
8076 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8077 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8078 (const gchar **) qtdemux->protection_system_ids->pdata);
8080 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8081 qtdemux->protection_system_ids->len - 1);
8082 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8083 "decryptors for %u of them, running context request",
8084 qtdemux->protection_system_ids->len, g_strv_length (filtered_sys_ids));
8086 if (stream->protection_scheme_event_queue.length) {
8087 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8088 stream->protection_scheme_event_queue.length);
8089 walk = stream->protection_scheme_event_queue.tail;
8091 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8092 qtdemux->protection_event_queue.length);
8093 walk = qtdemux->protection_event_queue.tail;
8096 g_value_init (&event_list, GST_TYPE_LIST);
8097 for (; walk; walk = g_list_previous (walk)) {
8098 GValue *event_value = g_new0 (GValue, 1);
8099 g_value_init (event_value, GST_TYPE_EVENT);
8100 g_value_set_boxed (event_value, walk->data);
8101 gst_value_list_append_and_take_value (&event_list, event_value);
8104 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8105 * check if downstream already has a context of the specific type
8106 * 2b) Query upstream as above.
8108 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8109 st = gst_query_writable_structure (query);
8110 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8111 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8113 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8114 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8115 gst_query_parse_context (query, &ctxt);
8116 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8117 gst_element_set_context (element, ctxt);
8118 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8119 gst_query_parse_context (query, &ctxt);
8120 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8121 gst_element_set_context (element, ctxt);
8123 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8124 * the required context type and afterwards check if a
8125 * usable context was set now as in 1). The message could
8126 * be handled by the parent bins of the element and the
8131 GST_INFO_OBJECT (element, "posting need context message");
8132 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8133 "drm-preferred-decryption-system-id");
8134 st = (GstStructure *) gst_message_get_structure (msg);
8135 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8136 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8139 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8140 gst_element_post_message (element, msg);
8143 g_strfreev (filtered_sys_ids);
8144 g_value_unset (&event_list);
8145 gst_query_unref (query);
8149 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8150 QtDemuxStream * stream)
8153 const gchar *selected_system = NULL;
8155 g_return_val_if_fail (qtdemux != NULL, FALSE);
8156 g_return_val_if_fail (stream != NULL, FALSE);
8157 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8160 if (stream->protection_scheme_type != FOURCC_cenc) {
8161 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
8164 if (qtdemux->protection_system_ids == NULL) {
8165 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8166 "cenc protection system information has been found");
8170 gst_qtdemux_request_protection_context (qtdemux, stream);
8171 if (qtdemux->preferred_protection_system_id != NULL) {
8172 const gchar *preferred_system_array[] =
8173 { qtdemux->preferred_protection_system_id, NULL };
8175 selected_system = gst_protection_select_system (preferred_system_array);
8177 if (selected_system) {
8178 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8179 qtdemux->preferred_protection_system_id);
8181 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8182 "because there is no available decryptor",
8183 qtdemux->preferred_protection_system_id);
8187 if (!selected_system) {
8188 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8189 selected_system = gst_protection_select_system ((const gchar **)
8190 qtdemux->protection_system_ids->pdata);
8191 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8192 qtdemux->protection_system_ids->len - 1);
8195 if (!selected_system) {
8196 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8197 "suitable decryptor element has been found");
8201 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8204 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8205 if (!gst_structure_has_name (s, "application/x-cenc")) {
8206 gst_structure_set (s,
8207 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8208 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8210 gst_structure_set_name (s, "application/x-cenc");
8216 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8218 if (stream->subtype == FOURCC_vide) {
8219 /* fps is calculated base on the duration of the average framerate since
8220 * qt does not have a fixed framerate. */
8221 gboolean fps_available = TRUE;
8222 guint32 first_duration = 0;
8224 if (stream->n_samples > 0)
8225 first_duration = stream->samples[0].duration;
8227 if ((stream->n_samples == 1 && first_duration == 0)
8228 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8230 CUR_STREAM (stream)->fps_n = 0;
8231 CUR_STREAM (stream)->fps_d = 1;
8233 if (stream->duration == 0 || stream->n_samples < 2) {
8234 CUR_STREAM (stream)->fps_n = stream->timescale;
8235 CUR_STREAM (stream)->fps_d = 1;
8236 fps_available = FALSE;
8238 GstClockTime avg_duration;
8242 /* duration and n_samples can be updated for fragmented format
8243 * so, framerate of fragmented format is calculated using data in a moof */
8244 if (qtdemux->fragmented && stream->n_samples_moof > 0
8245 && stream->duration_moof > 0) {
8246 n_samples = stream->n_samples_moof;
8247 duration = stream->duration_moof;
8249 n_samples = stream->n_samples;
8250 duration = stream->duration;
8253 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8254 /* stream->duration is guint64, timescale, n_samples are guint32 */
8256 gst_util_uint64_scale_round (duration -
8257 first_duration, GST_SECOND,
8258 (guint64) (stream->timescale) * (n_samples - 1));
8260 GST_LOG_OBJECT (qtdemux,
8261 "Calculating avg sample duration based on stream (or moof) duration %"
8263 " minus first sample %u, leaving %d samples gives %"
8264 GST_TIME_FORMAT, duration, first_duration,
8265 n_samples - 1, GST_TIME_ARGS (avg_duration));
8267 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8268 &CUR_STREAM (stream)->fps_d);
8270 GST_DEBUG_OBJECT (qtdemux,
8271 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8272 stream->timescale, CUR_STREAM (stream)->fps_n,
8273 CUR_STREAM (stream)->fps_d);
8277 if (CUR_STREAM (stream)->caps) {
8278 CUR_STREAM (stream)->caps =
8279 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8281 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8282 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8283 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8285 /* set framerate if calculated framerate is reliable */
8286 if (fps_available) {
8287 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8288 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8289 CUR_STREAM (stream)->fps_d, NULL);
8292 /* calculate pixel-aspect-ratio using display width and height */
8293 GST_DEBUG_OBJECT (qtdemux,
8294 "video size %dx%d, target display size %dx%d",
8295 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8296 stream->display_width, stream->display_height);
8297 /* qt file might have pasp atom */
8298 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8299 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8300 CUR_STREAM (stream)->par_h);
8301 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8302 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8303 CUR_STREAM (stream)->par_h, NULL);
8304 } else if (stream->display_width > 0 && stream->display_height > 0
8305 && CUR_STREAM (stream)->width > 0
8306 && CUR_STREAM (stream)->height > 0) {
8309 /* calculate the pixel aspect ratio using the display and pixel w/h */
8310 n = stream->display_width * CUR_STREAM (stream)->height;
8311 d = stream->display_height * CUR_STREAM (stream)->width;
8314 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8315 CUR_STREAM (stream)->par_w = n;
8316 CUR_STREAM (stream)->par_h = d;
8317 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8318 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8319 CUR_STREAM (stream)->par_h, NULL);
8322 if (CUR_STREAM (stream)->interlace_mode > 0) {
8323 if (CUR_STREAM (stream)->interlace_mode == 1) {
8324 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8325 G_TYPE_STRING, "progressive", NULL);
8326 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8327 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8328 G_TYPE_STRING, "interleaved", NULL);
8329 if (CUR_STREAM (stream)->field_order == 9) {
8330 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8331 G_TYPE_STRING, "top-field-first", NULL);
8332 } else if (CUR_STREAM (stream)->field_order == 14) {
8333 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8334 G_TYPE_STRING, "bottom-field-first", NULL);
8339 /* Create incomplete colorimetry here if needed */
8340 if (CUR_STREAM (stream)->colorimetry.range ||
8341 CUR_STREAM (stream)->colorimetry.matrix ||
8342 CUR_STREAM (stream)->colorimetry.transfer
8343 || CUR_STREAM (stream)->colorimetry.primaries) {
8344 gchar *colorimetry =
8345 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8346 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8347 G_TYPE_STRING, colorimetry, NULL);
8348 g_free (colorimetry);
8351 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8352 guint par_w = 1, par_h = 1;
8354 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8355 par_w = CUR_STREAM (stream)->par_w;
8356 par_h = CUR_STREAM (stream)->par_h;
8359 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8360 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8362 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8365 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8366 "multiview-mode", G_TYPE_STRING,
8367 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8368 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8369 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8374 else if (stream->subtype == FOURCC_soun) {
8375 if (CUR_STREAM (stream)->caps) {
8376 CUR_STREAM (stream)->caps =
8377 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8378 if (CUR_STREAM (stream)->rate > 0)
8379 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8380 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8381 if (CUR_STREAM (stream)->n_channels > 0)
8382 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8383 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8384 if (CUR_STREAM (stream)->n_channels > 2) {
8385 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8386 * correctly; this is just the minimum we can do - assume
8387 * we don't actually have any channel positions. */
8388 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8389 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8395 GstCaps *prev_caps = NULL;
8397 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8398 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8399 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8400 gst_pad_set_active (stream->pad, TRUE);
8402 gst_pad_use_fixed_caps (stream->pad);
8404 if (stream->protected) {
8405 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8406 GST_ERROR_OBJECT (qtdemux,
8407 "Failed to configure protected stream caps.");
8412 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8413 CUR_STREAM (stream)->caps);
8414 if (stream->new_stream) {
8416 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8419 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8422 gst_event_parse_stream_flags (event, &stream_flags);
8423 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8424 qtdemux->have_group_id = TRUE;
8426 qtdemux->have_group_id = FALSE;
8427 gst_event_unref (event);
8428 } else if (!qtdemux->have_group_id) {
8429 qtdemux->have_group_id = TRUE;
8430 qtdemux->group_id = gst_util_group_id_next ();
8433 stream->new_stream = FALSE;
8434 event = gst_event_new_stream_start (stream->stream_id);
8435 if (qtdemux->have_group_id)
8436 gst_event_set_group_id (event, qtdemux->group_id);
8437 if (stream->disabled)
8438 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8439 if (CUR_STREAM (stream)->sparse) {
8440 stream_flags |= GST_STREAM_FLAG_SPARSE;
8442 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8444 gst_event_set_stream_flags (event, stream_flags);
8445 gst_pad_push_event (stream->pad, event);
8448 prev_caps = gst_pad_get_current_caps (stream->pad);
8450 if (CUR_STREAM (stream)->caps) {
8452 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8453 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8454 CUR_STREAM (stream)->caps);
8455 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8457 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8460 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8464 gst_caps_unref (prev_caps);
8465 stream->new_caps = FALSE;
8471 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8472 QtDemuxStream * stream)
8474 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8477 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8478 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8479 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8480 stream->stsd_entries_length)) {
8481 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8482 (_("This file is invalid and cannot be played.")),
8483 ("New sample description id is out of bounds (%d >= %d)",
8484 stream->stsd_sample_description_id, stream->stsd_entries_length));
8486 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8487 stream->new_caps = TRUE;
8492 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8493 QtDemuxStream * stream, GstTagList * list)
8495 gboolean ret = TRUE;
8496 /* consistent default for push based mode */
8497 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8499 if (stream->subtype == FOURCC_vide) {
8500 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8503 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8506 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8507 gst_object_unref (stream->pad);
8513 qtdemux->n_video_streams++;
8514 } else if (stream->subtype == FOURCC_soun) {
8515 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8518 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8520 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8521 gst_object_unref (stream->pad);
8526 qtdemux->n_audio_streams++;
8527 } else if (stream->subtype == FOURCC_strm) {
8528 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8529 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8530 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8531 || stream->subtype == FOURCC_clcp) {
8532 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8535 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8537 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8538 gst_object_unref (stream->pad);
8543 qtdemux->n_sub_streams++;
8544 } else if (CUR_STREAM (stream)->caps) {
8545 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8548 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8550 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8551 gst_object_unref (stream->pad);
8556 qtdemux->n_video_streams++;
8558 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8565 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8566 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8567 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8568 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8570 if (stream->stream_tags)
8571 gst_tag_list_unref (stream->stream_tags);
8572 stream->stream_tags = list;
8574 /* global tags go on each pad anyway */
8575 stream->send_global_tags = TRUE;
8576 /* send upstream GST_EVENT_PROTECTION events that were received before
8577 this source pad was created */
8578 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8579 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8583 gst_tag_list_unref (list);
8587 /* find next atom with @fourcc starting at @offset */
8588 static GstFlowReturn
8589 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8590 guint64 * length, guint32 fourcc)
8596 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8597 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8603 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8604 if (G_UNLIKELY (ret != GST_FLOW_OK))
8606 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8609 gst_buffer_unref (buf);
8612 gst_buffer_map (buf, &map, GST_MAP_READ);
8613 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8614 gst_buffer_unmap (buf, &map);
8615 gst_buffer_unref (buf);
8617 if (G_UNLIKELY (*length == 0)) {
8618 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8619 ret = GST_FLOW_ERROR;
8623 if (lfourcc == fourcc) {
8624 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8628 GST_LOG_OBJECT (qtdemux,
8629 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8630 GST_FOURCC_ARGS (fourcc), *offset);
8639 /* might simply have had last one */
8640 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8645 /* should only do something in pull mode */
8646 /* call with OBJECT lock */
8647 static GstFlowReturn
8648 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8650 guint64 length, offset;
8651 GstBuffer *buf = NULL;
8652 GstFlowReturn ret = GST_FLOW_OK;
8653 GstFlowReturn res = GST_FLOW_OK;
8656 offset = qtdemux->moof_offset;
8657 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8660 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8661 return GST_FLOW_EOS;
8664 /* best not do pull etc with lock held */
8665 GST_OBJECT_UNLOCK (qtdemux);
8667 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8668 if (ret != GST_FLOW_OK)
8671 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8672 if (G_UNLIKELY (ret != GST_FLOW_OK))
8674 gst_buffer_map (buf, &map, GST_MAP_READ);
8675 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8676 gst_buffer_unmap (buf, &map);
8677 gst_buffer_unref (buf);
8682 gst_buffer_unmap (buf, &map);
8683 gst_buffer_unref (buf);
8687 /* look for next moof */
8688 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8689 if (G_UNLIKELY (ret != GST_FLOW_OK))
8693 GST_OBJECT_LOCK (qtdemux);
8695 qtdemux->moof_offset = offset;
8701 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8703 res = GST_FLOW_ERROR;
8708 /* maybe upstream temporarily flushing */
8709 if (ret != GST_FLOW_FLUSHING) {
8710 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8713 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8714 /* resume at current position next time */
8721 /* initialise bytereaders for stbl sub-atoms */
8723 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8725 stream->stbl_index = -1; /* no samples have yet been parsed */
8726 stream->sample_index = -1;
8728 /* time-to-sample atom */
8729 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8732 /* copy atom data into a new buffer for later use */
8733 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8735 /* skip version + flags */
8736 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8737 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8739 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8741 /* make sure there's enough data */
8742 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8743 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8744 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8745 stream->n_sample_times);
8746 if (!stream->n_sample_times)
8750 /* sync sample atom */
8751 stream->stps_present = FALSE;
8752 if ((stream->stss_present =
8753 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8754 &stream->stss) ? TRUE : FALSE) == TRUE) {
8755 /* copy atom data into a new buffer for later use */
8756 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8758 /* skip version + flags */
8759 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8760 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8763 if (stream->n_sample_syncs) {
8764 /* make sure there's enough data */
8765 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8769 /* partial sync sample atom */
8770 if ((stream->stps_present =
8771 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8772 &stream->stps) ? TRUE : FALSE) == TRUE) {
8773 /* copy atom data into a new buffer for later use */
8774 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8776 /* skip version + flags */
8777 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8778 !gst_byte_reader_get_uint32_be (&stream->stps,
8779 &stream->n_sample_partial_syncs))
8782 /* if there are no entries, the stss table contains the real
8784 if (stream->n_sample_partial_syncs) {
8785 /* make sure there's enough data */
8786 if (!qt_atom_parser_has_chunks (&stream->stps,
8787 stream->n_sample_partial_syncs, 4))
8794 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8797 /* copy atom data into a new buffer for later use */
8798 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8800 /* skip version + flags */
8801 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8802 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8805 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8808 if (!stream->n_samples)
8811 /* sample-to-chunk atom */
8812 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8815 /* copy atom data into a new buffer for later use */
8816 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8818 /* skip version + flags */
8819 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8820 !gst_byte_reader_get_uint32_be (&stream->stsc,
8821 &stream->n_samples_per_chunk))
8824 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8825 stream->n_samples_per_chunk);
8827 /* make sure there's enough data */
8828 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8834 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8835 stream->co_size = sizeof (guint32);
8836 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8838 stream->co_size = sizeof (guint64);
8842 /* copy atom data into a new buffer for later use */
8843 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8845 /* skip version + flags */
8846 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8849 /* chunks_are_samples == TRUE means treat chunks as samples */
8850 stream->chunks_are_samples = stream->sample_size
8851 && !CUR_STREAM (stream)->sampled;
8852 if (stream->chunks_are_samples) {
8853 /* treat chunks as samples */
8854 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8857 /* skip number of entries */
8858 if (!gst_byte_reader_skip (&stream->stco, 4))
8861 /* make sure there are enough data in the stsz atom */
8862 if (!stream->sample_size) {
8863 /* different sizes for each sample */
8864 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8869 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8870 stream->n_samples, (guint) sizeof (QtDemuxSample),
8871 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8873 if (stream->n_samples >=
8874 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8875 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8876 "be larger than %uMB (broken file?)", stream->n_samples,
8877 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8881 g_assert (stream->samples == NULL);
8882 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8883 if (!stream->samples) {
8884 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8889 /* composition time-to-sample */
8890 if ((stream->ctts_present =
8891 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8892 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8893 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8895 /* copy atom data into a new buffer for later use */
8896 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8898 /* skip version + flags */
8899 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8900 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8901 &stream->n_composition_times))
8904 /* make sure there's enough data */
8905 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8909 /* This is optional, if missing we iterate the ctts */
8910 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8911 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8912 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8913 g_free ((gpointer) cslg.data);
8917 gint32 cslg_least = 0;
8918 guint num_entries, pos;
8921 pos = gst_byte_reader_get_pos (&stream->ctts);
8922 num_entries = stream->n_composition_times;
8924 stream->cslg_shift = 0;
8926 for (i = 0; i < num_entries; i++) {
8929 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8930 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8932 if (offset < cslg_least)
8933 cslg_least = offset;
8937 stream->cslg_shift = ABS (cslg_least);
8939 stream->cslg_shift = 0;
8941 /* reset the reader so we can generate sample table */
8942 gst_byte_reader_set_pos (&stream->ctts, pos);
8945 /* Ensure the cslg_shift value is consistent so we can use it
8946 * unconditionnally to produce TS and Segment */
8947 stream->cslg_shift = 0;
8954 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8955 (_("This file is corrupt and cannot be played.")), (NULL));
8960 gst_qtdemux_stbl_free (stream);
8961 if (!qtdemux->fragmented) {
8962 /* not quite good */
8963 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8966 /* may pick up samples elsewhere */
8972 /* collect samples from the next sample to be parsed up to sample @n for @stream
8973 * by reading the info from @stbl
8975 * This code can be executed from both the streaming thread and the seeking
8976 * thread so it takes the object lock to protect itself
8979 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8982 QtDemuxSample *samples, *first, *cur, *last;
8983 guint32 n_samples_per_chunk;
8986 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8987 GST_FOURCC_FORMAT ", pad %s",
8988 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8989 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8991 n_samples = stream->n_samples;
8994 goto out_of_samples;
8996 GST_OBJECT_LOCK (qtdemux);
8997 if (n <= stream->stbl_index)
8998 goto already_parsed;
9000 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9002 if (!stream->stsz.data) {
9003 /* so we already parsed and passed all the moov samples;
9004 * onto fragmented ones */
9005 g_assert (qtdemux->fragmented);
9009 /* pointer to the sample table */
9010 samples = stream->samples;
9012 /* starts from -1, moves to the next sample index to parse */
9013 stream->stbl_index++;
9015 /* keep track of the first and last sample to fill */
9016 first = &samples[stream->stbl_index];
9019 if (!stream->chunks_are_samples) {
9020 /* set the sample sizes */
9021 if (stream->sample_size == 0) {
9022 /* different sizes for each sample */
9023 for (cur = first; cur <= last; cur++) {
9024 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9025 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9026 (guint) (cur - samples), cur->size);
9029 /* samples have the same size */
9030 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9031 for (cur = first; cur <= last; cur++)
9032 cur->size = stream->sample_size;
9036 n_samples_per_chunk = stream->n_samples_per_chunk;
9039 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9042 if (stream->stsc_chunk_index >= stream->last_chunk
9043 || stream->stsc_chunk_index < stream->first_chunk) {
9044 stream->first_chunk =
9045 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9046 stream->samples_per_chunk =
9047 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9049 stream->stsd_sample_description_id =
9050 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9052 /* chunk numbers are counted from 1 it seems */
9053 if (G_UNLIKELY (stream->first_chunk == 0))
9056 --stream->first_chunk;
9058 /* the last chunk of each entry is calculated by taking the first chunk
9059 * of the next entry; except if there is no next, where we fake it with
9061 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9062 stream->last_chunk = G_MAXUINT32;
9064 stream->last_chunk =
9065 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9066 if (G_UNLIKELY (stream->last_chunk == 0))
9069 --stream->last_chunk;
9072 GST_LOG_OBJECT (qtdemux,
9073 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9074 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9075 stream->samples_per_chunk, stream->stsd_sample_description_id);
9077 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9080 if (stream->last_chunk != G_MAXUINT32) {
9081 if (!qt_atom_parser_peek_sub (&stream->stco,
9082 stream->first_chunk * stream->co_size,
9083 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9088 stream->co_chunk = stream->stco;
9089 if (!gst_byte_reader_skip (&stream->co_chunk,
9090 stream->first_chunk * stream->co_size))
9094 stream->stsc_chunk_index = stream->first_chunk;
9097 last_chunk = stream->last_chunk;
9099 if (stream->chunks_are_samples) {
9100 cur = &samples[stream->stsc_chunk_index];
9102 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9105 stream->stsc_chunk_index = j;
9110 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9113 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9114 "%" G_GUINT64_FORMAT, j, cur->offset);
9116 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9117 CUR_STREAM (stream)->bytes_per_frame > 0) {
9119 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9120 CUR_STREAM (stream)->samples_per_frame *
9121 CUR_STREAM (stream)->bytes_per_frame;
9123 cur->size = stream->samples_per_chunk;
9126 GST_DEBUG_OBJECT (qtdemux,
9127 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9128 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9129 stream->stco_sample_index)), cur->size);
9131 cur->timestamp = stream->stco_sample_index;
9132 cur->duration = stream->samples_per_chunk;
9133 cur->keyframe = TRUE;
9136 stream->stco_sample_index += stream->samples_per_chunk;
9138 stream->stsc_chunk_index = j;
9140 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9141 guint32 samples_per_chunk;
9142 guint64 chunk_offset;
9144 if (!stream->stsc_sample_index
9145 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9146 &stream->chunk_offset))
9149 samples_per_chunk = stream->samples_per_chunk;
9150 chunk_offset = stream->chunk_offset;
9152 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9153 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9154 G_GUINT64_FORMAT " and size %d",
9155 (guint) (cur - samples), chunk_offset, cur->size);
9157 cur->offset = chunk_offset;
9158 chunk_offset += cur->size;
9161 if (G_UNLIKELY (cur > last)) {
9163 stream->stsc_sample_index = k + 1;
9164 stream->chunk_offset = chunk_offset;
9165 stream->stsc_chunk_index = j;
9169 stream->stsc_sample_index = 0;
9171 stream->stsc_chunk_index = j;
9173 stream->stsc_index++;
9176 if (stream->chunks_are_samples)
9180 guint32 n_sample_times;
9182 n_sample_times = stream->n_sample_times;
9185 for (i = stream->stts_index; i < n_sample_times; i++) {
9186 guint32 stts_samples;
9187 gint32 stts_duration;
9190 if (stream->stts_sample_index >= stream->stts_samples
9191 || !stream->stts_sample_index) {
9193 stream->stts_samples =
9194 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9195 stream->stts_duration =
9196 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9198 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9199 i, stream->stts_samples, stream->stts_duration);
9201 stream->stts_sample_index = 0;
9204 stts_samples = stream->stts_samples;
9205 stts_duration = stream->stts_duration;
9206 stts_time = stream->stts_time;
9208 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9209 GST_DEBUG_OBJECT (qtdemux,
9210 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9211 (guint) (cur - samples), j,
9212 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9214 cur->timestamp = stts_time;
9215 cur->duration = stts_duration;
9217 /* avoid 32-bit wrap-around,
9218 * but still mind possible 'negative' duration */
9219 stts_time += (gint64) stts_duration;
9222 if (G_UNLIKELY (cur > last)) {
9224 stream->stts_time = stts_time;
9225 stream->stts_sample_index = j + 1;
9226 if (stream->stts_sample_index >= stream->stts_samples)
9227 stream->stts_index++;
9231 stream->stts_sample_index = 0;
9232 stream->stts_time = stts_time;
9233 stream->stts_index++;
9235 /* fill up empty timestamps with the last timestamp, this can happen when
9236 * the last samples do not decode and so we don't have timestamps for them.
9237 * We however look at the last timestamp to estimate the track length so we
9238 * need something in here. */
9239 for (; cur < last; cur++) {
9240 GST_DEBUG_OBJECT (qtdemux,
9241 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9242 (guint) (cur - samples),
9243 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9244 cur->timestamp = stream->stts_time;
9250 /* sample sync, can be NULL */
9251 if (stream->stss_present == TRUE) {
9252 guint32 n_sample_syncs;
9254 n_sample_syncs = stream->n_sample_syncs;
9256 if (!n_sample_syncs) {
9257 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9258 stream->all_keyframe = TRUE;
9260 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9261 /* note that the first sample is index 1, not 0 */
9264 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9266 if (G_LIKELY (index > 0 && index <= n_samples)) {
9268 samples[index].keyframe = TRUE;
9269 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9270 /* and exit if we have enough samples */
9271 if (G_UNLIKELY (index >= n)) {
9278 stream->stss_index = i;
9281 /* stps marks partial sync frames like open GOP I-Frames */
9282 if (stream->stps_present == TRUE) {
9283 guint32 n_sample_partial_syncs;
9285 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9287 /* if there are no entries, the stss table contains the real
9289 if (n_sample_partial_syncs) {
9290 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9291 /* note that the first sample is index 1, not 0 */
9294 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9296 if (G_LIKELY (index > 0 && index <= n_samples)) {
9298 samples[index].keyframe = TRUE;
9299 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9300 /* and exit if we have enough samples */
9301 if (G_UNLIKELY (index >= n)) {
9308 stream->stps_index = i;
9312 /* no stss, all samples are keyframes */
9313 stream->all_keyframe = TRUE;
9314 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9319 /* composition time to sample */
9320 if (stream->ctts_present == TRUE) {
9321 guint32 n_composition_times;
9323 gint32 ctts_soffset;
9325 /* Fill in the pts_offsets */
9327 n_composition_times = stream->n_composition_times;
9329 for (i = stream->ctts_index; i < n_composition_times; i++) {
9330 if (stream->ctts_sample_index >= stream->ctts_count
9331 || !stream->ctts_sample_index) {
9332 stream->ctts_count =
9333 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9334 stream->ctts_soffset =
9335 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9336 stream->ctts_sample_index = 0;
9339 ctts_count = stream->ctts_count;
9340 ctts_soffset = stream->ctts_soffset;
9342 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9343 cur->pts_offset = ctts_soffset;
9346 if (G_UNLIKELY (cur > last)) {
9348 stream->ctts_sample_index = j + 1;
9352 stream->ctts_sample_index = 0;
9353 stream->ctts_index++;
9357 stream->stbl_index = n;
9358 /* if index has been completely parsed, free data that is no-longer needed */
9359 if (n + 1 == stream->n_samples) {
9360 gst_qtdemux_stbl_free (stream);
9361 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9362 if (qtdemux->pullbased) {
9363 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9364 while (n + 1 == stream->n_samples)
9365 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9369 GST_OBJECT_UNLOCK (qtdemux);
9376 GST_LOG_OBJECT (qtdemux,
9377 "Tried to parse up to sample %u but this sample has already been parsed",
9379 /* if fragmented, there may be more */
9380 if (qtdemux->fragmented && n == stream->stbl_index)
9382 GST_OBJECT_UNLOCK (qtdemux);
9388 GST_LOG_OBJECT (qtdemux,
9389 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9391 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9392 (_("This file is corrupt and cannot be played.")), (NULL));
9397 GST_OBJECT_UNLOCK (qtdemux);
9398 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9399 (_("This file is corrupt and cannot be played.")), (NULL));
9404 /* collect all segment info for @stream.
9407 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9411 /* accept edts if they contain gaps at start and there is only
9412 * one media segment */
9413 gboolean allow_pushbased_edts = TRUE;
9414 gint media_segments_count = 0;
9416 /* parse and prepare segment info from the edit list */
9417 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9418 stream->n_segments = 0;
9419 stream->segments = NULL;
9420 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9423 gint segment_number, entry_size;
9426 const guint8 *buffer;
9430 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9431 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9434 buffer = elst->data;
9436 size = QT_UINT32 (buffer);
9437 /* version, flags, n_segments */
9439 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9442 version = QT_UINT8 (buffer + 8);
9443 entry_size = (version == 1) ? 20 : 12;
9445 n_segments = QT_UINT32 (buffer + 12);
9447 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9448 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9452 /* we might allocate a bit too much, at least allocate 1 segment */
9453 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9455 /* segments always start from 0 */
9459 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9462 gboolean empty_edit = FALSE;
9463 QtDemuxSegment *segment;
9465 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9468 media_time = QT_UINT64 (buffer + 8);
9469 duration = QT_UINT64 (buffer);
9470 if (media_time == G_MAXUINT64)
9473 media_time = QT_UINT32 (buffer + 4);
9474 duration = QT_UINT32 (buffer);
9475 if (media_time == G_MAXUINT32)
9480 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9482 segment = &stream->segments[segment_number];
9484 /* time and duration expressed in global timescale */
9485 segment->time = stime;
9486 if (duration != 0 || empty_edit) {
9487 /* edge case: empty edits with duration=zero are treated here.
9488 * (files should not have these anyway). */
9490 /* add non scaled values so we don't cause roundoff errors */
9492 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9493 segment->duration = stime - segment->time;
9495 /* zero duration does not imply media_start == media_stop
9496 * but, only specify media_start. The edit ends with the track. */
9497 stime = segment->duration = GST_CLOCK_TIME_NONE;
9498 /* Don't allow more edits after this one. */
9499 n_segments = segment_number + 1;
9501 segment->stop_time = stime;
9503 segment->trak_media_start = media_time;
9504 /* media_time expressed in stream timescale */
9506 segment->media_start = media_start;
9507 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9508 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9509 media_segments_count++;
9511 segment->media_start = GST_CLOCK_TIME_NONE;
9512 segment->media_stop = GST_CLOCK_TIME_NONE;
9514 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9516 if (rate_int <= 1) {
9517 /* 0 is not allowed, some programs write 1 instead of the floating point
9519 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9523 segment->rate = rate_int / 65536.0;
9526 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9527 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9528 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9529 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9530 segment_number, GST_TIME_ARGS (segment->time),
9531 GST_TIME_ARGS (segment->duration),
9532 GST_TIME_ARGS (segment->media_start), media_time,
9533 GST_TIME_ARGS (segment->media_stop),
9534 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9536 if (segment->stop_time > qtdemux->segment.stop &&
9537 !qtdemux->upstream_format_is_time) {
9538 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9539 " extends to %" GST_TIME_FORMAT
9540 " past the end of the declared movie duration %" GST_TIME_FORMAT
9541 " movie segment will be extended", segment_number,
9542 GST_TIME_ARGS (segment->stop_time),
9543 GST_TIME_ARGS (qtdemux->segment.stop));
9544 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9547 buffer += entry_size;
9549 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9550 stream->n_segments = n_segments;
9551 if (media_segments_count != 1)
9552 allow_pushbased_edts = FALSE;
9556 /* push based does not handle segments, so act accordingly here,
9557 * and warn if applicable */
9558 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9559 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9560 /* remove and use default one below, we stream like it anyway */
9561 g_free (stream->segments);
9562 stream->segments = NULL;
9563 stream->n_segments = 0;
9566 /* no segments, create one to play the complete trak */
9567 if (stream->n_segments == 0) {
9568 GstClockTime stream_duration =
9569 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9571 if (stream->segments == NULL)
9572 stream->segments = g_new (QtDemuxSegment, 1);
9574 /* represent unknown our way */
9575 if (stream_duration == 0)
9576 stream_duration = GST_CLOCK_TIME_NONE;
9578 stream->segments[0].time = 0;
9579 stream->segments[0].stop_time = stream_duration;
9580 stream->segments[0].duration = stream_duration;
9581 stream->segments[0].media_start = 0;
9582 stream->segments[0].media_stop = stream_duration;
9583 stream->segments[0].rate = 1.0;
9584 stream->segments[0].trak_media_start = 0;
9586 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9587 GST_TIME_ARGS (stream_duration));
9588 stream->n_segments = 1;
9589 stream->dummy_segment = TRUE;
9591 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9597 * Parses the stsd atom of a svq3 trak looking for
9598 * the SMI and gama atoms.
9601 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9602 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9604 const guint8 *_gamma = NULL;
9605 GstBuffer *_seqh = NULL;
9606 const guint8 *stsd_data = stsd_entry_data;
9607 guint32 length = QT_UINT32 (stsd_data);
9611 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9617 version = QT_UINT16 (stsd_data);
9622 while (length > 8) {
9623 guint32 fourcc, size;
9625 size = QT_UINT32 (stsd_data);
9626 fourcc = QT_FOURCC (stsd_data + 4);
9627 data = stsd_data + 8;
9630 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9631 "svq3 atom parsing");
9640 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9641 " for gama atom, expected 12", size);
9646 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9648 if (_seqh != NULL) {
9649 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9650 " found, ignoring");
9652 seqh_size = QT_UINT32 (data + 4);
9653 if (seqh_size > 0) {
9654 _seqh = gst_buffer_new_and_alloc (seqh_size);
9655 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9662 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9663 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9667 if (size <= length) {
9673 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9676 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9677 G_GUINT16_FORMAT, version);
9688 gst_buffer_unref (_seqh);
9693 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9700 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9701 * atom that might contain a 'data' atom with the rtsp uri.
9702 * This case was reported in bug #597497, some info about
9703 * the hndl atom can be found in TN1195
9705 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9706 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9709 guint32 dref_num_entries = 0;
9710 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9711 gst_byte_reader_skip (&dref, 4) &&
9712 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9715 /* search dref entries for hndl atom */
9716 for (i = 0; i < dref_num_entries; i++) {
9717 guint32 size = 0, type;
9718 guint8 string_len = 0;
9719 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9720 qt_atom_parser_get_fourcc (&dref, &type)) {
9721 if (type == FOURCC_hndl) {
9722 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9724 /* skip data reference handle bytes and the
9725 * following pascal string and some extra 4
9726 * bytes I have no idea what are */
9727 if (!gst_byte_reader_skip (&dref, 4) ||
9728 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9729 !gst_byte_reader_skip (&dref, string_len + 4)) {
9730 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9734 /* iterate over the atoms to find the data atom */
9735 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9739 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9740 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9741 if (atom_type == FOURCC_data) {
9742 const guint8 *uri_aux = NULL;
9744 /* found the data atom that might contain the rtsp uri */
9745 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9746 "hndl atom, interpreting it as an URI");
9747 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9749 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9750 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9752 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9753 "didn't contain a rtsp address");
9755 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9760 /* skipping to the next entry */
9761 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9764 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9771 /* skip to the next entry */
9772 if (!gst_byte_reader_skip (&dref, size - 8))
9775 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9778 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9784 #define AMR_NB_ALL_MODES 0x81ff
9785 #define AMR_WB_ALL_MODES 0x83ff
9787 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9789 /* The 'damr' atom is of the form:
9791 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9792 * 32 b 8 b 16 b 8 b 8 b
9794 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9795 * represents the highest mode used in the stream (and thus the maximum
9796 * bitrate), with a couple of special cases as seen below.
9799 /* Map of frame type ID -> bitrate */
9800 static const guint nb_bitrates[] = {
9801 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9803 static const guint wb_bitrates[] = {
9804 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9810 gst_buffer_map (buf, &map, GST_MAP_READ);
9812 if (map.size != 0x11) {
9813 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9817 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9818 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9819 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9823 mode_set = QT_UINT16 (map.data + 13);
9825 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9826 max_mode = 7 + (wb ? 1 : 0);
9828 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9829 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9831 if (max_mode == -1) {
9832 GST_DEBUG ("No mode indication was found (mode set) = %x",
9837 gst_buffer_unmap (buf, &map);
9838 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9841 gst_buffer_unmap (buf, &map);
9846 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9847 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9850 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9856 if (gst_byte_reader_get_remaining (reader) < 36)
9859 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9860 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9861 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9862 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9863 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9864 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9865 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9866 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9867 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9869 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9870 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9871 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9873 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9874 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9876 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9877 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9884 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9885 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9892 * This macro will only compare value abdegh, it expects cfi to have already
9895 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9896 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9898 /* only handle the cases where the last column has standard values */
9899 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9900 const gchar *rotation_tag = NULL;
9902 /* no rotation needed */
9903 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9905 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9906 rotation_tag = "rotate-90";
9907 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9908 rotation_tag = "rotate-180";
9909 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9910 rotation_tag = "rotate-270";
9912 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9915 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9917 if (rotation_tag != NULL) {
9918 if (*taglist == NULL)
9919 *taglist = gst_tag_list_new_empty ();
9920 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9921 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9924 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9928 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9929 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9930 * Common Encryption (cenc), the function will also parse the tenc box (defined
9931 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9932 * (typically an enc[v|a|t|s] sample entry); the function will set
9933 * @original_fmt to the fourcc of the original unencrypted stream format.
9934 * Returns TRUE if successful; FALSE otherwise. */
9936 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9937 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9944 g_return_val_if_fail (qtdemux != NULL, FALSE);
9945 g_return_val_if_fail (stream != NULL, FALSE);
9946 g_return_val_if_fail (container != NULL, FALSE);
9947 g_return_val_if_fail (original_fmt != NULL, FALSE);
9949 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9950 if (G_UNLIKELY (!sinf)) {
9951 if (stream->protection_scheme_type == FOURCC_cenc) {
9952 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9953 "mandatory for Common Encryption");
9959 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9960 if (G_UNLIKELY (!frma)) {
9961 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9965 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9966 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9967 GST_FOURCC_ARGS (*original_fmt));
9969 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9971 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9974 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9975 stream->protection_scheme_version =
9976 QT_UINT32 ((const guint8 *) schm->data + 16);
9978 GST_DEBUG_OBJECT (qtdemux,
9979 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9980 "protection_scheme_version: %#010x",
9981 GST_FOURCC_ARGS (stream->protection_scheme_type),
9982 stream->protection_scheme_version);
9984 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9986 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9989 if (stream->protection_scheme_type == FOURCC_cenc) {
9990 QtDemuxCencSampleSetInfo *info;
9992 const guint8 *tenc_data;
9993 guint32 isEncrypted;
9995 const guint8 *default_kid;
9998 if (G_UNLIKELY (!stream->protection_scheme_info))
9999 stream->protection_scheme_info =
10000 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10002 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10004 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10006 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10007 "which is mandatory for Common Encryption");
10010 tenc_data = (const guint8 *) tenc->data + 12;
10011 isEncrypted = QT_UINT24 (tenc_data);
10012 iv_size = QT_UINT8 (tenc_data + 3);
10013 default_kid = (tenc_data + 4);
10014 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
10015 gst_buffer_fill (kid_buf, 0, default_kid, 16);
10016 if (info->default_properties)
10017 gst_structure_free (info->default_properties);
10018 info->default_properties =
10019 gst_structure_new ("application/x-cenc",
10020 "iv_size", G_TYPE_UINT, iv_size,
10021 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
10022 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
10023 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
10024 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
10025 gst_buffer_unref (kid_buf);
10031 qtdemux_track_id_compare_func (QtDemuxStream * stream1, QtDemuxStream * stream2)
10033 return (gint) stream1->track_id - (gint) stream2->track_id;
10036 /* parse the traks.
10037 * With each track we associate a new QtDemuxStream that contains all the info
10039 * traks that do not decode to something (like strm traks) will not have a pad.
10042 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10044 GstByteReader tkhd;
10059 QtDemuxStream *stream = NULL;
10060 const guint8 *stsd_data;
10061 const guint8 *stsd_entry_data;
10062 guint remaining_stsd_len;
10063 guint stsd_entry_count;
10065 guint16 lang_code; /* quicktime lang code or packed iso code */
10067 guint32 tkhd_flags = 0;
10068 guint8 tkhd_version = 0;
10069 guint32 w = 0, h = 0;
10070 guint value_size, stsd_len, len;
10074 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10076 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10077 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10078 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10081 /* pick between 64 or 32 bits */
10082 value_size = tkhd_version == 1 ? 8 : 4;
10083 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10084 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10087 /* Check if current moov has duplicated track_id */
10088 if (qtdemux_find_stream (qtdemux, track_id))
10089 goto existing_stream;
10091 stream = _create_stream (qtdemux, track_id);
10092 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10094 /* need defaults for fragments */
10095 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10097 if ((tkhd_flags & 1) == 0)
10098 stream->disabled = TRUE;
10100 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10101 tkhd_version, tkhd_flags, stream->track_id);
10103 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10106 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10107 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10108 if (qtdemux->major_brand != FOURCC_mjp2 ||
10109 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10113 len = QT_UINT32 ((guint8 *) mdhd->data);
10114 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10115 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10116 if (version == 0x01000000) {
10119 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10120 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10121 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10125 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10126 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10127 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10130 if (lang_code < 0x400) {
10131 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10132 } else if (lang_code == 0x7fff) {
10133 stream->lang_id[0] = 0; /* unspecified */
10135 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10136 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10137 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10138 stream->lang_id[3] = 0;
10141 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10142 stream->timescale);
10143 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10145 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10146 lang_code, stream->lang_id);
10148 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10151 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10152 /* chapters track reference */
10153 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10155 gsize length = GST_READ_UINT32_BE (chap->data);
10156 if (qtdemux->chapters_track_id)
10157 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10159 if (length >= 12) {
10160 qtdemux->chapters_track_id =
10161 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10166 /* fragmented files may have bogus duration in moov */
10167 if (!qtdemux->fragmented &&
10168 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10169 guint64 tdur1, tdur2;
10171 /* don't overflow */
10172 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10173 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10176 * some of those trailers, nowadays, have prologue images that are
10177 * themselves video tracks as well. I haven't really found a way to
10178 * identify those yet, except for just looking at their duration. */
10179 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10180 GST_WARNING_OBJECT (qtdemux,
10181 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10182 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10183 "found, assuming preview image or something; skipping track",
10184 stream->duration, stream->timescale, qtdemux->duration,
10185 qtdemux->timescale);
10186 gst_qtdemux_stream_free (stream);
10191 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10194 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10195 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10197 len = QT_UINT32 ((guint8 *) hdlr->data);
10199 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10200 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10201 GST_FOURCC_ARGS (stream->subtype));
10203 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10206 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10209 /*parse svmi header if existing */
10210 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10212 len = QT_UINT32 ((guint8 *) svmi->data);
10213 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10215 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10216 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10217 guint8 frame_type, frame_layout;
10219 /* MPEG-A stereo video */
10220 if (qtdemux->major_brand == FOURCC_ss02)
10221 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10223 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10224 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10225 switch (frame_type) {
10227 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10230 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10233 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10236 /* mode 3 is primary/secondary view sequence, ie
10237 * left/right views in separate tracks. See section 7.2
10238 * of ISO/IEC 23000-11:2009 */
10239 GST_FIXME_OBJECT (qtdemux,
10240 "Implement stereo video in separate streams");
10243 if ((frame_layout & 0x1) == 0)
10244 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10246 GST_LOG_OBJECT (qtdemux,
10247 "StereoVideo: composition type: %u, is_left_first: %u",
10248 frame_type, frame_layout);
10249 stream->multiview_mode = mode;
10250 stream->multiview_flags = flags;
10254 /* parse rest of tkhd */
10255 if (stream->subtype == FOURCC_vide) {
10258 /* version 1 uses some 64-bit ints */
10259 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10262 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10265 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10266 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10269 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10270 &stream->stream_tags);
10274 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10276 stsd_data = (const guint8 *) stsd->data;
10278 /* stsd should at least have one entry */
10279 stsd_len = QT_UINT32 (stsd_data);
10280 if (stsd_len < 24) {
10281 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10282 if (stream->subtype == FOURCC_vivo) {
10283 gst_qtdemux_stream_free (stream);
10290 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10291 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10292 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10293 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10295 stsd_entry_data = stsd_data + 16;
10296 remaining_stsd_len = stsd_len - 16;
10297 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10299 gchar *codec = NULL;
10300 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10302 /* and that entry should fit within stsd */
10303 len = QT_UINT32 (stsd_entry_data);
10304 if (len > remaining_stsd_len)
10307 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10308 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10309 GST_FOURCC_ARGS (entry->fourcc));
10310 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10312 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10313 goto error_encrypted;
10315 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10316 /* FIXME this looks wrong, there might be multiple children
10317 * with the same type */
10318 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10319 stream->protected = TRUE;
10320 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10321 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10324 if (stream->subtype == FOURCC_vide) {
10329 gint depth, palette_size, palette_count;
10330 guint32 *palette_data = NULL;
10332 entry->sampled = TRUE;
10334 stream->display_width = w >> 16;
10335 stream->display_height = h >> 16;
10338 if (len < 86) /* TODO verify */
10341 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10342 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10343 entry->fps_n = 0; /* this is filled in later */
10344 entry->fps_d = 0; /* this is filled in later */
10345 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10346 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10348 /* if color_table_id is 0, ctab atom must follow; however some files
10349 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10350 * if color table is not present we'll correct the value */
10351 if (entry->color_table_id == 0 &&
10353 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10354 entry->color_table_id = -1;
10357 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10358 entry->width, entry->height, entry->bits_per_sample,
10359 entry->color_table_id);
10361 depth = entry->bits_per_sample;
10363 /* more than 32 bits means grayscale */
10364 gray = (depth > 32);
10365 /* low 32 bits specify the depth */
10368 /* different number of palette entries is determined by depth. */
10370 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10371 palette_count = (1 << depth);
10372 palette_size = palette_count * 4;
10374 if (entry->color_table_id) {
10375 switch (palette_count) {
10379 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10382 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10387 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10389 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10394 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10396 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10399 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10400 (_("The video in this file might not play correctly.")),
10401 ("unsupported palette depth %d", depth));
10405 gint i, j, start, end;
10411 start = QT_UINT32 (stsd_entry_data + offset + 70);
10412 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10413 end = QT_UINT16 (stsd_entry_data + offset + 76);
10415 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10416 start, end, palette_count);
10423 if (len < 94 + (end - start) * 8)
10426 /* palette is always the same size */
10427 palette_data = g_malloc0 (256 * 4);
10428 palette_size = 256 * 4;
10430 for (j = 0, i = start; i <= end; j++, i++) {
10431 guint32 a, r, g, b;
10433 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10434 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10435 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10436 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10438 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10439 (g & 0xff00) | (b >> 8);
10444 gst_caps_unref (entry->caps);
10447 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10449 if (G_UNLIKELY (!entry->caps)) {
10450 g_free (palette_data);
10451 goto unknown_stream;
10455 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10456 GST_TAG_VIDEO_CODEC, codec, NULL);
10461 if (palette_data) {
10464 if (entry->rgb8_palette)
10465 gst_memory_unref (entry->rgb8_palette);
10466 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10467 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10469 s = gst_caps_get_structure (entry->caps, 0);
10471 /* non-raw video has a palette_data property. raw video has the palette as
10472 * an extra plane that we append to the output buffers before we push
10474 if (!gst_structure_has_name (s, "video/x-raw")) {
10475 GstBuffer *palette;
10477 palette = gst_buffer_new ();
10478 gst_buffer_append_memory (palette, entry->rgb8_palette);
10479 entry->rgb8_palette = NULL;
10481 gst_caps_set_simple (entry->caps, "palette_data",
10482 GST_TYPE_BUFFER, palette, NULL);
10483 gst_buffer_unref (palette);
10485 } else if (palette_count != 0) {
10486 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10487 (NULL), ("Unsupported palette depth %d", depth));
10490 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10491 QT_UINT16 (stsd_entry_data + offset + 32));
10497 /* pick 'the' stsd child */
10498 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10499 if (!stream->protected) {
10500 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10504 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10510 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10511 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10512 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10513 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10517 const guint8 *pasp_data = (const guint8 *) pasp->data;
10518 gint len = QT_UINT32 (pasp_data);
10521 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10522 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10524 CUR_STREAM (stream)->par_w = 0;
10525 CUR_STREAM (stream)->par_h = 0;
10528 CUR_STREAM (stream)->par_w = 0;
10529 CUR_STREAM (stream)->par_h = 0;
10533 const guint8 *fiel_data = (const guint8 *) fiel->data;
10534 gint len = QT_UINT32 (fiel_data);
10537 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10538 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10543 const guint8 *colr_data = (const guint8 *) colr->data;
10544 gint len = QT_UINT32 (colr_data);
10546 if (len == 19 || len == 18) {
10547 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10549 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10550 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10551 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10552 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10553 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10555 switch (primaries) {
10557 CUR_STREAM (stream)->colorimetry.primaries =
10558 GST_VIDEO_COLOR_PRIMARIES_BT709;
10561 CUR_STREAM (stream)->colorimetry.primaries =
10562 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10565 CUR_STREAM (stream)->colorimetry.primaries =
10566 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10569 CUR_STREAM (stream)->colorimetry.primaries =
10570 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10576 switch (transfer_function) {
10578 CUR_STREAM (stream)->colorimetry.transfer =
10579 GST_VIDEO_TRANSFER_BT709;
10582 CUR_STREAM (stream)->colorimetry.transfer =
10583 GST_VIDEO_TRANSFER_SMPTE240M;
10591 CUR_STREAM (stream)->colorimetry.matrix =
10592 GST_VIDEO_COLOR_MATRIX_BT709;
10595 CUR_STREAM (stream)->colorimetry.matrix =
10596 GST_VIDEO_COLOR_MATRIX_BT601;
10599 CUR_STREAM (stream)->colorimetry.matrix =
10600 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10603 CUR_STREAM (stream)->colorimetry.matrix =
10604 GST_VIDEO_COLOR_MATRIX_BT2020;
10610 CUR_STREAM (stream)->colorimetry.range =
10611 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10612 GST_VIDEO_COLOR_RANGE_16_235;
10614 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10617 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10622 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10623 stream->stream_tags);
10630 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10631 const guint8 *avc_data = stsd_entry_data + 0x56;
10634 while (len >= 0x8) {
10637 if (QT_UINT32 (avc_data) <= len)
10638 size = QT_UINT32 (avc_data) - 0x8;
10643 /* No real data, so break out */
10646 switch (QT_FOURCC (avc_data + 0x4)) {
10649 /* parse, if found */
10652 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10654 /* First 4 bytes are the length of the atom, the next 4 bytes
10655 * are the fourcc, the next 1 byte is the version, and the
10656 * subsequent bytes are profile_tier_level structure like data. */
10657 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10658 avc_data + 8 + 1, size - 1);
10659 buf = gst_buffer_new_and_alloc (size);
10660 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10661 gst_caps_set_simple (entry->caps,
10662 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10663 gst_buffer_unref (buf);
10671 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10673 /* First 4 bytes are the length of the atom, the next 4 bytes
10674 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10675 * next 1 byte is the version, and the
10676 * subsequent bytes are sequence parameter set like data. */
10678 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10680 gst_codec_utils_h264_caps_set_level_and_profile
10681 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10683 buf = gst_buffer_new_and_alloc (size);
10684 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10685 gst_caps_set_simple (entry->caps,
10686 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10687 gst_buffer_unref (buf);
10693 guint avg_bitrate, max_bitrate;
10695 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10699 max_bitrate = QT_UINT32 (avc_data + 0xc);
10700 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10702 if (!max_bitrate && !avg_bitrate)
10705 /* Some muxers seem to swap the average and maximum bitrates
10706 * (I'm looking at you, YouTube), so we swap for sanity. */
10707 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10708 guint temp = avg_bitrate;
10710 avg_bitrate = max_bitrate;
10711 max_bitrate = temp;
10714 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10715 gst_tag_list_add (stream->stream_tags,
10716 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10717 max_bitrate, NULL);
10719 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10720 gst_tag_list_add (stream->stream_tags,
10721 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10733 avc_data += size + 8;
10742 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10743 const guint8 *hevc_data = stsd_entry_data + 0x56;
10746 while (len >= 0x8) {
10749 if (QT_UINT32 (hevc_data) <= len)
10750 size = QT_UINT32 (hevc_data) - 0x8;
10755 /* No real data, so break out */
10758 switch (QT_FOURCC (hevc_data + 0x4)) {
10761 /* parse, if found */
10764 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10766 /* First 4 bytes are the length of the atom, the next 4 bytes
10767 * are the fourcc, the next 1 byte is the version, and the
10768 * subsequent bytes are sequence parameter set like data. */
10769 gst_codec_utils_h265_caps_set_level_tier_and_profile
10770 (entry->caps, hevc_data + 8 + 1, size - 1);
10772 buf = gst_buffer_new_and_alloc (size);
10773 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10774 gst_caps_set_simple (entry->caps,
10775 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10776 gst_buffer_unref (buf);
10783 hevc_data += size + 8;
10796 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10797 GST_FOURCC_ARGS (fourcc));
10799 /* codec data might be in glbl extension atom */
10801 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10807 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10809 len = QT_UINT32 (data);
10812 buf = gst_buffer_new_and_alloc (len);
10813 gst_buffer_fill (buf, 0, data + 8, len);
10814 gst_caps_set_simple (entry->caps,
10815 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10816 gst_buffer_unref (buf);
10823 /* see annex I of the jpeg2000 spec */
10824 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10825 const guint8 *data;
10826 const gchar *colorspace = NULL;
10828 guint32 ncomp_map = 0;
10829 gint32 *comp_map = NULL;
10830 guint32 nchan_def = 0;
10831 gint32 *chan_def = NULL;
10833 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10834 /* some required atoms */
10835 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10838 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10842 /* number of components; redundant with info in codestream, but useful
10844 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10845 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10847 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10849 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10852 GST_DEBUG_OBJECT (qtdemux, "found colr");
10853 /* extract colour space info */
10854 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10855 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10857 colorspace = "sRGB";
10860 colorspace = "GRAY";
10863 colorspace = "sYUV";
10871 /* colr is required, and only values 16, 17, and 18 are specified,
10872 so error if we have no colorspace */
10875 /* extract component mapping */
10876 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10878 guint32 cmap_len = 0;
10880 cmap_len = QT_UINT32 (cmap->data);
10881 if (cmap_len >= 8) {
10882 /* normal box, subtract off header */
10884 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10885 if (cmap_len % 4 == 0) {
10886 ncomp_map = (cmap_len / 4);
10887 comp_map = g_new0 (gint32, ncomp_map);
10888 for (i = 0; i < ncomp_map; i++) {
10891 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10892 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10893 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10894 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10899 /* extract channel definitions */
10900 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10902 guint32 cdef_len = 0;
10904 cdef_len = QT_UINT32 (cdef->data);
10905 if (cdef_len >= 10) {
10906 /* normal box, subtract off header and len */
10908 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10909 if (cdef_len % 6 == 0) {
10910 nchan_def = (cdef_len / 6);
10911 chan_def = g_new0 (gint32, nchan_def);
10912 for (i = 0; i < nchan_def; i++)
10914 for (i = 0; i < nchan_def; i++) {
10915 guint16 cn, typ, asoc;
10916 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10917 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10918 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10919 if (cn < nchan_def) {
10922 chan_def[cn] = asoc;
10925 chan_def[cn] = 0; /* alpha */
10928 chan_def[cn] = -typ;
10936 gst_caps_set_simple (entry->caps,
10937 "num-components", G_TYPE_INT, ncomp, NULL);
10938 gst_caps_set_simple (entry->caps,
10939 "colorspace", G_TYPE_STRING, colorspace, NULL);
10942 GValue arr = { 0, };
10943 GValue elt = { 0, };
10945 g_value_init (&arr, GST_TYPE_ARRAY);
10946 g_value_init (&elt, G_TYPE_INT);
10947 for (i = 0; i < ncomp_map; i++) {
10948 g_value_set_int (&elt, comp_map[i]);
10949 gst_value_array_append_value (&arr, &elt);
10951 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10952 "component-map", &arr);
10953 g_value_unset (&elt);
10954 g_value_unset (&arr);
10959 GValue arr = { 0, };
10960 GValue elt = { 0, };
10962 g_value_init (&arr, GST_TYPE_ARRAY);
10963 g_value_init (&elt, G_TYPE_INT);
10964 for (i = 0; i < nchan_def; i++) {
10965 g_value_set_int (&elt, chan_def[i]);
10966 gst_value_array_append_value (&arr, &elt);
10968 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10969 "channel-definitions", &arr);
10970 g_value_unset (&elt);
10971 g_value_unset (&arr);
10975 /* some optional atoms */
10976 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10977 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10979 /* indicate possible fields in caps */
10981 data = (guint8 *) field->data + 8;
10983 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10984 (gint) * data, NULL);
10986 /* add codec_data if provided */
10991 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10992 data = prefix->data;
10993 len = QT_UINT32 (data);
10996 buf = gst_buffer_new_and_alloc (len);
10997 gst_buffer_fill (buf, 0, data + 8, len);
10998 gst_caps_set_simple (entry->caps,
10999 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11000 gst_buffer_unref (buf);
11009 GstBuffer *seqh = NULL;
11010 const guint8 *gamma_data = NULL;
11011 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11013 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11016 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11017 QT_FP32 (gamma_data), NULL);
11020 /* sorry for the bad name, but we don't know what this is, other
11021 * than its own fourcc */
11022 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11024 gst_buffer_unref (seqh);
11027 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11028 buf = gst_buffer_new_and_alloc (len);
11029 gst_buffer_fill (buf, 0, stsd_data, len);
11030 gst_caps_set_simple (entry->caps,
11031 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11032 gst_buffer_unref (buf);
11037 /* https://developer.apple.com/standards/qtff-2001.pdf,
11038 * page 92, "Video Sample Description", under table 3.1 */
11041 const gint compressor_offset =
11042 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11043 const gint min_size = compressor_offset + 32 + 2 + 2;
11046 guint16 color_table_id = 0;
11049 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11051 /* recover information on interlaced/progressive */
11052 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11056 len = QT_UINT32 (jpeg->data);
11057 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11059 if (len >= min_size) {
11060 gst_byte_reader_init (&br, jpeg->data, len);
11062 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11063 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11064 if (color_table_id != 0) {
11065 /* the spec says there can be concatenated chunks in the data, and we want
11066 * to find one called field. Walk through them. */
11067 gint offset = min_size;
11068 while (offset + 8 < len) {
11069 guint32 size = 0, tag;
11070 ok = gst_byte_reader_get_uint32_le (&br, &size);
11071 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11072 if (!ok || size < 8) {
11073 GST_WARNING_OBJECT (qtdemux,
11074 "Failed to walk optional chunk list");
11077 GST_DEBUG_OBJECT (qtdemux,
11078 "Found optional %4.4s chunk, size %u",
11079 (const char *) &tag, size);
11080 if (tag == FOURCC_fiel) {
11081 guint8 n_fields = 0, ordering = 0;
11082 gst_byte_reader_get_uint8 (&br, &n_fields);
11083 gst_byte_reader_get_uint8 (&br, &ordering);
11084 if (n_fields == 1 || n_fields == 2) {
11085 GST_DEBUG_OBJECT (qtdemux,
11086 "Found fiel tag with %u fields, ordering %u",
11087 n_fields, ordering);
11089 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11090 "interlace-mode", G_TYPE_STRING, "interleaved",
11093 GST_WARNING_OBJECT (qtdemux,
11094 "Found fiel tag with invalid fields (%u)", n_fields);
11100 GST_DEBUG_OBJECT (qtdemux,
11101 "Color table ID is 0, not trying to get interlacedness");
11104 GST_WARNING_OBJECT (qtdemux,
11105 "Length of jpeg chunk is too small, not trying to get interlacedness");
11113 gst_caps_set_simple (entry->caps,
11114 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11120 GNode *xith, *xdxt;
11122 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11123 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11127 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11131 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11132 /* collect the headers and store them in a stream list so that we can
11133 * send them out first */
11134 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11144 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11145 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11148 ovc1_data = ovc1->data;
11149 ovc1_len = QT_UINT32 (ovc1_data);
11150 if (ovc1_len <= 198) {
11151 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11154 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11155 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11156 gst_caps_set_simple (entry->caps,
11157 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11158 gst_buffer_unref (buf);
11163 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11164 const guint8 *vc1_data = stsd_entry_data + 0x56;
11170 if (QT_UINT32 (vc1_data) <= len)
11171 size = QT_UINT32 (vc1_data) - 8;
11176 /* No real data, so break out */
11179 switch (QT_FOURCC (vc1_data + 0x4)) {
11180 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11184 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11185 buf = gst_buffer_new_and_alloc (size);
11186 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11187 gst_caps_set_simple (entry->caps,
11188 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11189 gst_buffer_unref (buf);
11196 vc1_data += size + 8;
11202 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11203 const guint8 *av1_data = stsd_entry_data + 0x56;
11206 while (len >= 0x8) {
11209 if (QT_UINT32 (av1_data) <= len)
11210 size = QT_UINT32 (av1_data) - 0x8;
11215 /* No real data, so break out */
11218 switch (QT_FOURCC (av1_data + 0x4)) {
11221 /* parse, if found */
11223 guint8 pres_delay_field;
11225 GST_DEBUG_OBJECT (qtdemux,
11226 "found av1C codec_data in stsd of size %d", size);
11228 /* not enough data, just ignore and hope for the best */
11233 * 4 bytes: atom length
11238 * 1 bits: initial_presentation_delay_present
11239 * 4 bits: initial_presentation_delay (if present else reserved
11243 if (av1_data[9] != 0) {
11244 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11248 /* We skip initial_presentation_delay* for now */
11249 pres_delay_field = *(av1_data + 12);
11250 if (pres_delay_field & (1 << 5)) {
11251 gst_caps_set_simple (entry->caps,
11252 "presentation-delay", G_TYPE_INT,
11253 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11256 buf = gst_buffer_new_and_alloc (size - 5);
11257 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11258 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11259 gst_caps_set_simple (entry->caps,
11260 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11261 gst_buffer_unref (buf);
11270 av1_data += size + 8;
11280 GST_INFO_OBJECT (qtdemux,
11281 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11282 GST_FOURCC_ARGS (fourcc), entry->caps);
11284 } else if (stream->subtype == FOURCC_soun) {
11286 int version, samplesize;
11287 guint16 compression_id;
11288 gboolean amrwb = FALSE;
11291 /* sample description entry (16) + sound sample description v0 (20) */
11295 version = QT_UINT32 (stsd_entry_data + offset);
11296 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11297 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11298 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11299 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11301 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11302 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11303 QT_UINT32 (stsd_entry_data + offset + 4));
11304 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11305 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11306 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11307 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11308 QT_UINT16 (stsd_entry_data + offset + 14));
11309 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11311 if (compression_id == 0xfffe)
11312 entry->sampled = TRUE;
11314 /* first assume uncompressed audio */
11315 entry->bytes_per_sample = samplesize / 8;
11316 entry->samples_per_frame = entry->n_channels;
11317 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11318 entry->samples_per_packet = entry->samples_per_frame;
11319 entry->bytes_per_packet = entry->bytes_per_sample;
11323 /* Yes, these have to be hard-coded */
11326 entry->samples_per_packet = 6;
11327 entry->bytes_per_packet = 1;
11328 entry->bytes_per_frame = 1 * entry->n_channels;
11329 entry->bytes_per_sample = 1;
11330 entry->samples_per_frame = 6 * entry->n_channels;
11335 entry->samples_per_packet = 3;
11336 entry->bytes_per_packet = 1;
11337 entry->bytes_per_frame = 1 * entry->n_channels;
11338 entry->bytes_per_sample = 1;
11339 entry->samples_per_frame = 3 * entry->n_channels;
11344 entry->samples_per_packet = 64;
11345 entry->bytes_per_packet = 34;
11346 entry->bytes_per_frame = 34 * entry->n_channels;
11347 entry->bytes_per_sample = 2;
11348 entry->samples_per_frame = 64 * entry->n_channels;
11354 entry->samples_per_packet = 1;
11355 entry->bytes_per_packet = 1;
11356 entry->bytes_per_frame = 1 * entry->n_channels;
11357 entry->bytes_per_sample = 1;
11358 entry->samples_per_frame = 1 * entry->n_channels;
11363 entry->samples_per_packet = 160;
11364 entry->bytes_per_packet = 33;
11365 entry->bytes_per_frame = 33 * entry->n_channels;
11366 entry->bytes_per_sample = 2;
11367 entry->samples_per_frame = 160 * entry->n_channels;
11374 if (version == 0x00010000) {
11375 /* sample description entry (16) + sound sample description v1 (20+16) */
11387 /* only parse extra decoding config for non-pcm audio */
11388 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11389 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11390 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11391 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11393 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11394 entry->samples_per_packet);
11395 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11396 entry->bytes_per_packet);
11397 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11398 entry->bytes_per_frame);
11399 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11400 entry->bytes_per_sample);
11402 if (!entry->sampled && entry->bytes_per_packet) {
11403 entry->samples_per_frame = (entry->bytes_per_frame /
11404 entry->bytes_per_packet) * entry->samples_per_packet;
11405 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11406 entry->samples_per_frame);
11411 } else if (version == 0x00020000) {
11418 /* sample description entry (16) + sound sample description v2 (56) */
11422 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11423 entry->rate = qtfp.fp;
11424 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11426 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11427 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11428 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11429 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11430 QT_UINT32 (stsd_entry_data + offset + 20));
11431 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11432 QT_UINT32 (stsd_entry_data + offset + 24));
11433 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11434 QT_UINT32 (stsd_entry_data + offset + 28));
11435 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11436 QT_UINT32 (stsd_entry_data + offset + 32));
11437 } else if (version != 0x00000) {
11438 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11443 gst_caps_unref (entry->caps);
11445 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11446 stsd_entry_data + 32, len - 16, &codec);
11454 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11456 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11458 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11460 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11463 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11464 gst_caps_set_simple (entry->caps,
11465 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11472 const guint8 *owma_data;
11473 const gchar *codec_name = NULL;
11477 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11478 /* FIXME this should also be gst_riff_strf_auds,
11479 * but the latter one is actually missing bits-per-sample :( */
11484 gint32 nSamplesPerSec;
11485 gint32 nAvgBytesPerSec;
11486 gint16 nBlockAlign;
11487 gint16 wBitsPerSample;
11490 WAVEFORMATEX *wfex;
11492 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11493 owma_data = stsd_entry_data;
11494 owma_len = QT_UINT32 (owma_data);
11495 if (owma_len <= 54) {
11496 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11499 wfex = (WAVEFORMATEX *) (owma_data + 36);
11500 buf = gst_buffer_new_and_alloc (owma_len - 54);
11501 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11502 if (wfex->wFormatTag == 0x0161) {
11503 codec_name = "Windows Media Audio";
11505 } else if (wfex->wFormatTag == 0x0162) {
11506 codec_name = "Windows Media Audio 9 Pro";
11508 } else if (wfex->wFormatTag == 0x0163) {
11509 codec_name = "Windows Media Audio 9 Lossless";
11510 /* is that correct? gstffmpegcodecmap.c is missing it, but
11511 * fluendo codec seems to support it */
11515 gst_caps_set_simple (entry->caps,
11516 "codec_data", GST_TYPE_BUFFER, buf,
11517 "wmaversion", G_TYPE_INT, version,
11518 "block_align", G_TYPE_INT,
11519 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11520 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11521 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11522 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11523 gst_buffer_unref (buf);
11527 codec = g_strdup (codec_name);
11533 gint len = QT_UINT32 (stsd_entry_data) - offset;
11534 const guint8 *wfex_data = stsd_entry_data + offset;
11535 const gchar *codec_name = NULL;
11537 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11538 /* FIXME this should also be gst_riff_strf_auds,
11539 * but the latter one is actually missing bits-per-sample :( */
11544 gint32 nSamplesPerSec;
11545 gint32 nAvgBytesPerSec;
11546 gint16 nBlockAlign;
11547 gint16 wBitsPerSample;
11552 /* FIXME: unify with similar wavformatex parsing code above */
11553 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11559 if (QT_UINT32 (wfex_data) <= len)
11560 size = QT_UINT32 (wfex_data) - 8;
11565 /* No real data, so break out */
11568 switch (QT_FOURCC (wfex_data + 4)) {
11569 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11571 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11576 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11577 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11578 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11579 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11580 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11581 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11582 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11584 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11585 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11586 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11587 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11588 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11589 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11591 if (wfex.wFormatTag == 0x0161) {
11592 codec_name = "Windows Media Audio";
11594 } else if (wfex.wFormatTag == 0x0162) {
11595 codec_name = "Windows Media Audio 9 Pro";
11597 } else if (wfex.wFormatTag == 0x0163) {
11598 codec_name = "Windows Media Audio 9 Lossless";
11599 /* is that correct? gstffmpegcodecmap.c is missing it, but
11600 * fluendo codec seems to support it */
11604 gst_caps_set_simple (entry->caps,
11605 "wmaversion", G_TYPE_INT, version,
11606 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11607 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11608 "width", G_TYPE_INT, wfex.wBitsPerSample,
11609 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11611 if (size > wfex.cbSize) {
11614 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11615 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11616 size - wfex.cbSize);
11617 gst_caps_set_simple (entry->caps,
11618 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11619 gst_buffer_unref (buf);
11621 GST_WARNING_OBJECT (qtdemux, "no codec data");
11626 codec = g_strdup (codec_name);
11634 wfex_data += size + 8;
11640 const guint8 *opus_data;
11641 guint8 *channel_mapping = NULL;
11644 guint8 channel_mapping_family;
11645 guint8 stream_count;
11646 guint8 coupled_count;
11649 opus_data = stsd_entry_data;
11651 channels = GST_READ_UINT8 (opus_data + 45);
11652 rate = GST_READ_UINT32_LE (opus_data + 48);
11653 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11654 stream_count = GST_READ_UINT8 (opus_data + 55);
11655 coupled_count = GST_READ_UINT8 (opus_data + 56);
11657 if (channels > 0) {
11658 channel_mapping = g_malloc (channels * sizeof (guint8));
11659 for (i = 0; i < channels; i++)
11660 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11663 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11664 channel_mapping_family, stream_count, coupled_count,
11676 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11677 GST_TAG_AUDIO_CODEC, codec, NULL);
11681 /* some bitrate info may have ended up in caps */
11682 s = gst_caps_get_structure (entry->caps, 0);
11683 gst_structure_get_int (s, "bitrate", &bitrate);
11685 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11686 GST_TAG_BITRATE, bitrate, NULL);
11689 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11690 if (!stream->protected) {
11692 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11696 if (stream->protected && fourcc == FOURCC_mp4a) {
11697 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11701 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11709 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11711 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11713 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11717 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11718 16 bits is a byte-swapped wave-style codec identifier,
11719 and we can find a WAVE header internally to a 'wave' atom here.
11720 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11721 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11724 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11725 if (len < offset + 20) {
11726 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11728 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11729 const guint8 *data = stsd_entry_data + offset + 16;
11731 GNode *waveheadernode;
11733 wavenode = g_node_new ((guint8 *) data);
11734 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11735 const guint8 *waveheader;
11738 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11739 if (waveheadernode) {
11740 waveheader = (const guint8 *) waveheadernode->data;
11741 headerlen = QT_UINT32 (waveheader);
11743 if (headerlen > 8) {
11744 gst_riff_strf_auds *header = NULL;
11745 GstBuffer *headerbuf;
11751 headerbuf = gst_buffer_new_and_alloc (headerlen);
11752 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11754 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11755 headerbuf, &header, &extra)) {
11756 gst_caps_unref (entry->caps);
11757 /* FIXME: Need to do something with the channel reorder map */
11759 gst_riff_create_audio_caps (header->format, NULL, header,
11760 extra, NULL, NULL, NULL);
11763 gst_buffer_unref (extra);
11768 GST_DEBUG ("Didn't find waveheadernode for this codec");
11770 g_node_destroy (wavenode);
11773 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11774 stream->stream_tags);
11778 /* FIXME: what is in the chunk? */
11781 gint len = QT_UINT32 (stsd_data);
11783 /* seems to be always = 116 = 0x74 */
11789 gint len = QT_UINT32 (stsd_entry_data);
11792 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11794 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11795 gst_caps_set_simple (entry->caps,
11796 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11797 gst_buffer_unref (buf);
11799 gst_caps_set_simple (entry->caps,
11800 "samplesize", G_TYPE_INT, samplesize, NULL);
11805 GNode *alac, *wave = NULL;
11807 /* apparently, m4a has this atom appended directly in the stsd entry,
11808 * while mov has it in a wave atom */
11809 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11811 /* alac now refers to stsd entry atom */
11812 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11814 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11816 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11819 const guint8 *alac_data = alac->data;
11820 gint len = QT_UINT32 (alac->data);
11824 GST_DEBUG_OBJECT (qtdemux,
11825 "discarding alac atom with unexpected len %d", len);
11827 /* codec-data contains alac atom size and prefix,
11828 * ffmpeg likes it that way, not quite gst-ish though ...*/
11829 buf = gst_buffer_new_and_alloc (len);
11830 gst_buffer_fill (buf, 0, alac->data, len);
11831 gst_caps_set_simple (entry->caps,
11832 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11833 gst_buffer_unref (buf);
11835 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11836 entry->n_channels = QT_UINT8 (alac_data + 21);
11837 entry->rate = QT_UINT32 (alac_data + 32);
11840 gst_caps_set_simple (entry->caps,
11841 "samplesize", G_TYPE_INT, samplesize, NULL);
11846 /* The codingname of the sample entry is 'fLaC' */
11847 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11850 /* The 'dfLa' box is added to the sample entry to convey
11851 initializing information for the decoder. */
11852 const GNode *dfla =
11853 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11856 const guint32 len = QT_UINT32 (dfla->data);
11858 /* Must contain at least dfLa box header (12),
11859 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11861 GST_DEBUG_OBJECT (qtdemux,
11862 "discarding dfla atom with unexpected len %d", len);
11864 /* skip dfLa header to get the METADATA_BLOCKs */
11865 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11866 const guint32 metadata_blocks_len = len - 12;
11868 gchar *stream_marker = g_strdup ("fLaC");
11869 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11870 strlen (stream_marker));
11873 guint32 remainder = 0;
11874 guint32 block_size = 0;
11875 gboolean is_last = FALSE;
11877 GValue array = G_VALUE_INIT;
11878 GValue value = G_VALUE_INIT;
11880 g_value_init (&array, GST_TYPE_ARRAY);
11881 g_value_init (&value, GST_TYPE_BUFFER);
11883 gst_value_set_buffer (&value, block);
11884 gst_value_array_append_value (&array, &value);
11885 g_value_reset (&value);
11887 gst_buffer_unref (block);
11889 /* check there's at least one METADATA_BLOCK_HEADER's worth
11890 * of data, and we haven't already finished parsing */
11891 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11892 remainder = metadata_blocks_len - index;
11894 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11896 (metadata_blocks[index + 1] << 16) +
11897 (metadata_blocks[index + 2] << 8) +
11898 metadata_blocks[index + 3];
11900 /* be careful not to read off end of box */
11901 if (block_size > remainder) {
11905 is_last = metadata_blocks[index] >> 7;
11907 block = gst_buffer_new_and_alloc (block_size);
11909 gst_buffer_fill (block, 0, &metadata_blocks[index],
11912 gst_value_set_buffer (&value, block);
11913 gst_value_array_append_value (&array, &value);
11914 g_value_reset (&value);
11916 gst_buffer_unref (block);
11918 index += block_size;
11921 /* only append the metadata if we successfully read all of it */
11923 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11924 (stream)->caps, 0), "streamheader", &array);
11926 GST_WARNING_OBJECT (qtdemux,
11927 "discarding all METADATA_BLOCKs due to invalid "
11928 "block_size %d at idx %d, rem %d", block_size, index,
11932 g_value_unset (&value);
11933 g_value_unset (&array);
11935 /* The sample rate obtained from the stsd may not be accurate
11936 * since it cannot represent rates greater than 65535Hz, so
11937 * override that value with the sample rate from the
11938 * METADATA_BLOCK_STREAMINFO block */
11939 CUR_STREAM (stream)->rate =
11940 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11951 gint len = QT_UINT32 (stsd_entry_data);
11954 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11957 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11959 /* If we have enough data, let's try to get the 'damr' atom. See
11960 * the 3GPP container spec (26.244) for more details. */
11961 if ((len - 0x34) > 8 &&
11962 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11963 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11964 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11967 gst_caps_set_simple (entry->caps,
11968 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11969 gst_buffer_unref (buf);
11975 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11976 gint len = QT_UINT32 (stsd_entry_data);
11979 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11981 if (sound_version == 1) {
11982 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11983 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11984 guint8 codec_data[2];
11986 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11988 gint sample_rate_index =
11989 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11991 /* build AAC codec data */
11992 codec_data[0] = profile << 3;
11993 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11994 codec_data[1] = (sample_rate_index & 0x01) << 7;
11995 codec_data[1] |= (channels & 0xF) << 3;
11997 buf = gst_buffer_new_and_alloc (2);
11998 gst_buffer_fill (buf, 0, codec_data, 2);
11999 gst_caps_set_simple (entry->caps,
12000 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12001 gst_buffer_unref (buf);
12007 /* Fully handled elsewhere */
12010 GST_INFO_OBJECT (qtdemux,
12011 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12015 GST_INFO_OBJECT (qtdemux,
12016 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12017 GST_FOURCC_ARGS (fourcc), entry->caps);
12019 } else if (stream->subtype == FOURCC_strm) {
12020 if (fourcc == FOURCC_rtsp) {
12021 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12023 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12024 GST_FOURCC_ARGS (fourcc));
12025 goto unknown_stream;
12027 entry->sampled = TRUE;
12028 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12029 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12030 || stream->subtype == FOURCC_clcp) {
12032 entry->sampled = TRUE;
12033 entry->sparse = TRUE;
12036 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12039 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12040 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12045 /* hunt for sort-of codec data */
12049 GNode *mp4s = NULL;
12050 GNode *esds = NULL;
12052 /* look for palette in a stsd->mp4s->esds sub-atom */
12053 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12055 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12056 if (esds == NULL) {
12058 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12062 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12063 stream->stream_tags);
12067 GST_INFO_OBJECT (qtdemux,
12068 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12071 GST_INFO_OBJECT (qtdemux,
12072 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12073 GST_FOURCC_ARGS (fourcc), entry->caps);
12075 /* everything in 1 sample */
12076 entry->sampled = TRUE;
12079 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12082 if (entry->caps == NULL)
12083 goto unknown_stream;
12086 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12087 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12093 /* promote to sampled format */
12094 if (entry->fourcc == FOURCC_samr) {
12095 /* force mono 8000 Hz for AMR */
12096 entry->sampled = TRUE;
12097 entry->n_channels = 1;
12098 entry->rate = 8000;
12099 } else if (entry->fourcc == FOURCC_sawb) {
12100 /* force mono 16000 Hz for AMR-WB */
12101 entry->sampled = TRUE;
12102 entry->n_channels = 1;
12103 entry->rate = 16000;
12104 } else if (entry->fourcc == FOURCC_mp4a) {
12105 entry->sampled = TRUE;
12109 stsd_entry_data += len;
12110 remaining_stsd_len -= len;
12114 /* collect sample information */
12115 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12116 goto samples_failed;
12118 if (qtdemux->fragmented) {
12121 /* need all moov samples as basis; probably not many if any at all */
12122 /* prevent moof parsing taking of at this time */
12123 offset = qtdemux->moof_offset;
12124 qtdemux->moof_offset = 0;
12125 if (stream->n_samples &&
12126 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12127 qtdemux->moof_offset = offset;
12128 goto samples_failed;
12130 qtdemux->moof_offset = 0;
12131 /* movie duration more reliable in this case (e.g. mehd) */
12132 if (qtdemux->segment.duration &&
12133 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12135 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12138 /* configure segments */
12139 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12140 goto segments_failed;
12142 /* add some language tag, if useful */
12143 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12144 strcmp (stream->lang_id, "und")) {
12145 const gchar *lang_code;
12147 /* convert ISO 639-2 code to ISO 639-1 */
12148 lang_code = gst_tag_get_language_code (stream->lang_id);
12149 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12150 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12153 /* Check for UDTA tags */
12154 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12155 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12158 /* Insert and sort new stream in track-id order.
12159 * This will help in comparing old/new streams during stream update check */
12160 qtdemux->active_streams =
12161 g_list_insert_sorted (qtdemux->active_streams, stream,
12162 (GCompareFunc) qtdemux_track_id_compare_func);
12163 qtdemux->n_streams++;
12164 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
12171 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12172 (_("This file is corrupt and cannot be played.")), (NULL));
12174 gst_qtdemux_stream_free (stream);
12179 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12180 gst_qtdemux_stream_free (stream);
12186 /* we posted an error already */
12187 /* free stbl sub-atoms */
12188 gst_qtdemux_stbl_free (stream);
12189 gst_qtdemux_stream_free (stream);
12194 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12200 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12201 GST_FOURCC_ARGS (stream->subtype));
12202 gst_qtdemux_stream_free (stream);
12207 /* If we can estimate the overall bitrate, and don't have information about the
12208 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12209 * the overall bitrate minus the sum of the bitrates of all other streams. This
12210 * should be useful for the common case where we have one audio and one video
12211 * stream and can estimate the bitrate of one, but not the other. */
12213 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12215 QtDemuxStream *stream = NULL;
12216 gint64 size, sys_bitrate, sum_bitrate = 0;
12217 GstClockTime duration;
12221 if (qtdemux->fragmented)
12224 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12226 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12228 GST_DEBUG_OBJECT (qtdemux,
12229 "Size in bytes of the stream not known - bailing");
12233 /* Subtract the header size */
12234 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12235 size, qtdemux->header_size);
12237 if (size < qtdemux->header_size)
12240 size = size - qtdemux->header_size;
12242 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12243 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12247 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12248 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
12249 switch (str->subtype) {
12252 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12253 CUR_STREAM (str)->caps);
12254 /* retrieve bitrate, prefer avg then max */
12256 if (str->stream_tags) {
12257 if (gst_tag_list_get_uint (str->stream_tags,
12258 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12259 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12260 if (gst_tag_list_get_uint (str->stream_tags,
12261 GST_TAG_NOMINAL_BITRATE, &bitrate))
12262 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12263 if (gst_tag_list_get_uint (str->stream_tags,
12264 GST_TAG_BITRATE, &bitrate))
12265 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12268 sum_bitrate += bitrate;
12271 GST_DEBUG_OBJECT (qtdemux,
12272 ">1 stream with unknown bitrate - bailing");
12279 /* For other subtypes, we assume no significant impact on bitrate */
12285 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12289 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12291 if (sys_bitrate < sum_bitrate) {
12292 /* This can happen, since sum_bitrate might be derived from maximum
12293 * bitrates and not average bitrates */
12294 GST_DEBUG_OBJECT (qtdemux,
12295 "System bitrate less than sum bitrate - bailing");
12299 bitrate = sys_bitrate - sum_bitrate;
12300 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12301 ", Stream bitrate = %u", sys_bitrate, bitrate);
12303 if (!stream->stream_tags)
12304 stream->stream_tags = gst_tag_list_new_empty ();
12306 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12308 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12309 GST_TAG_BITRATE, bitrate, NULL);
12312 static GstFlowReturn
12313 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12315 GstFlowReturn ret = GST_FLOW_OK;
12316 GList *iter, *next;
12318 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12320 for (iter = qtdemux->active_streams; ret == GST_FLOW_OK && iter; iter = next) {
12321 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12322 guint32 sample_num = 0;
12326 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12327 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12329 if (qtdemux->fragmented) {
12330 /* need all moov samples first */
12331 GST_OBJECT_LOCK (qtdemux);
12332 while (stream->n_samples == 0)
12333 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12335 GST_OBJECT_UNLOCK (qtdemux);
12337 /* discard any stray moof */
12338 qtdemux->moof_offset = 0;
12341 /* prepare braking */
12342 if (ret != GST_FLOW_ERROR)
12345 /* in pull mode, we should have parsed some sample info by now;
12346 * and quite some code will not handle no samples.
12347 * in push mode, we'll just have to deal with it */
12348 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12349 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12350 gst_qtdemux_remove_stream (qtdemux, stream);
12352 } else if (stream->track_id == qtdemux->chapters_track_id &&
12353 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12354 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12355 so that it doesn't look like a subtitle track */
12356 gst_qtdemux_remove_stream (qtdemux, stream);
12360 /* parse the initial sample for use in setting the frame rate cap */
12361 while (sample_num == 0 && sample_num < stream->n_samples) {
12362 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12372 _stream_in_list (GList * list, QtDemuxStream * stream)
12376 for (iter = list; iter; iter = g_list_next (iter)) {
12377 QtDemuxStream *tmp = QTDEMUX_STREAM (iter->data);
12378 if (!g_strcmp0 (tmp->stream_id, stream->stream_id))
12386 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12390 if (!qtdemux->active_streams)
12393 /* streams in list are sorted in track-id order */
12394 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12395 new = g_list_next (new), old = g_list_next (old)) {
12397 /* Different stream-id, updated */
12398 if (g_strcmp0 (QTDEMUX_STREAM (new->data)->stream_id,
12399 QTDEMUX_STREAM (old->data)->stream_id))
12403 /* Different length, updated */
12404 if (new != NULL || old != NULL)
12411 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12412 QtDemuxStream * oldstream, QtDemuxStream * newstream)
12414 /* Connect old stream's srcpad to new stream */
12415 newstream->pad = oldstream->pad;
12416 oldstream->pad = NULL;
12418 /* unset new_stream to prevent stream-start event */
12419 newstream->new_stream = FALSE;
12421 return gst_qtdemux_configure_stream (qtdemux, newstream);
12425 qtdemux_update_streams (GstQTDemux * qtdemux)
12427 GList *iter, *next;
12428 g_assert (qtdemux->streams_aware);
12430 /* At below, figure out which stream in active_streams has identical stream-id
12431 * with that of in old_streams. If there is matching stream-id,
12432 * corresponding newstream will not be exposed again,
12433 * but demux will reuse srcpad of matched old stream
12435 * active_streams : newly created streams from the latest moov
12436 * old_streams : existing streams (belong to previous moov)
12439 /* Count n_streams again */
12440 qtdemux->n_streams = 0;
12442 for (iter = qtdemux->active_streams; iter; iter = next) {
12444 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12448 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12449 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12451 qtdemux->n_streams++;
12453 if ((tmp = _stream_in_list (qtdemux->old_streams, stream)) != NULL
12454 && QTDEMUX_STREAM (tmp->data)->pad) {
12455 QtDemuxStream *oldstream = QTDEMUX_STREAM (tmp->data);
12457 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12459 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12462 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, oldstream);
12463 gst_qtdemux_stream_free (oldstream);
12467 /* now we have all info and can expose */
12468 list = stream->stream_tags;
12469 stream->stream_tags = NULL;
12470 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12478 /* Must be called with expose lock */
12479 static GstFlowReturn
12480 qtdemux_expose_streams (GstQTDemux * qtdemux)
12482 GList *iter, *next;
12484 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12486 if (!qtdemux_is_streams_update (qtdemux)) {
12489 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12490 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12491 new = g_list_next (new), old = g_list_next (old)) {
12492 if (!qtdemux_reuse_and_configure_stream (qtdemux,
12493 QTDEMUX_STREAM (old->data), QTDEMUX_STREAM (new->data)))
12494 return GST_FLOW_ERROR;
12497 g_list_free_full (qtdemux->old_streams,
12498 (GDestroyNotify) gst_qtdemux_stream_free);
12499 qtdemux->old_streams = NULL;
12501 return GST_FLOW_OK;
12504 if (qtdemux->streams_aware) {
12505 if (!qtdemux_update_streams (qtdemux))
12506 return GST_FLOW_ERROR;
12508 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12509 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12512 /* now we have all info and can expose */
12513 list = stream->stream_tags;
12514 stream->stream_tags = NULL;
12515 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12516 return GST_FLOW_ERROR;
12521 gst_qtdemux_guess_bitrate (qtdemux);
12523 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12525 /* If we have still old_streams, it's no more used stream */
12526 for (iter = qtdemux->old_streams; iter; iter = next) {
12527 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12528 next = g_list_next (iter);
12533 event = gst_event_new_eos ();
12534 if (qtdemux->segment_seqnum)
12535 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12537 gst_pad_push_event (stream->pad, event);
12540 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, stream);
12541 gst_qtdemux_stream_free (stream);
12544 /* check if we should post a redirect in case there is a single trak
12545 * and it is a redirecting trak */
12546 if (qtdemux->n_streams == 1 &&
12547 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri != NULL) {
12550 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12551 "an external content");
12552 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12553 gst_structure_new ("redirect",
12554 "new-location", G_TYPE_STRING,
12555 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri, NULL));
12556 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12557 qtdemux->posted_redirect = TRUE;
12560 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12561 qtdemux_do_allocation (qtdemux, QTDEMUX_STREAM (iter->data));
12564 qtdemux->need_segment = TRUE;
12566 qtdemux->exposed = TRUE;
12567 return GST_FLOW_OK;
12570 /* check if major or compatible brand is 3GP */
12571 static inline gboolean
12572 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12575 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12577 } else if (qtdemux->comp_brands != NULL) {
12581 gboolean res = FALSE;
12583 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12586 while (size >= 4) {
12587 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12592 gst_buffer_unmap (qtdemux->comp_brands, &map);
12599 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12600 static inline gboolean
12601 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12603 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12604 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12605 || fourcc == FOURCC_albm;
12609 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12610 const char *tag, const char *dummy, GNode * node)
12612 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12616 gdouble longitude, latitude, altitude;
12619 len = QT_UINT32 (node->data);
12626 /* TODO: language code skipped */
12628 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12631 /* do not alarm in trivial case, but bail out otherwise */
12632 if (*(data + offset) != 0) {
12633 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12637 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12638 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12639 offset += strlen (name);
12643 if (len < offset + 2 + 4 + 4 + 4)
12646 /* +1 +1 = skip null-terminator and location role byte */
12648 /* table in spec says unsigned, semantics say negative has meaning ... */
12649 longitude = QT_SFP32 (data + offset);
12652 latitude = QT_SFP32 (data + offset);
12655 altitude = QT_SFP32 (data + offset);
12657 /* one invalid means all are invalid */
12658 if (longitude >= -180.0 && longitude <= 180.0 &&
12659 latitude >= -90.0 && latitude <= 90.0) {
12660 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12661 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12662 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12663 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12666 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12673 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12680 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12681 const char *tag, const char *dummy, GNode * node)
12687 len = QT_UINT32 (node->data);
12691 y = QT_UINT16 ((guint8 *) node->data + 12);
12693 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12696 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12698 date = g_date_new_dmy (1, 1, y);
12699 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12700 g_date_free (date);
12704 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12705 const char *tag, const char *dummy, GNode * node)
12708 char *tag_str = NULL;
12713 len = QT_UINT32 (node->data);
12718 entity = (guint8 *) node->data + offset;
12719 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12720 GST_DEBUG_OBJECT (qtdemux,
12721 "classification info: %c%c%c%c invalid classification entity",
12722 entity[0], entity[1], entity[2], entity[3]);
12727 table = QT_UINT16 ((guint8 *) node->data + offset);
12729 /* Language code skipped */
12733 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12734 * XXXX: classification entity, fixed length 4 chars.
12735 * Y[YYYY]: classification table, max 5 chars.
12737 tag_str = g_strdup_printf ("----://%u/%s",
12738 table, (char *) node->data + offset);
12740 /* memcpy To be sure we're preserving byte order */
12741 memcpy (tag_str, entity, 4);
12742 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12744 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12753 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12759 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12760 const char *tag, const char *dummy, GNode * node)
12762 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12768 gboolean ret = TRUE;
12769 const gchar *charset = NULL;
12771 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12773 len = QT_UINT32 (data->data);
12774 type = QT_UINT32 ((guint8 *) data->data + 8);
12775 if (type == 0x00000001 && len > 16) {
12776 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12779 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12780 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12783 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12787 len = QT_UINT32 (node->data);
12788 type = QT_UINT32 ((guint8 *) node->data + 4);
12789 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12793 /* Type starts with the (C) symbol, so the next data is a list
12794 * of (string size(16), language code(16), string) */
12796 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12797 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12799 /* the string + fourcc + size + 2 16bit fields,
12800 * means that there are more tags in this atom */
12801 if (len > str_len + 8 + 4) {
12802 /* TODO how to represent the same tag in different languages? */
12803 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12804 "text alternatives, reading only first one");
12808 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12809 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12811 if (lang_code < 0x800) { /* MAC encoded string */
12814 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12815 QT_FOURCC ((guint8 *) node->data + 4))) {
12816 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12818 /* we go for 3GP style encoding if major brands claims so,
12819 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12820 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12821 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12822 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12824 /* 16-bit Language code is ignored here as well */
12825 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12832 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12833 ret = FALSE; /* may have to fallback */
12836 GError *err = NULL;
12838 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12839 charset, NULL, NULL, &err);
12841 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12842 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12844 g_error_free (err);
12847 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12848 len - offset, env_vars);
12851 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12852 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12856 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12863 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12864 const char *tag, const char *dummy, GNode * node)
12866 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12870 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12871 const char *tag, const char *dummy, GNode * node)
12873 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12875 char *s, *t, *k = NULL;
12880 /* first try normal string tag if major brand not 3GP */
12881 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12882 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12883 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12884 * let's try it 3gpp way after minor safety check */
12886 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12892 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12896 len = QT_UINT32 (data);
12900 count = QT_UINT8 (data + 14);
12902 for (; count; count--) {
12905 if (offset + 1 > len)
12907 slen = QT_UINT8 (data + offset);
12909 if (offset + slen > len)
12911 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12914 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12916 t = g_strjoin (",", k, s, NULL);
12924 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12931 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12932 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12941 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12947 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12948 const char *tag1, const char *tag2, GNode * node)
12955 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12957 len = QT_UINT32 (data->data);
12958 type = QT_UINT32 ((guint8 *) data->data + 8);
12959 if (type == 0x00000000 && len >= 22) {
12960 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12961 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12963 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12964 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12967 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12968 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12975 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12976 const char *tag1, const char *dummy, GNode * node)
12983 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12985 len = QT_UINT32 (data->data);
12986 type = QT_UINT32 ((guint8 *) data->data + 8);
12987 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12988 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12989 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12990 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12992 /* do not add bpm=0 */
12993 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12994 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13002 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13003 const char *tag1, const char *dummy, GNode * node)
13010 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13012 len = QT_UINT32 (data->data);
13013 type = QT_UINT32 ((guint8 *) data->data + 8);
13014 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13015 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13016 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13017 num = QT_UINT32 ((guint8 *) data->data + 16);
13019 /* do not add num=0 */
13020 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13021 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13028 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13029 const char *tag1, const char *dummy, GNode * node)
13036 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13038 len = QT_UINT32 (data->data);
13039 type = QT_UINT32 ((guint8 *) data->data + 8);
13040 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13041 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13042 GstTagImageType image_type;
13044 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13045 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13047 image_type = GST_TAG_IMAGE_TYPE_NONE;
13050 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13051 len - 16, image_type))) {
13052 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13053 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13054 gst_sample_unref (sample);
13061 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
13062 const char *tag, const char *dummy, GNode * node)
13065 GstDateTime *datetime = NULL;
13070 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13072 len = QT_UINT32 (data->data);
13073 type = QT_UINT32 ((guint8 *) data->data + 8);
13074 if (type == 0x00000001 && len > 16) {
13075 guint y, m = 1, d = 1;
13078 s = g_strndup ((char *) data->data + 16, len - 16);
13079 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13080 datetime = gst_date_time_new_from_iso8601_string (s);
13081 if (datetime != NULL) {
13082 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13084 gst_date_time_unref (datetime);
13087 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13088 if (ret >= 1 && y > 1500 && y < 3000) {
13091 date = g_date_new_dmy (d, m, y);
13092 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13093 g_date_free (date);
13095 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13103 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13104 const char *tag, const char *dummy, GNode * node)
13108 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13110 /* re-route to normal string tag if major brand says so
13111 * or no data atom and compatible brand suggests so */
13112 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13113 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13114 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13119 guint len, type, n;
13121 len = QT_UINT32 (data->data);
13122 type = QT_UINT32 ((guint8 *) data->data + 8);
13123 if (type == 0x00000000 && len >= 18) {
13124 n = QT_UINT16 ((guint8 *) data->data + 16);
13126 const gchar *genre;
13128 genre = gst_tag_id3_genre_get (n - 1);
13129 if (genre != NULL) {
13130 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13131 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13139 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13140 const gchar * tag, guint8 * data, guint32 datasize)
13145 /* make a copy to have \0 at the end */
13146 datacopy = g_strndup ((gchar *) data, datasize);
13148 /* convert the str to double */
13149 if (sscanf (datacopy, "%lf", &value) == 1) {
13150 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13151 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13153 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13161 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13162 const char *tag, const char *tag_bis, GNode * node)
13171 const gchar *meanstr;
13172 const gchar *namestr;
13174 /* checking the whole ---- atom size for consistency */
13175 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13176 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13180 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13182 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13186 meansize = QT_UINT32 (mean->data);
13187 if (meansize <= 12) {
13188 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13191 meanstr = ((gchar *) mean->data) + 12;
13194 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13196 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13200 namesize = QT_UINT32 (name->data);
13201 if (namesize <= 12) {
13202 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13205 namestr = ((gchar *) name->data) + 12;
13213 * uint24 - data type
13217 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13219 GST_WARNING_OBJECT (demux, "No data atom in this tag");
13222 datasize = QT_UINT32 (data->data);
13223 if (datasize <= 16) {
13224 GST_WARNING_OBJECT (demux, "Data atom too small");
13227 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13229 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13230 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13231 static const struct
13233 const gchar name[28];
13234 const gchar tag[28];
13237 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13238 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13239 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13240 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13241 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13242 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13243 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13244 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13248 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13249 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13250 switch (gst_tag_get_type (tags[i].tag)) {
13251 case G_TYPE_DOUBLE:
13252 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13253 ((guint8 *) data->data) + 16, datasize - 16);
13255 case G_TYPE_STRING:
13256 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13265 if (i == G_N_ELEMENTS (tags))
13275 #ifndef GST_DISABLE_GST_DEBUG
13277 gchar *namestr_dbg;
13278 gchar *meanstr_dbg;
13280 meanstr_dbg = g_strndup (meanstr, meansize);
13281 namestr_dbg = g_strndup (namestr, namesize);
13283 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13284 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13286 g_free (namestr_dbg);
13287 g_free (meanstr_dbg);
13294 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13295 const char *tag_bis, GNode * node)
13300 GstTagList *id32_taglist = NULL;
13302 GST_LOG_OBJECT (demux, "parsing ID32");
13305 len = GST_READ_UINT32_BE (data);
13307 /* need at least full box and language tag */
13311 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13312 gst_buffer_fill (buf, 0, data + 14, len - 14);
13314 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13315 if (id32_taglist) {
13316 GST_LOG_OBJECT (demux, "parsing ok");
13317 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13318 gst_tag_list_unref (id32_taglist);
13320 GST_LOG_OBJECT (demux, "parsing failed");
13323 gst_buffer_unref (buf);
13326 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13327 const char *tag, const char *tag_bis, GNode * node);
13330 FOURCC_pcst -> if media is a podcast -> bool
13331 FOURCC_cpil -> if media is part of a compilation -> bool
13332 FOURCC_pgap -> if media is part of a gapless context -> bool
13333 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13336 static const struct
13339 const gchar *gst_tag;
13340 const gchar *gst_tag_bis;
13341 const GstQTDemuxAddTagFunc func;
13344 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13345 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13346 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13347 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13348 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13349 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13350 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13351 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13352 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13353 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13354 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13355 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13356 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13357 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13358 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13359 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13360 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13361 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13362 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13363 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13364 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13365 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13366 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13367 qtdemux_tag_add_num}, {
13368 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13369 qtdemux_tag_add_num}, {
13370 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13371 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13372 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13373 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13374 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13375 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13376 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13377 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13378 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13379 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13380 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13381 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13382 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13383 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13384 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13385 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13386 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13387 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13388 qtdemux_tag_add_classification}, {
13389 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13390 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13391 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13393 /* This is a special case, some tags are stored in this
13394 * 'reverse dns naming', according to:
13395 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13398 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13399 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13400 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13403 struct _GstQtDemuxTagList
13406 GstTagList *taglist;
13408 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13411 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13417 const gchar *style;
13422 GstQTDemux *demux = qtdemuxtaglist->demux;
13423 GstTagList *taglist = qtdemuxtaglist->taglist;
13426 len = QT_UINT32 (data);
13427 buf = gst_buffer_new_and_alloc (len);
13428 gst_buffer_fill (buf, 0, data, len);
13430 /* heuristic to determine style of tag */
13431 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13432 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13434 else if (demux->major_brand == FOURCC_qt__)
13435 style = "quicktime";
13436 /* fall back to assuming iso/3gp tag style */
13440 /* santize the name for the caps. */
13441 for (i = 0; i < 4; i++) {
13442 guint8 d = data[4 + i];
13443 if (g_ascii_isalnum (d))
13444 ndata[i] = g_ascii_tolower (d);
13449 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13450 ndata[0], ndata[1], ndata[2], ndata[3]);
13451 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13453 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13454 sample = gst_sample_new (buf, NULL, NULL, s);
13455 gst_buffer_unref (buf);
13456 g_free (media_type);
13458 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13461 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13462 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13464 gst_sample_unref (sample);
13468 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13475 GstQtDemuxTagList demuxtaglist;
13477 demuxtaglist.demux = qtdemux;
13478 demuxtaglist.taglist = taglist;
13480 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13481 if (meta != NULL) {
13482 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13483 if (ilst == NULL) {
13484 GST_LOG_OBJECT (qtdemux, "no ilst");
13489 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13493 while (i < G_N_ELEMENTS (add_funcs)) {
13494 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13498 len = QT_UINT32 (node->data);
13500 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13501 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13503 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13504 add_funcs[i].gst_tag_bis, node);
13506 g_node_destroy (node);
13512 /* parsed nodes have been removed, pass along remainder as blob */
13513 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13514 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13516 /* parse up XMP_ node if existing */
13517 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13518 if (xmp_ != NULL) {
13520 GstTagList *xmptaglist;
13522 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13523 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13524 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13525 gst_buffer_unref (buf);
13527 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13529 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13535 GstStructure *structure; /* helper for sort function */
13537 guint min_req_bitrate;
13538 guint min_req_qt_version;
13542 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13544 GstQtReference *ref_a = (GstQtReference *) a;
13545 GstQtReference *ref_b = (GstQtReference *) b;
13547 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13548 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13550 /* known bitrates go before unknown; higher bitrates go first */
13551 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13554 /* sort the redirects and post a message for the application.
13557 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13559 GstQtReference *best;
13562 GValue list_val = { 0, };
13565 g_assert (references != NULL);
13567 references = g_list_sort (references, qtdemux_redirects_sort_func);
13569 best = (GstQtReference *) references->data;
13571 g_value_init (&list_val, GST_TYPE_LIST);
13573 for (l = references; l != NULL; l = l->next) {
13574 GstQtReference *ref = (GstQtReference *) l->data;
13575 GValue struct_val = { 0, };
13577 ref->structure = gst_structure_new ("redirect",
13578 "new-location", G_TYPE_STRING, ref->location, NULL);
13580 if (ref->min_req_bitrate > 0) {
13581 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13582 ref->min_req_bitrate, NULL);
13585 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13586 g_value_set_boxed (&struct_val, ref->structure);
13587 gst_value_list_append_value (&list_val, &struct_val);
13588 g_value_unset (&struct_val);
13589 /* don't free anything here yet, since we need best->structure below */
13592 g_assert (best != NULL);
13593 s = gst_structure_copy (best->structure);
13595 if (g_list_length (references) > 1) {
13596 gst_structure_set_value (s, "locations", &list_val);
13599 g_value_unset (&list_val);
13601 for (l = references; l != NULL; l = l->next) {
13602 GstQtReference *ref = (GstQtReference *) l->data;
13604 gst_structure_free (ref->structure);
13605 g_free (ref->location);
13608 g_list_free (references);
13610 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13611 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13612 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13613 qtdemux->posted_redirect = TRUE;
13616 /* look for redirect nodes, collect all redirect information and
13620 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13622 GNode *rmra, *rmda, *rdrf;
13624 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13626 GList *redirects = NULL;
13628 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13630 GstQtReference ref = { NULL, NULL, 0, 0 };
13631 GNode *rmdr, *rmvc;
13633 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13634 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13635 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13636 ref.min_req_bitrate);
13639 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13640 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13641 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13643 #ifndef GST_DISABLE_GST_DEBUG
13644 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13646 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13648 GST_LOG_OBJECT (qtdemux,
13649 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13650 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13651 bitmask, check_type);
13652 if (package == FOURCC_qtim && check_type == 0) {
13653 ref.min_req_qt_version = version;
13657 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13663 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13664 if (ref_len > 20) {
13665 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13666 ref_data = (guint8 *) rdrf->data + 20;
13667 if (ref_type == FOURCC_alis) {
13668 guint record_len, record_version, fn_len;
13670 if (ref_len > 70) {
13671 /* MacOSX alias record, google for alias-layout.txt */
13672 record_len = QT_UINT16 (ref_data + 4);
13673 record_version = QT_UINT16 (ref_data + 4 + 2);
13674 fn_len = QT_UINT8 (ref_data + 50);
13675 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13676 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13679 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13682 } else if (ref_type == FOURCC_url_) {
13683 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13685 GST_DEBUG_OBJECT (qtdemux,
13686 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13687 GST_FOURCC_ARGS (ref_type));
13689 if (ref.location != NULL) {
13690 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13692 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13694 GST_WARNING_OBJECT (qtdemux,
13695 "Failed to extract redirect location from rdrf atom");
13698 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13702 /* look for others */
13703 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13706 if (redirects != NULL) {
13707 qtdemux_process_redirects (qtdemux, redirects);
13713 static GstTagList *
13714 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13718 if (tags == NULL) {
13719 tags = gst_tag_list_new_empty ();
13720 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13723 if (qtdemux->major_brand == FOURCC_mjp2)
13724 fmt = "Motion JPEG 2000";
13725 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13727 else if (qtdemux->major_brand == FOURCC_qt__)
13729 else if (qtdemux->fragmented)
13732 fmt = "ISO MP4/M4A";
13734 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13735 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13737 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13743 /* we have read the complete moov node now.
13744 * This function parses all of the relevant info, creates the traks and
13745 * prepares all data structures for playback
13748 qtdemux_parse_tree (GstQTDemux * qtdemux)
13755 guint64 creation_time;
13756 GstDateTime *datetime = NULL;
13759 /* make sure we have a usable taglist */
13760 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13762 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13763 if (mvhd == NULL) {
13764 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13765 return qtdemux_parse_redirects (qtdemux);
13768 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13769 if (version == 1) {
13770 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13771 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13772 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13773 } else if (version == 0) {
13774 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13775 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13776 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13778 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13782 /* Moving qt creation time (secs since 1904) to unix time */
13783 if (creation_time != 0) {
13784 /* Try to use epoch first as it should be faster and more commonly found */
13785 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13788 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13789 /* some data cleansing sanity */
13790 g_get_current_time (&now);
13791 if (now.tv_sec + 24 * 3600 < creation_time) {
13792 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13794 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13797 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13798 GDateTime *dt, *dt_local;
13800 dt = g_date_time_add_seconds (base_dt, creation_time);
13801 dt_local = g_date_time_to_local (dt);
13802 datetime = gst_date_time_new_from_g_date_time (dt_local);
13804 g_date_time_unref (base_dt);
13805 g_date_time_unref (dt);
13809 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13810 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13812 gst_date_time_unref (datetime);
13815 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13816 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13818 /* check for fragmented file and get some (default) data */
13819 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13822 GstByteReader mehd_data;
13824 /* let track parsing or anyone know weird stuff might happen ... */
13825 qtdemux->fragmented = TRUE;
13827 /* compensate for total duration */
13828 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13830 qtdemux_parse_mehd (qtdemux, &mehd_data);
13833 /* Update the movie segment duration, unless it was directly given to us
13834 * by upstream. Otherwise let it as is, as we don't want to mangle the
13835 * duration provided by upstream that may come e.g. from a MPD file. */
13836 if (!qtdemux->upstream_format_is_time) {
13837 GstClockTime duration;
13838 /* set duration in the segment info */
13839 gst_qtdemux_get_duration (qtdemux, &duration);
13840 qtdemux->segment.duration = duration;
13841 /* also do not exceed duration; stop is set that way post seek anyway,
13842 * and segment activation falls back to duration,
13843 * whereas loop only checks stop, so let's align this here as well */
13844 qtdemux->segment.stop = duration;
13847 /* parse all traks */
13848 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13850 qtdemux_parse_trak (qtdemux, trak);
13851 /* iterate all siblings */
13852 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13855 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13858 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13860 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13862 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13865 /* maybe also some tags in meta box */
13866 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13868 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13869 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13871 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13874 /* parse any protection system info */
13875 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13877 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13878 qtdemux_parse_pssh (qtdemux, pssh);
13879 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13882 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13887 /* taken from ffmpeg */
13889 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13901 len = (len << 7) | (c & 0x7f);
13910 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13911 gsize codec_data_size)
13913 GList *list = NULL;
13914 guint8 *p = codec_data;
13915 gint i, offset, num_packets;
13916 guint *length, last;
13918 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13920 if (codec_data == NULL || codec_data_size == 0)
13923 /* start of the stream and vorbis audio or theora video, need to
13924 * send the codec_priv data as first three packets */
13925 num_packets = p[0] + 1;
13926 GST_DEBUG_OBJECT (qtdemux,
13927 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13928 (guint) num_packets, codec_data_size);
13930 /* Let's put some limits, Don't think there even is a xiph codec
13931 * with more than 3-4 headers */
13932 if (G_UNLIKELY (num_packets > 16)) {
13933 GST_WARNING_OBJECT (qtdemux,
13934 "Unlikely number of xiph headers, most likely not valid");
13938 length = g_alloca (num_packets * sizeof (guint));
13942 /* first packets, read length values */
13943 for (i = 0; i < num_packets - 1; i++) {
13945 while (offset < codec_data_size) {
13946 length[i] += p[offset];
13947 if (p[offset++] != 0xff)
13952 if (offset + last > codec_data_size)
13955 /* last packet is the remaining size */
13956 length[i] = codec_data_size - offset - last;
13958 for (i = 0; i < num_packets; i++) {
13961 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13963 if (offset + length[i] > codec_data_size)
13966 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
13967 list = g_list_append (list, hdr);
13969 offset += length[i];
13978 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13984 /* this can change the codec originally present in @list */
13986 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13987 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13989 int len = QT_UINT32 (esds->data);
13990 guint8 *ptr = esds->data;
13991 guint8 *end = ptr + len;
13993 guint8 *data_ptr = NULL;
13995 guint8 object_type_id = 0;
13996 guint8 stream_type = 0;
13997 const char *codec_name = NULL;
13998 GstCaps *caps = NULL;
14000 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14002 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14004 while (ptr + 1 < end) {
14005 tag = QT_UINT8 (ptr);
14006 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14008 len = read_descr_size (ptr, end, &ptr);
14009 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14011 /* Check the stated amount of data is available for reading */
14012 if (len < 0 || ptr + len > end)
14016 case ES_DESCRIPTOR_TAG:
14017 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14018 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14021 case DECODER_CONFIG_DESC_TAG:{
14022 guint max_bitrate, avg_bitrate;
14024 object_type_id = QT_UINT8 (ptr);
14025 stream_type = QT_UINT8 (ptr + 1) >> 2;
14026 max_bitrate = QT_UINT32 (ptr + 5);
14027 avg_bitrate = QT_UINT32 (ptr + 9);
14028 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14029 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14030 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14031 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14032 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14033 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14034 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14035 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14037 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14038 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14039 avg_bitrate, NULL);
14044 case DECODER_SPECIFIC_INFO_TAG:
14045 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14046 if (object_type_id == 0xe0 && len == 0x40) {
14052 GST_DEBUG_OBJECT (qtdemux,
14053 "Have VOBSUB palette. Creating palette event");
14054 /* move to decConfigDescr data and read palette */
14056 for (i = 0; i < 16; i++) {
14057 clut[i] = QT_UINT32 (data);
14061 s = gst_structure_new ("application/x-gst-dvd", "event",
14062 G_TYPE_STRING, "dvd-spu-clut-change",
14063 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14064 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14065 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14066 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14067 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14068 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14069 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14070 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14073 /* store event and trigger custom processing */
14074 stream->pending_event =
14075 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14077 /* Generic codec_data handler puts it on the caps */
14084 case SL_CONFIG_DESC_TAG:
14085 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14089 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14091 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14097 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14098 * in use, and should also be used to override some other parameters for some
14100 switch (object_type_id) {
14101 case 0x20: /* MPEG-4 */
14102 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14103 * profile_and_level_indication */
14104 if (data_ptr != NULL && data_len >= 5 &&
14105 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14106 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14107 data_ptr + 4, data_len - 4);
14109 break; /* Nothing special needed here */
14110 case 0x21: /* H.264 */
14111 codec_name = "H.264 / AVC";
14112 caps = gst_caps_new_simple ("video/x-h264",
14113 "stream-format", G_TYPE_STRING, "avc",
14114 "alignment", G_TYPE_STRING, "au", NULL);
14116 case 0x40: /* AAC (any) */
14117 case 0x66: /* AAC Main */
14118 case 0x67: /* AAC LC */
14119 case 0x68: /* AAC SSR */
14120 /* Override channels and rate based on the codec_data, as it's often
14122 /* Only do so for basic setup without HE-AAC extension */
14123 if (data_ptr && data_len == 2) {
14124 guint channels, rate;
14126 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14128 entry->n_channels = channels;
14130 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14132 entry->rate = rate;
14135 /* Set level and profile if possible */
14136 if (data_ptr != NULL && data_len >= 2) {
14137 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14138 data_ptr, data_len);
14140 const gchar *profile_str = NULL;
14143 guint8 *codec_data;
14144 gint rate_idx, profile;
14146 /* No codec_data, let's invent something.
14147 * FIXME: This is wrong for SBR! */
14149 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14151 buffer = gst_buffer_new_and_alloc (2);
14152 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14153 codec_data = map.data;
14156 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14159 switch (object_type_id) {
14161 profile_str = "main";
14165 profile_str = "lc";
14169 profile_str = "ssr";
14177 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14179 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14181 gst_buffer_unmap (buffer, &map);
14182 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14183 GST_TYPE_BUFFER, buffer, NULL);
14184 gst_buffer_unref (buffer);
14187 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14188 G_TYPE_STRING, profile_str, NULL);
14192 case 0x60: /* MPEG-2, various profiles */
14198 codec_name = "MPEG-2 video";
14199 caps = gst_caps_new_simple ("video/mpeg",
14200 "mpegversion", G_TYPE_INT, 2,
14201 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14203 case 0x69: /* MPEG-2 BC audio */
14204 case 0x6B: /* MPEG-1 audio */
14205 caps = gst_caps_new_simple ("audio/mpeg",
14206 "mpegversion", G_TYPE_INT, 1, NULL);
14207 codec_name = "MPEG-1 audio";
14209 case 0x6A: /* MPEG-1 */
14210 codec_name = "MPEG-1 video";
14211 caps = gst_caps_new_simple ("video/mpeg",
14212 "mpegversion", G_TYPE_INT, 1,
14213 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14215 case 0x6C: /* MJPEG */
14217 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14219 codec_name = "Motion-JPEG";
14221 case 0x6D: /* PNG */
14223 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14225 codec_name = "PNG still images";
14227 case 0x6E: /* JPEG2000 */
14228 codec_name = "JPEG-2000";
14229 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14231 case 0xA4: /* Dirac */
14232 codec_name = "Dirac";
14233 caps = gst_caps_new_empty_simple ("video/x-dirac");
14235 case 0xA5: /* AC3 */
14236 codec_name = "AC-3 audio";
14237 caps = gst_caps_new_simple ("audio/x-ac3",
14238 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14240 case 0xA9: /* AC3 */
14241 codec_name = "DTS audio";
14242 caps = gst_caps_new_simple ("audio/x-dts",
14243 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14246 if (stream_type == 0x05 && data_ptr) {
14248 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14251 GValue arr_val = G_VALUE_INIT;
14252 GValue buf_val = G_VALUE_INIT;
14255 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14256 codec_name = "Vorbis";
14257 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14258 g_value_init (&arr_val, GST_TYPE_ARRAY);
14259 g_value_init (&buf_val, GST_TYPE_BUFFER);
14260 for (tmp = headers; tmp; tmp = tmp->next) {
14261 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14262 gst_value_array_append_value (&arr_val, &buf_val);
14264 s = gst_caps_get_structure (caps, 0);
14265 gst_structure_take_value (s, "streamheader", &arr_val);
14266 g_value_unset (&buf_val);
14267 g_list_free (headers);
14274 case 0xE1: /* QCELP */
14275 /* QCELP, the codec_data is a riff tag (little endian) with
14276 * 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). */
14277 caps = gst_caps_new_empty_simple ("audio/qcelp");
14278 codec_name = "QCELP";
14284 /* If we have a replacement caps, then change our caps for this stream */
14286 gst_caps_unref (entry->caps);
14287 entry->caps = caps;
14290 if (codec_name && list)
14291 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14292 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14294 /* Add the codec_data attribute to caps, if we have it */
14298 buffer = gst_buffer_new_and_alloc (data_len);
14299 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14301 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14302 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14304 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14306 gst_buffer_unref (buffer);
14311 static inline GstCaps *
14312 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14316 char *s, fourstr[5];
14318 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14319 for (i = 0; i < 4; i++) {
14320 if (!g_ascii_isalnum (fourstr[i]))
14323 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14324 caps = gst_caps_new_empty_simple (s);
14329 #define _codec(name) \
14331 if (codec_name) { \
14332 *codec_name = g_strdup (name); \
14337 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14338 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14339 const guint8 * stsd_entry_data, gchar ** codec_name)
14341 GstCaps *caps = NULL;
14342 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14346 _codec ("PNG still images");
14347 caps = gst_caps_new_empty_simple ("image/png");
14350 _codec ("JPEG still images");
14352 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14355 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14356 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14357 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14358 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14359 _codec ("Motion-JPEG");
14361 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14364 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14365 _codec ("Motion-JPEG format B");
14366 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14369 _codec ("JPEG-2000");
14370 /* override to what it should be according to spec, avoid palette_data */
14371 entry->bits_per_sample = 24;
14372 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14375 _codec ("Sorensen video v.3");
14376 caps = gst_caps_new_simple ("video/x-svq",
14377 "svqversion", G_TYPE_INT, 3, NULL);
14379 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14380 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14381 _codec ("Sorensen video v.1");
14382 caps = gst_caps_new_simple ("video/x-svq",
14383 "svqversion", G_TYPE_INT, 1, NULL);
14385 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14386 caps = gst_caps_new_empty_simple ("video/x-raw");
14387 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14388 _codec ("Windows Raw RGB");
14389 stream->alignment = 32;
14395 bps = QT_UINT16 (stsd_entry_data + 82);
14398 format = GST_VIDEO_FORMAT_RGB15;
14401 format = GST_VIDEO_FORMAT_RGB16;
14404 format = GST_VIDEO_FORMAT_RGB;
14407 format = GST_VIDEO_FORMAT_ARGB;
14415 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14416 format = GST_VIDEO_FORMAT_I420;
14418 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14419 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14420 format = GST_VIDEO_FORMAT_I420;
14423 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14424 format = GST_VIDEO_FORMAT_UYVY;
14426 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14427 format = GST_VIDEO_FORMAT_v308;
14429 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14430 format = GST_VIDEO_FORMAT_v216;
14433 format = GST_VIDEO_FORMAT_v210;
14435 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14436 format = GST_VIDEO_FORMAT_r210;
14438 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14439 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14440 format = GST_VIDEO_FORMAT_v410;
14443 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14444 * but different order than AYUV
14445 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14446 format = GST_VIDEO_FORMAT_v408;
14449 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14450 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14451 _codec ("MPEG-1 video");
14452 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14453 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14455 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14456 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14457 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14458 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14459 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14460 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14461 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14462 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14463 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14464 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14465 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14466 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14467 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14468 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14469 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14470 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14471 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14472 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14473 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14474 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14475 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14476 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14477 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14478 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14479 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14480 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14481 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14482 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14483 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14484 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14485 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14486 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14487 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14488 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14489 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14490 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14491 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14492 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14493 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14494 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14495 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14496 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14497 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14498 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14499 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14500 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14501 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14502 _codec ("MPEG-2 video");
14503 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14504 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14506 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14507 _codec ("GIF still images");
14508 caps = gst_caps_new_empty_simple ("image/gif");
14511 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14513 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14515 /* ffmpeg uses the height/width props, don't know why */
14516 caps = gst_caps_new_simple ("video/x-h263",
14517 "variant", G_TYPE_STRING, "itu", NULL);
14521 _codec ("MPEG-4 video");
14522 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14523 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14525 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14526 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14527 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14528 caps = gst_caps_new_simple ("video/x-msmpeg",
14529 "msmpegversion", G_TYPE_INT, 43, NULL);
14531 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14533 caps = gst_caps_new_simple ("video/x-divx",
14534 "divxversion", G_TYPE_INT, 3, NULL);
14536 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14537 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14539 caps = gst_caps_new_simple ("video/x-divx",
14540 "divxversion", G_TYPE_INT, 4, NULL);
14542 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14544 caps = gst_caps_new_simple ("video/x-divx",
14545 "divxversion", G_TYPE_INT, 5, NULL);
14548 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14550 caps = gst_caps_new_simple ("video/x-ffv",
14551 "ffvversion", G_TYPE_INT, 1, NULL);
14554 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14555 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14560 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14561 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14562 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14566 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14567 _codec ("Cinepak");
14568 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14570 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14571 _codec ("Apple QuickDraw");
14572 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14574 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14575 _codec ("Apple video");
14576 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14580 _codec ("H.264 / AVC");
14581 caps = gst_caps_new_simple ("video/x-h264",
14582 "stream-format", G_TYPE_STRING, "avc",
14583 "alignment", G_TYPE_STRING, "au", NULL);
14586 _codec ("H.264 / AVC");
14587 caps = gst_caps_new_simple ("video/x-h264",
14588 "stream-format", G_TYPE_STRING, "avc3",
14589 "alignment", G_TYPE_STRING, "au", NULL);
14593 _codec ("H.265 / HEVC");
14594 caps = gst_caps_new_simple ("video/x-h265",
14595 "stream-format", G_TYPE_STRING, "hvc1",
14596 "alignment", G_TYPE_STRING, "au", NULL);
14599 _codec ("H.265 / HEVC");
14600 caps = gst_caps_new_simple ("video/x-h265",
14601 "stream-format", G_TYPE_STRING, "hev1",
14602 "alignment", G_TYPE_STRING, "au", NULL);
14605 _codec ("Run-length encoding");
14606 caps = gst_caps_new_simple ("video/x-rle",
14607 "layout", G_TYPE_STRING, "quicktime", NULL);
14610 _codec ("Run-length encoding");
14611 caps = gst_caps_new_simple ("video/x-rle",
14612 "layout", G_TYPE_STRING, "microsoft", NULL);
14614 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14615 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14616 _codec ("Indeo Video 3");
14617 caps = gst_caps_new_simple ("video/x-indeo",
14618 "indeoversion", G_TYPE_INT, 3, NULL);
14620 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14621 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14622 _codec ("Intel Video 4");
14623 caps = gst_caps_new_simple ("video/x-indeo",
14624 "indeoversion", G_TYPE_INT, 4, NULL);
14628 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14629 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14630 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14631 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14632 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14633 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14634 _codec ("DV Video");
14635 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14636 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14638 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14639 case FOURCC_dv5p: /* DVCPRO50 PAL */
14640 _codec ("DVCPro50 Video");
14641 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14642 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14644 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14645 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14646 _codec ("DVCProHD Video");
14647 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14648 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14650 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14651 _codec ("Apple Graphics (SMC)");
14652 caps = gst_caps_new_empty_simple ("video/x-smc");
14654 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14656 caps = gst_caps_new_empty_simple ("video/x-vp3");
14658 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14659 _codec ("VP6 Flash");
14660 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14664 caps = gst_caps_new_empty_simple ("video/x-theora");
14665 /* theora uses one byte of padding in the data stream because it does not
14666 * allow 0 sized packets while theora does */
14667 entry->padding = 1;
14671 caps = gst_caps_new_empty_simple ("video/x-dirac");
14673 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14674 _codec ("TIFF still images");
14675 caps = gst_caps_new_empty_simple ("image/tiff");
14677 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14678 _codec ("Apple Intermediate Codec");
14679 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14681 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14682 _codec ("AVID DNxHD");
14683 caps = gst_caps_from_string ("video/x-dnxhd");
14687 _codec ("On2 VP8");
14688 caps = gst_caps_from_string ("video/x-vp8");
14691 _codec ("Google VP9");
14692 caps = gst_caps_from_string ("video/x-vp9");
14695 _codec ("Apple ProRes LT");
14697 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14701 _codec ("Apple ProRes HQ");
14703 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14707 _codec ("Apple ProRes");
14709 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14713 _codec ("Apple ProRes Proxy");
14715 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14719 _codec ("Apple ProRes 4444");
14721 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14725 _codec ("Apple ProRes 4444 XQ");
14727 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14731 _codec ("GoPro CineForm");
14732 caps = gst_caps_from_string ("video/x-cineform");
14737 caps = gst_caps_new_simple ("video/x-wmv",
14738 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14742 caps = gst_caps_new_empty_simple ("video/x-av1");
14744 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14747 caps = _get_unknown_codec_name ("video", fourcc);
14752 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14755 gst_video_info_init (&info);
14756 gst_video_info_set_format (&info, format, entry->width, entry->height);
14758 caps = gst_video_info_to_caps (&info);
14759 *codec_name = gst_pb_utils_get_codec_description (caps);
14761 /* enable clipping for raw video streams */
14762 stream->need_clip = TRUE;
14763 stream->alignment = 32;
14770 round_up_pow2 (guint n)
14782 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14783 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14784 int len, gchar ** codec_name)
14787 const GstStructure *s;
14790 GstAudioFormat format = 0;
14793 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14795 depth = entry->bytes_per_packet * 8;
14798 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14800 /* 8-bit audio is unsigned */
14802 format = GST_AUDIO_FORMAT_U8;
14803 /* otherwise it's signed and big-endian just like 'twos' */
14805 endian = G_BIG_ENDIAN;
14812 endian = G_LITTLE_ENDIAN;
14815 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14817 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14821 caps = gst_caps_new_simple ("audio/x-raw",
14822 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14823 "layout", G_TYPE_STRING, "interleaved", NULL);
14824 stream->alignment = GST_ROUND_UP_8 (depth);
14825 stream->alignment = round_up_pow2 (stream->alignment);
14828 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14829 _codec ("Raw 64-bit floating-point audio");
14830 caps = gst_caps_new_simple ("audio/x-raw",
14831 "format", G_TYPE_STRING, "F64BE",
14832 "layout", G_TYPE_STRING, "interleaved", NULL);
14833 stream->alignment = 8;
14835 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14836 _codec ("Raw 32-bit floating-point audio");
14837 caps = gst_caps_new_simple ("audio/x-raw",
14838 "format", G_TYPE_STRING, "F32BE",
14839 "layout", G_TYPE_STRING, "interleaved", NULL);
14840 stream->alignment = 4;
14843 _codec ("Raw 24-bit PCM audio");
14844 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14846 caps = gst_caps_new_simple ("audio/x-raw",
14847 "format", G_TYPE_STRING, "S24BE",
14848 "layout", G_TYPE_STRING, "interleaved", NULL);
14849 stream->alignment = 4;
14851 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14852 _codec ("Raw 32-bit PCM audio");
14853 caps = gst_caps_new_simple ("audio/x-raw",
14854 "format", G_TYPE_STRING, "S32BE",
14855 "layout", G_TYPE_STRING, "interleaved", NULL);
14856 stream->alignment = 4;
14858 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14859 _codec ("Raw 16-bit PCM audio");
14860 caps = gst_caps_new_simple ("audio/x-raw",
14861 "format", G_TYPE_STRING, "S16LE",
14862 "layout", G_TYPE_STRING, "interleaved", NULL);
14863 stream->alignment = 2;
14866 _codec ("Mu-law audio");
14867 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14870 _codec ("A-law audio");
14871 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14875 _codec ("Microsoft ADPCM");
14876 /* Microsoft ADPCM-ACM code 2 */
14877 caps = gst_caps_new_simple ("audio/x-adpcm",
14878 "layout", G_TYPE_STRING, "microsoft", NULL);
14882 _codec ("DVI/IMA ADPCM");
14883 caps = gst_caps_new_simple ("audio/x-adpcm",
14884 "layout", G_TYPE_STRING, "dvi", NULL);
14888 _codec ("DVI/Intel IMA ADPCM");
14889 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14890 caps = gst_caps_new_simple ("audio/x-adpcm",
14891 "layout", G_TYPE_STRING, "quicktime", NULL);
14895 /* MPEG layer 3, CBR only (pre QT4.1) */
14897 _codec ("MPEG-1 layer 3");
14898 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14899 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14900 "mpegversion", G_TYPE_INT, 1, NULL);
14902 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14903 _codec ("MPEG-1 layer 2");
14905 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14906 "mpegversion", G_TYPE_INT, 1, NULL);
14909 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14910 _codec ("EAC-3 audio");
14911 caps = gst_caps_new_simple ("audio/x-eac3",
14912 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14913 entry->sampled = TRUE;
14915 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14917 _codec ("AC-3 audio");
14918 caps = gst_caps_new_simple ("audio/x-ac3",
14919 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14920 entry->sampled = TRUE;
14922 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14923 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14924 _codec ("DTS audio");
14925 caps = gst_caps_new_simple ("audio/x-dts",
14926 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14927 entry->sampled = TRUE;
14929 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14930 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14931 _codec ("DTS-HD audio");
14932 caps = gst_caps_new_simple ("audio/x-dts",
14933 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14934 entry->sampled = TRUE;
14938 caps = gst_caps_new_simple ("audio/x-mace",
14939 "maceversion", G_TYPE_INT, 3, NULL);
14943 caps = gst_caps_new_simple ("audio/x-mace",
14944 "maceversion", G_TYPE_INT, 6, NULL);
14946 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14948 caps = gst_caps_new_empty_simple ("application/ogg");
14950 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14951 _codec ("DV audio");
14952 caps = gst_caps_new_empty_simple ("audio/x-dv");
14955 _codec ("MPEG-4 AAC audio");
14956 caps = gst_caps_new_simple ("audio/mpeg",
14957 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14958 "stream-format", G_TYPE_STRING, "raw", NULL);
14960 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14961 _codec ("QDesign Music");
14962 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14965 _codec ("QDesign Music v.2");
14966 /* FIXME: QDesign music version 2 (no constant) */
14967 if (FALSE && data) {
14968 caps = gst_caps_new_simple ("audio/x-qdm2",
14969 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14970 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14971 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14973 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14977 _codec ("GSM audio");
14978 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14981 _codec ("AMR audio");
14982 caps = gst_caps_new_empty_simple ("audio/AMR");
14985 _codec ("AMR-WB audio");
14986 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14989 _codec ("Quicktime IMA ADPCM");
14990 caps = gst_caps_new_simple ("audio/x-adpcm",
14991 "layout", G_TYPE_STRING, "quicktime", NULL);
14994 _codec ("Apple lossless audio");
14995 caps = gst_caps_new_empty_simple ("audio/x-alac");
14998 _codec ("Free Lossless Audio Codec");
14999 caps = gst_caps_new_simple ("audio/x-flac",
15000 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15002 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15003 _codec ("QualComm PureVoice");
15004 caps = gst_caps_from_string ("audio/qcelp");
15009 caps = gst_caps_new_empty_simple ("audio/x-wma");
15013 caps = gst_caps_new_empty_simple ("audio/x-opus");
15020 GstAudioFormat format;
15023 FLAG_IS_FLOAT = 0x1,
15024 FLAG_IS_BIG_ENDIAN = 0x2,
15025 FLAG_IS_SIGNED = 0x4,
15026 FLAG_IS_PACKED = 0x8,
15027 FLAG_IS_ALIGNED_HIGH = 0x10,
15028 FLAG_IS_NON_INTERLEAVED = 0x20
15030 _codec ("Raw LPCM audio");
15032 if (data && len >= 36) {
15033 depth = QT_UINT32 (data + 24);
15034 flags = QT_UINT32 (data + 28);
15035 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15037 if ((flags & FLAG_IS_FLOAT) == 0) {
15042 if ((flags & FLAG_IS_ALIGNED_HIGH))
15045 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15046 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15047 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15048 caps = gst_caps_new_simple ("audio/x-raw",
15049 "format", G_TYPE_STRING,
15051 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15052 "UNKNOWN", "layout", G_TYPE_STRING,
15053 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15054 "interleaved", NULL);
15055 stream->alignment = GST_ROUND_UP_8 (depth);
15056 stream->alignment = round_up_pow2 (stream->alignment);
15061 if (flags & FLAG_IS_BIG_ENDIAN)
15062 format = GST_AUDIO_FORMAT_F64BE;
15064 format = GST_AUDIO_FORMAT_F64LE;
15066 if (flags & FLAG_IS_BIG_ENDIAN)
15067 format = GST_AUDIO_FORMAT_F32BE;
15069 format = GST_AUDIO_FORMAT_F32LE;
15071 caps = gst_caps_new_simple ("audio/x-raw",
15072 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15073 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15074 "non-interleaved" : "interleaved", NULL);
15075 stream->alignment = width / 8;
15079 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15083 caps = _get_unknown_codec_name ("audio", fourcc);
15089 GstCaps *templ_caps =
15090 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15091 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15092 gst_caps_unref (caps);
15093 gst_caps_unref (templ_caps);
15094 caps = intersection;
15097 /* enable clipping for raw audio streams */
15098 s = gst_caps_get_structure (caps, 0);
15099 name = gst_structure_get_name (s);
15100 if (g_str_has_prefix (name, "audio/x-raw")) {
15101 stream->need_clip = TRUE;
15102 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15103 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15109 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15110 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15111 const guint8 * stsd_entry_data, gchar ** codec_name)
15115 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15119 _codec ("DVD subtitle");
15120 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15121 stream->need_process = TRUE;
15124 _codec ("Quicktime timed text");
15127 _codec ("3GPP timed text");
15129 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15131 /* actual text piece needs to be extracted */
15132 stream->need_process = TRUE;
15135 _codec ("XML subtitles");
15136 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15139 _codec ("CEA 608 Closed Caption");
15141 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15142 G_TYPE_STRING, "cc_data", NULL);
15143 stream->need_process = TRUE;
15146 _codec ("CEA 708 Closed Caption");
15148 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15149 G_TYPE_STRING, "cdp", NULL);
15150 stream->need_process = TRUE;
15155 caps = _get_unknown_codec_name ("text", fourcc);
15163 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15164 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15165 const guint8 * stsd_entry_data, gchar ** codec_name)
15171 _codec ("MPEG 1 video");
15172 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15173 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15183 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15184 const gchar * system_id)
15188 if (!qtdemux->protection_system_ids)
15189 qtdemux->protection_system_ids =
15190 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15191 /* Check whether we already have an entry for this system ID. */
15192 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15193 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15194 if (g_ascii_strcasecmp (system_id, id) == 0) {
15198 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15199 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,