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->upstream_format_is_time)
4083 gst_qtdemux_stream_flush_samples_data (stream);
4085 /* initialise moof sample data */
4086 stream->n_samples_moof = 0;
4087 stream->duration_last_moof = stream->duration_moof;
4088 stream->duration_moof = 0;
4090 /* Track Run node */
4092 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4095 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4096 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4097 &running_offset, decode_time, (tfdt_node != NULL));
4098 /* iterate all siblings */
4099 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4103 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4105 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4106 guint32 box_length = QT_UINT32 (uuid_buffer);
4108 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4111 /* if no new base_offset provided for next traf,
4112 * base is end of current traf */
4113 base_offset = running_offset;
4114 running_offset = -1;
4116 if (stream->n_samples_moof && stream->duration_moof)
4117 stream->new_caps = TRUE;
4120 /* iterate all siblings */
4121 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4124 /* parse any protection system info */
4125 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4127 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4128 qtdemux_parse_pssh (qtdemux, pssh_node);
4129 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4132 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4133 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4135 /* Unless the user has explictly requested another seek, perform an
4136 * internal seek to the time specified in the tfdt.
4138 * This way if the user opens a file where the first tfdt is 1 hour
4139 * into the presentation, they will not have to wait 1 hour for run
4140 * time to catch up and actual playback to start. */
4143 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4144 "performing an internal seek to %" GST_TIME_FORMAT,
4145 GST_TIME_ARGS (min_dts));
4147 qtdemux->segment.start = min_dts;
4148 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4150 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4151 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
4152 stream->time_position = min_dts;
4155 /* Before this code was run a segment was already sent when the moov was
4156 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4157 * be emitted after a moov, and we can emit a second segment anyway for
4158 * special cases like this. */
4159 qtdemux->need_segment = TRUE;
4162 qtdemux->first_moof_already_parsed = TRUE;
4164 g_node_destroy (moof_node);
4169 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4174 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4179 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4184 g_node_destroy (moof_node);
4185 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4186 (_("This file is corrupt and cannot be played.")), (NULL));
4192 /* might be used if some day we actually use mfra & co
4193 * for random access to fragments,
4194 * but that will require quite some modifications and much less relying
4195 * on a sample array */
4199 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4201 QtDemuxStream *stream;
4202 guint32 ver_flags, track_id, len, num_entries, i;
4203 guint value_size, traf_size, trun_size, sample_size;
4204 guint64 time = 0, moof_offset = 0;
4206 GstBuffer *buf = NULL;
4211 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4213 if (!gst_byte_reader_skip (&tfra, 8))
4216 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4219 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4220 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4221 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4224 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4226 stream = qtdemux_find_stream (qtdemux, track_id);
4228 goto unknown_trackid;
4230 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4231 sample_size = (len & 3) + 1;
4232 trun_size = ((len & 12) >> 2) + 1;
4233 traf_size = ((len & 48) >> 4) + 1;
4235 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4236 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4238 if (num_entries == 0)
4241 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4242 value_size + value_size + traf_size + trun_size + sample_size))
4245 g_free (stream->ra_entries);
4246 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4247 stream->n_ra_entries = num_entries;
4249 for (i = 0; i < num_entries; i++) {
4250 qt_atom_parser_get_offset (&tfra, value_size, &time);
4251 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4252 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4253 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4254 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4256 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4258 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4259 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4261 stream->ra_entries[i].ts = time;
4262 stream->ra_entries[i].moof_offset = moof_offset;
4264 /* don't want to go through the entire file and read all moofs at startup */
4266 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4267 if (ret != GST_FLOW_OK)
4269 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4270 moof_offset, stream);
4271 gst_buffer_unref (buf);
4275 check_update_duration (qtdemux, time);
4282 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4287 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4292 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4298 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4300 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4301 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4302 GstBuffer *mfro = NULL, *mfra = NULL;
4304 gboolean ret = FALSE;
4305 GNode *mfra_node, *tfra_node;
4306 guint64 mfra_offset = 0;
4307 guint32 fourcc, mfra_size;
4310 /* query upstream size in bytes */
4311 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4312 goto size_query_failed;
4314 /* mfro box should be at the very end of the file */
4315 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4316 if (flow != GST_FLOW_OK)
4319 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4321 fourcc = QT_FOURCC (mfro_map.data + 4);
4322 if (fourcc != FOURCC_mfro)
4325 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4326 if (mfro_map.size < 16)
4327 goto invalid_mfro_size;
4329 mfra_size = QT_UINT32 (mfro_map.data + 12);
4330 if (mfra_size >= len)
4331 goto invalid_mfra_size;
4333 mfra_offset = len - mfra_size;
4335 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4336 mfra_offset, mfra_size);
4338 /* now get and parse mfra box */
4339 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4340 if (flow != GST_FLOW_OK)
4343 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4345 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4346 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4348 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4351 qtdemux_parse_tfra (qtdemux, tfra_node);
4352 /* iterate all siblings */
4353 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4355 g_node_destroy (mfra_node);
4357 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4363 if (mfro_map.memory != NULL)
4364 gst_buffer_unmap (mfro, &mfro_map);
4365 gst_buffer_unref (mfro);
4368 if (mfra_map.memory != NULL)
4369 gst_buffer_unmap (mfra, &mfra_map);
4370 gst_buffer_unref (mfra);
4377 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4382 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4387 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4392 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4398 add_offset (guint64 offset, guint64 advance)
4400 /* Avoid 64-bit overflow by clamping */
4401 if (offset > G_MAXUINT64 - advance)
4403 return offset + advance;
4406 static GstFlowReturn
4407 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4411 GstBuffer *buf = NULL;
4412 GstFlowReturn ret = GST_FLOW_OK;
4413 guint64 cur_offset = qtdemux->offset;
4416 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4417 if (G_UNLIKELY (ret != GST_FLOW_OK))
4419 gst_buffer_map (buf, &map, GST_MAP_READ);
4420 if (G_LIKELY (map.size >= 8))
4421 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4422 gst_buffer_unmap (buf, &map);
4423 gst_buffer_unref (buf);
4425 /* maybe we already got most we needed, so only consider this eof */
4426 if (G_UNLIKELY (length == 0)) {
4427 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4428 (_("Invalid atom size.")),
4429 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4430 GST_FOURCC_ARGS (fourcc)));
4437 /* record for later parsing when needed */
4438 if (!qtdemux->moof_offset) {
4439 qtdemux->moof_offset = qtdemux->offset;
4441 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4444 qtdemux->offset += length; /* skip moof and keep going */
4446 if (qtdemux->got_moov) {
4447 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4459 GST_LOG_OBJECT (qtdemux,
4460 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4461 GST_FOURCC_ARGS (fourcc), cur_offset);
4462 qtdemux->offset = add_offset (qtdemux->offset, length);
4467 GstBuffer *moov = NULL;
4469 if (qtdemux->got_moov) {
4470 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4471 qtdemux->offset = add_offset (qtdemux->offset, length);
4475 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4476 if (ret != GST_FLOW_OK)
4478 gst_buffer_map (moov, &map, GST_MAP_READ);
4480 if (length != map.size) {
4481 /* Some files have a 'moov' atom at the end of the file which contains
4482 * a terminal 'free' atom where the body of the atom is missing.
4483 * Check for, and permit, this special case.
4485 if (map.size >= 8) {
4486 guint8 *final_data = map.data + (map.size - 8);
4487 guint32 final_length = QT_UINT32 (final_data);
4488 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4490 if (final_fourcc == FOURCC_free
4491 && map.size + final_length - 8 == length) {
4492 /* Ok, we've found that special case. Allocate a new buffer with
4493 * that free atom actually present. */
4494 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4495 gst_buffer_fill (newmoov, 0, map.data, map.size);
4496 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4497 gst_buffer_unmap (moov, &map);
4498 gst_buffer_unref (moov);
4500 gst_buffer_map (moov, &map, GST_MAP_READ);
4505 if (length != map.size) {
4506 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4507 (_("This file is incomplete and cannot be played.")),
4508 ("We got less than expected (received %" G_GSIZE_FORMAT
4509 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4510 (guint) length, cur_offset));
4511 gst_buffer_unmap (moov, &map);
4512 gst_buffer_unref (moov);
4513 ret = GST_FLOW_ERROR;
4516 qtdemux->offset += length;
4518 qtdemux_parse_moov (qtdemux, map.data, length);
4519 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4521 qtdemux_parse_tree (qtdemux);
4522 if (qtdemux->moov_node_compressed) {
4523 g_node_destroy (qtdemux->moov_node_compressed);
4524 g_free (qtdemux->moov_node->data);
4526 qtdemux->moov_node_compressed = NULL;
4527 g_node_destroy (qtdemux->moov_node);
4528 qtdemux->moov_node = NULL;
4529 gst_buffer_unmap (moov, &map);
4530 gst_buffer_unref (moov);
4531 qtdemux->got_moov = TRUE;
4537 GstBuffer *ftyp = NULL;
4539 /* extract major brand; might come in handy for ISO vs QT issues */
4540 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4541 if (ret != GST_FLOW_OK)
4543 qtdemux->offset += length;
4544 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4545 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4546 gst_buffer_unmap (ftyp, &map);
4547 gst_buffer_unref (ftyp);
4552 GstBuffer *uuid = NULL;
4554 /* uuid are extension atoms */
4555 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4556 if (ret != GST_FLOW_OK)
4558 qtdemux->offset += length;
4559 gst_buffer_map (uuid, &map, GST_MAP_READ);
4560 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4561 gst_buffer_unmap (uuid, &map);
4562 gst_buffer_unref (uuid);
4567 GstBuffer *sidx = NULL;
4568 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4569 if (ret != GST_FLOW_OK)
4571 qtdemux->offset += length;
4572 gst_buffer_map (sidx, &map, GST_MAP_READ);
4573 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4574 gst_buffer_unmap (sidx, &map);
4575 gst_buffer_unref (sidx);
4580 GstBuffer *unknown = NULL;
4582 GST_LOG_OBJECT (qtdemux,
4583 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4584 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4586 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4587 if (ret != GST_FLOW_OK)
4589 gst_buffer_map (unknown, &map, GST_MAP_READ);
4590 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4591 gst_buffer_unmap (unknown, &map);
4592 gst_buffer_unref (unknown);
4593 qtdemux->offset += length;
4599 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4600 /* digested all data, show what we have */
4601 qtdemux_prepare_streams (qtdemux);
4602 QTDEMUX_EXPOSE_LOCK (qtdemux);
4603 ret = qtdemux_expose_streams (qtdemux);
4604 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4606 qtdemux->state = QTDEMUX_STATE_MOVIE;
4607 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4614 /* Seeks to the previous keyframe of the indexed stream and
4615 * aligns other streams with respect to the keyframe timestamp
4616 * of indexed stream. Only called in case of Reverse Playback
4618 static GstFlowReturn
4619 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4621 guint32 seg_idx = 0, k_index = 0;
4622 guint32 ref_seg_idx, ref_k_index;
4623 GstClockTime k_pos = 0, last_stop = 0;
4624 QtDemuxSegment *seg = NULL;
4625 QtDemuxStream *ref_str = NULL;
4626 guint64 seg_media_start_mov; /* segment media start time in mov format */
4630 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4631 * and finally align all the other streams on that timestamp with their
4632 * respective keyframes */
4633 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4634 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4636 /* No candidate yet, take the first stream */
4642 /* So that stream has a segment, we prefer video streams */
4643 if (str->subtype == FOURCC_vide) {
4649 if (G_UNLIKELY (!ref_str)) {
4650 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4654 if (G_UNLIKELY (!ref_str->from_sample)) {
4655 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4659 /* So that stream has been playing from from_sample to to_sample. We will
4660 * get the timestamp of the previous sample and search for a keyframe before
4661 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4662 if (ref_str->subtype == FOURCC_vide) {
4663 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4664 ref_str->from_sample - 1, FALSE);
4666 if (ref_str->from_sample >= 10)
4667 k_index = ref_str->from_sample - 10;
4673 ref_str->samples[k_index].timestamp +
4674 ref_str->samples[k_index].pts_offset;
4676 /* get current segment for that stream */
4677 seg = &ref_str->segments[ref_str->segment_index];
4678 /* Use segment start in original timescale for comparisons */
4679 seg_media_start_mov = seg->trak_media_start;
4681 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4682 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4683 k_index, target_ts, seg_media_start_mov,
4684 GST_TIME_ARGS (seg->media_start));
4686 /* Crawl back through segments to find the one containing this I frame */
4687 while (target_ts < seg_media_start_mov) {
4688 GST_DEBUG_OBJECT (qtdemux,
4689 "keyframe position (sample %u) is out of segment %u " " target %"
4690 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4691 ref_str->segment_index, target_ts, seg_media_start_mov);
4693 if (G_UNLIKELY (!ref_str->segment_index)) {
4694 /* Reached first segment, let's consider it's EOS */
4697 ref_str->segment_index--;
4698 seg = &ref_str->segments[ref_str->segment_index];
4699 /* Use segment start in original timescale for comparisons */
4700 seg_media_start_mov = seg->trak_media_start;
4702 /* Calculate time position of the keyframe and where we should stop */
4704 QTSTREAMTIME_TO_GSTTIME (ref_str,
4705 target_ts - seg->trak_media_start) + seg->time;
4707 QTSTREAMTIME_TO_GSTTIME (ref_str,
4708 ref_str->samples[ref_str->from_sample].timestamp -
4709 seg->trak_media_start) + seg->time;
4711 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4712 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4713 k_index, GST_TIME_ARGS (k_pos));
4715 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4716 qtdemux->segment.position = last_stop;
4717 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4718 GST_TIME_ARGS (last_stop));
4720 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4721 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4725 ref_seg_idx = ref_str->segment_index;
4726 ref_k_index = k_index;
4728 /* Align them all on this */
4729 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4731 GstClockTime seg_time = 0;
4732 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4734 /* aligning reference stream again might lead to backing up to yet another
4735 * keyframe (due to timestamp rounding issues),
4736 * potentially putting more load on downstream; so let's try to avoid */
4737 if (str == ref_str) {
4738 seg_idx = ref_seg_idx;
4739 seg = &str->segments[seg_idx];
4740 k_index = ref_k_index;
4741 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4742 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4744 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4745 GST_DEBUG_OBJECT (qtdemux,
4746 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4747 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4749 /* get segment and time in the segment */
4750 seg = &str->segments[seg_idx];
4751 seg_time = k_pos - seg->time;
4753 /* get the media time in the segment.
4754 * No adjustment for empty "filler" segments */
4755 if (seg->media_start != GST_CLOCK_TIME_NONE)
4756 seg_time += seg->media_start;
4758 /* get the index of the sample with media time */
4759 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4760 GST_DEBUG_OBJECT (qtdemux,
4761 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4762 GST_TIME_ARGS (seg_time), index);
4764 /* find previous keyframe */
4765 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4768 /* Remember until where we want to go */
4769 str->to_sample = str->from_sample - 1;
4770 /* Define our time position */
4772 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4773 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4774 if (seg->media_start != GST_CLOCK_TIME_NONE)
4775 str->time_position -= seg->media_start;
4777 /* Now seek back in time */
4778 gst_qtdemux_move_stream (qtdemux, str, k_index);
4779 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4780 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4781 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4787 return GST_FLOW_EOS;
4791 * Gets the current qt segment start, stop and position for the
4792 * given time offset. This is used in update_segment()
4795 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4796 QtDemuxStream * stream, GstClockTime offset,
4797 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4799 GstClockTime seg_time;
4800 GstClockTime start, stop, time;
4801 QtDemuxSegment *segment;
4803 segment = &stream->segments[stream->segment_index];
4805 /* get time in this segment */
4806 seg_time = (offset - segment->time) * segment->rate;
4808 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4809 GST_TIME_ARGS (seg_time));
4811 if (G_UNLIKELY (seg_time > segment->duration)) {
4812 GST_LOG_OBJECT (stream->pad,
4813 "seg_time > segment->duration %" GST_TIME_FORMAT,
4814 GST_TIME_ARGS (segment->duration));
4815 seg_time = segment->duration;
4818 /* qtdemux->segment.stop is in outside-time-realm, whereas
4819 * segment->media_stop is in track-time-realm.
4821 * In order to compare the two, we need to bring segment.stop
4822 * into the track-time-realm
4824 * FIXME - does this comment still hold? Don't see any conversion here */
4826 stop = qtdemux->segment.stop;
4827 if (stop == GST_CLOCK_TIME_NONE)
4828 stop = qtdemux->segment.duration;
4829 if (stop == GST_CLOCK_TIME_NONE)
4830 stop = segment->media_stop;
4833 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4835 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4836 start = segment->time + seg_time;
4838 stop = start - seg_time + segment->duration;
4839 } else if (qtdemux->segment.rate >= 0) {
4840 start = MIN (segment->media_start + seg_time, stop);
4843 if (segment->media_start >= qtdemux->segment.start) {
4844 time = segment->time;
4846 time = segment->time + (qtdemux->segment.start - segment->media_start);
4849 start = MAX (segment->media_start, qtdemux->segment.start);
4850 stop = MIN (segment->media_start + seg_time, stop);
4859 * Updates the qt segment used for the stream and pushes a new segment event
4860 * downstream on this stream's pad.
4863 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4864 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4865 GstClockTime * _stop)
4867 QtDemuxSegment *segment;
4868 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4872 /* update the current segment */
4873 stream->segment_index = seg_idx;
4875 /* get the segment */
4876 segment = &stream->segments[seg_idx];
4878 if (G_UNLIKELY (offset < segment->time)) {
4879 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4880 GST_TIME_ARGS (segment->time));
4884 /* segment lies beyond total indicated duration */
4885 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4886 segment->time > qtdemux->segment.duration)) {
4887 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4888 " < segment->time %" GST_TIME_FORMAT,
4889 GST_TIME_ARGS (qtdemux->segment.duration),
4890 GST_TIME_ARGS (segment->time));
4894 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4895 &start, &stop, &time);
4897 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4898 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4899 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4901 /* combine global rate with that of the segment */
4902 rate = segment->rate * qtdemux->segment.rate;
4904 /* Copy flags from main segment */
4905 stream->segment.flags = qtdemux->segment.flags;
4907 /* update the segment values used for clipping */
4908 stream->segment.offset = qtdemux->segment.offset;
4909 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4910 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4911 stream->segment.rate = rate;
4912 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4913 stream->cslg_shift);
4914 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4915 stream->cslg_shift);
4916 stream->segment.time = time;
4917 stream->segment.position = stream->segment.start;
4919 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4922 /* now prepare and send the segment */
4924 event = gst_event_new_segment (&stream->segment);
4925 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4926 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4928 gst_pad_push_event (stream->pad, event);
4929 /* assume we can send more data now */
4930 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4931 /* clear to send tags on this pad now */
4932 gst_qtdemux_push_tags (qtdemux, stream);
4943 /* activate the given segment number @seg_idx of @stream at time @offset.
4944 * @offset is an absolute global position over all the segments.
4946 * This will push out a NEWSEGMENT event with the right values and
4947 * position the stream index to the first decodable sample before
4951 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4952 guint32 seg_idx, GstClockTime offset)
4954 QtDemuxSegment *segment;
4955 guint32 index, kf_index;
4956 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4958 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4959 seg_idx, GST_TIME_ARGS (offset));
4961 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4965 segment = &stream->segments[stream->segment_index];
4967 /* in the fragmented case, we pick a fragment that starts before our
4968 * desired position and rely on downstream to wait for a keyframe
4969 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4970 * tfra entries tells us which trun/sample the key unit is in, but we don't
4971 * make use of this additional information at the moment) */
4972 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4973 stream->to_sample = G_MAXUINT32;
4976 /* well, it will be taken care of below */
4977 qtdemux->fragmented_seek_pending = FALSE;
4978 /* FIXME ideally the do_fragmented_seek can be done right here,
4979 * rather than at loop level
4980 * (which might even allow handling edit lists in a fragmented file) */
4983 /* We don't need to look for a sample in push-based */
4984 if (!qtdemux->pullbased)
4987 /* and move to the keyframe before the indicated media time of the
4989 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4990 if (qtdemux->segment.rate >= 0) {
4991 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4992 stream->to_sample = G_MAXUINT32;
4993 GST_DEBUG_OBJECT (stream->pad,
4994 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4995 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4996 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4998 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4999 stream->to_sample = index;
5000 GST_DEBUG_OBJECT (stream->pad,
5001 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5002 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5003 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5006 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5007 "this is an empty segment");
5011 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5012 * encountered an error and printed a message so we return appropriately */
5016 /* we're at the right spot */
5017 if (index == stream->sample_index) {
5018 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5022 /* find keyframe of the target index */
5023 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5026 /* indent does stupid stuff with stream->samples[].timestamp */
5028 /* if we move forwards, we don't have to go back to the previous
5029 * keyframe since we already sent that. We can also just jump to
5030 * the keyframe right before the target index if there is one. */
5031 if (index > stream->sample_index) {
5032 /* moving forwards check if we move past a keyframe */
5033 if (kf_index > stream->sample_index) {
5034 GST_DEBUG_OBJECT (stream->pad,
5035 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5036 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5037 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5038 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5040 GST_DEBUG_OBJECT (stream->pad,
5041 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5042 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5043 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5046 GST_DEBUG_OBJECT (stream->pad,
5047 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5048 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5049 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5050 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5058 /* prepare to get the current sample of @stream, getting essential values.
5060 * This function will also prepare and send the segment when needed.
5062 * Return FALSE if the stream is EOS.
5067 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5068 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5069 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5070 gboolean * keyframe)
5072 QtDemuxSample *sample;
5073 GstClockTime time_position;
5076 g_return_val_if_fail (stream != NULL, FALSE);
5078 time_position = stream->time_position;
5079 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5082 seg_idx = stream->segment_index;
5083 if (G_UNLIKELY (seg_idx == -1)) {
5084 /* find segment corresponding to time_position if we are looking
5086 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5089 /* different segment, activate it, sample_index will be set. */
5090 if (G_UNLIKELY (stream->segment_index != seg_idx))
5091 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5093 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5095 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5097 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5098 " prepare empty sample");
5101 *pts = *dts = time_position;
5102 *duration = seg->duration - (time_position - seg->time);
5109 if (stream->sample_index == -1)
5110 stream->sample_index = 0;
5112 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5113 stream->sample_index, stream->n_samples);
5115 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5116 if (!qtdemux->fragmented)
5119 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5123 GST_OBJECT_LOCK (qtdemux);
5124 flow = qtdemux_add_fragmented_samples (qtdemux);
5125 GST_OBJECT_UNLOCK (qtdemux);
5127 if (flow != GST_FLOW_OK)
5130 while (stream->sample_index >= stream->n_samples);
5133 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5134 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5135 stream->sample_index);
5139 /* now get the info for the sample we're at */
5140 sample = &stream->samples[stream->sample_index];
5142 *dts = QTSAMPLE_DTS (stream, sample);
5143 *pts = QTSAMPLE_PTS (stream, sample);
5144 *offset = sample->offset;
5145 *size = sample->size;
5146 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5147 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5154 stream->time_position = GST_CLOCK_TIME_NONE;
5159 /* move to the next sample in @stream.
5161 * Moves to the next segment when needed.
5164 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5166 QtDemuxSample *sample;
5167 QtDemuxSegment *segment;
5169 /* get current segment */
5170 segment = &stream->segments[stream->segment_index];
5172 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5173 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5177 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5178 /* Mark the stream as EOS */
5179 GST_DEBUG_OBJECT (qtdemux,
5180 "reached max allowed sample %u, mark EOS", stream->to_sample);
5181 stream->time_position = GST_CLOCK_TIME_NONE;
5185 /* move to next sample */
5186 stream->sample_index++;
5187 stream->offset_in_sample = 0;
5189 /* reached the last sample, we need the next segment */
5190 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5193 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5194 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5195 stream->sample_index);
5199 /* get next sample */
5200 sample = &stream->samples[stream->sample_index];
5202 /* see if we are past the segment */
5203 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5206 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5207 /* inside the segment, update time_position, looks very familiar to
5208 * GStreamer segments, doesn't it? */
5209 stream->time_position =
5210 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5212 /* not yet in segment, time does not yet increment. This means
5213 * that we are still prerolling keyframes to the decoder so it can
5214 * decode the first sample of the segment. */
5215 stream->time_position = segment->time;
5219 /* move to the next segment */
5222 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5224 if (stream->segment_index == stream->n_segments - 1) {
5225 /* are we at the end of the last segment, we're EOS */
5226 stream->time_position = GST_CLOCK_TIME_NONE;
5228 /* else we're only at the end of the current segment */
5229 stream->time_position = segment->stop_time;
5231 /* make sure we select a new segment */
5233 /* accumulate previous segments */
5234 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5235 stream->accumulated_base +=
5236 (stream->segment.stop -
5237 stream->segment.start) / ABS (stream->segment.rate);
5239 stream->segment_index = -1;
5244 gst_qtdemux_sync_streams (GstQTDemux * demux)
5248 if (demux->n_streams <= 1)
5251 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
5252 QtDemuxStream *stream;
5253 GstClockTime end_time;
5255 stream = QTDEMUX_STREAM (iter->data);
5260 /* TODO advance time on subtitle streams here, if any some day */
5262 /* some clips/trailers may have unbalanced streams at the end,
5263 * so send EOS on shorter stream to prevent stalling others */
5265 /* do not mess with EOS if SEGMENT seeking */
5266 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5269 if (demux->pullbased) {
5270 /* loop mode is sample time based */
5271 if (!STREAM_IS_EOS (stream))
5274 /* push mode is byte position based */
5275 if (stream->n_samples &&
5276 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5280 if (stream->sent_eos)
5283 /* only act if some gap */
5284 end_time = stream->segments[stream->n_segments - 1].stop_time;
5285 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5286 ", stream end: %" GST_TIME_FORMAT,
5287 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5288 if (GST_CLOCK_TIME_IS_VALID (end_time)
5289 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5292 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5293 GST_PAD_NAME (stream->pad));
5294 stream->sent_eos = TRUE;
5295 event = gst_event_new_eos ();
5296 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5297 gst_event_set_seqnum (event, demux->segment_seqnum);
5298 gst_pad_push_event (stream->pad, event);
5303 /* EOS and NOT_LINKED need to be combined. This means that we return:
5305 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5306 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5308 static GstFlowReturn
5309 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5312 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5315 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5318 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5320 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5324 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5325 * completely clipped
5327 * Should be used only with raw buffers */
5329 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5332 guint64 start, stop, cstart, cstop, diff;
5333 GstClockTime pts, duration;
5335 gint num_rate, denom_rate;
5340 osize = size = gst_buffer_get_size (buf);
5343 /* depending on the type, setup the clip parameters */
5344 if (stream->subtype == FOURCC_soun) {
5345 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5346 num_rate = GST_SECOND;
5347 denom_rate = (gint) CUR_STREAM (stream)->rate;
5349 } else if (stream->subtype == FOURCC_vide) {
5351 num_rate = CUR_STREAM (stream)->fps_n;
5352 denom_rate = CUR_STREAM (stream)->fps_d;
5357 if (frame_size <= 0)
5358 goto bad_frame_size;
5360 /* we can only clip if we have a valid pts */
5361 pts = GST_BUFFER_PTS (buf);
5362 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5365 duration = GST_BUFFER_DURATION (buf);
5367 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5369 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5373 stop = start + duration;
5375 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5376 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5379 /* see if some clipping happened */
5380 diff = cstart - start;
5386 /* bring clipped time to samples and to bytes */
5387 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5390 GST_DEBUG_OBJECT (qtdemux,
5391 "clipping start to %" GST_TIME_FORMAT " %"
5392 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5398 diff = stop - cstop;
5403 /* bring clipped time to samples and then to bytes */
5404 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5406 GST_DEBUG_OBJECT (qtdemux,
5407 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5408 " bytes", GST_TIME_ARGS (cstop), diff);
5413 if (offset != 0 || size != osize)
5414 gst_buffer_resize (buf, offset, size);
5416 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5417 GST_BUFFER_PTS (buf) = pts;
5418 GST_BUFFER_DURATION (buf) = duration;
5422 /* dropped buffer */
5425 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5430 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5435 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5440 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5441 gst_buffer_unref (buf);
5447 gst_qtdemux_align_buffer (GstQTDemux * demux,
5448 GstBuffer * buffer, gsize alignment)
5452 gst_buffer_map (buffer, &map, GST_MAP_READ);
5454 if (map.size < sizeof (guintptr)) {
5455 gst_buffer_unmap (buffer, &map);
5459 if (((guintptr) map.data) & (alignment - 1)) {
5460 GstBuffer *new_buffer;
5461 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5463 new_buffer = gst_buffer_new_allocate (NULL,
5464 gst_buffer_get_size (buffer), ¶ms);
5466 /* Copy data "by hand", so ensure alignment is kept: */
5467 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5469 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5470 GST_DEBUG_OBJECT (demux,
5471 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5474 gst_buffer_unmap (buffer, &map);
5475 gst_buffer_unref (buffer);
5480 gst_buffer_unmap (buffer, &map);
5485 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5491 /* We are converting from pairs to triplets */
5492 *res = ccpair_size / 2 * 3;
5493 storage = g_malloc (*res);
5494 for (i = 0; i * 2 < ccpair_size; i += 1) {
5496 storage[i * 3] = 0xfc;
5498 storage[i * 3] = 0xfd;
5499 storage[i * 3 + 1] = ccpair[i * 2];
5500 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5507 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5511 guint32 atom_length, fourcc;
5512 QtDemuxStreamStsdEntry *stsd_entry;
5514 GST_MEMDUMP ("caption atom", data, size);
5516 /* There might be multiple atoms */
5521 atom_length = QT_UINT32 (data);
5522 fourcc = QT_FOURCC (data + 4);
5523 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5526 GST_DEBUG_OBJECT (stream->pad, "here");
5528 /* Check if we have somethig compatible */
5529 stsd_entry = CUR_STREAM (stream);
5530 switch (stsd_entry->fourcc) {
5532 guint8 *cdat = NULL, *cdt2 = NULL;
5533 gsize cdat_size = 0, cdt2_size = 0;
5534 /* Should be cdat or cdt2 */
5535 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5536 GST_WARNING_OBJECT (stream->pad,
5537 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5538 GST_FOURCC_ARGS (fourcc));
5542 /* Convert to cc_data triplet */
5543 if (fourcc == FOURCC_cdat)
5544 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5546 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5547 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5550 /* Check for another atom ? */
5551 if (size > atom_length + 8) {
5552 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5553 if (size >= atom_length + new_atom_length) {
5554 fourcc = QT_FOURCC (data + atom_length + 4);
5555 if (fourcc == FOURCC_cdat) {
5558 convert_to_ccdata (data + atom_length + 8,
5559 new_atom_length - 8, 1, &cdat_size);
5561 GST_WARNING_OBJECT (stream->pad,
5562 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5566 convert_to_ccdata (data + atom_length + 8,
5567 new_atom_length - 8, 2, &cdt2_size);
5569 GST_WARNING_OBJECT (stream->pad,
5570 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5575 *cclen = cdat_size + cdt2_size;
5576 res = g_malloc (*cclen);
5578 memcpy (res, cdat, cdat_size);
5580 memcpy (res + cdat_size, cdt2, cdt2_size);
5586 if (fourcc != FOURCC_ccdp) {
5587 GST_WARNING_OBJECT (stream->pad,
5588 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5589 GST_FOURCC_ARGS (fourcc));
5592 *cclen = atom_length - 8;
5593 res = g_memdup (data + 8, *cclen);
5596 /* Keep this here in case other closed caption formats are added */
5597 g_assert_not_reached ();
5601 GST_MEMDUMP ("Output", res, *cclen);
5606 GST_WARNING ("[cdat] atom is too small or invalid");
5610 /* the input buffer metadata must be writable,
5611 * but time/duration etc not yet set and need not be preserved */
5613 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5620 /* not many cases for now */
5621 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5622 /* send a one time dvd clut event */
5623 if (stream->pending_event && stream->pad)
5624 gst_pad_push_event (stream->pad, stream->pending_event);
5625 stream->pending_event = NULL;
5628 if (G_UNLIKELY (stream->subtype != FOURCC_text
5629 && stream->subtype != FOURCC_sbtl &&
5630 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5634 gst_buffer_map (buf, &map, GST_MAP_READ);
5636 /* empty buffer is sent to terminate previous subtitle */
5637 if (map.size <= 2) {
5638 gst_buffer_unmap (buf, &map);
5639 gst_buffer_unref (buf);
5642 if (stream->subtype == FOURCC_subp) {
5643 /* That's all the processing needed for subpictures */
5644 gst_buffer_unmap (buf, &map);
5648 if (stream->subtype == FOURCC_clcp) {
5651 /* For closed caption, we need to extract the information from the
5652 * [cdat],[cdt2] or [ccdp] atom */
5653 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5654 gst_buffer_unmap (buf, &map);
5655 gst_buffer_unref (buf);
5657 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5659 /* Conversion failed or there's nothing */
5665 nsize = GST_READ_UINT16_BE (map.data);
5666 nsize = MIN (nsize, map.size - 2);
5668 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5671 /* takes care of UTF-8 validation or UTF-16 recognition,
5672 * no other encoding expected */
5673 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5674 gst_buffer_unmap (buf, &map);
5676 gst_buffer_unref (buf);
5677 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5679 /* this should not really happen unless the subtitle is corrupted */
5680 gst_buffer_unref (buf);
5684 /* FIXME ? convert optional subsequent style info to markup */
5689 /* Sets a buffer's attributes properly and pushes it downstream.
5690 * Also checks for additional actions and custom processing that may
5691 * need to be done first.
5693 static GstFlowReturn
5694 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5695 QtDemuxStream * stream, GstBuffer * buf,
5696 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5697 gboolean keyframe, GstClockTime position, guint64 byte_position)
5699 GstFlowReturn ret = GST_FLOW_OK;
5701 /* offset the timestamps according to the edit list */
5703 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5707 gst_buffer_map (buf, &map, GST_MAP_READ);
5708 url = g_strndup ((gchar *) map.data, map.size);
5709 gst_buffer_unmap (buf, &map);
5710 if (url != NULL && strlen (url) != 0) {
5711 /* we have RTSP redirect now */
5712 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5713 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5714 gst_structure_new ("redirect",
5715 "new-location", G_TYPE_STRING, url, NULL)));
5716 qtdemux->posted_redirect = TRUE;
5718 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5724 /* position reporting */
5725 if (qtdemux->segment.rate >= 0) {
5726 qtdemux->segment.position = position;
5727 gst_qtdemux_sync_streams (qtdemux);
5730 if (G_UNLIKELY (!stream->pad)) {
5731 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5732 gst_buffer_unref (buf);
5736 /* send out pending buffers */
5737 while (stream->buffers) {
5738 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5740 if (G_UNLIKELY (stream->discont)) {
5741 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5742 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5743 stream->discont = FALSE;
5745 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5748 if (stream->alignment > 1)
5749 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5750 gst_pad_push (stream->pad, buffer);
5752 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5755 /* we're going to modify the metadata */
5756 buf = gst_buffer_make_writable (buf);
5758 if (G_UNLIKELY (stream->need_process))
5759 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5765 GST_BUFFER_DTS (buf) = dts;
5766 GST_BUFFER_PTS (buf) = pts;
5767 GST_BUFFER_DURATION (buf) = duration;
5768 GST_BUFFER_OFFSET (buf) = -1;
5769 GST_BUFFER_OFFSET_END (buf) = -1;
5771 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5772 gst_buffer_append_memory (buf,
5773 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5775 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5776 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5779 if (G_UNLIKELY (qtdemux->element_index)) {
5780 GstClockTime stream_time;
5783 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5785 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5786 GST_LOG_OBJECT (qtdemux,
5787 "adding association %" GST_TIME_FORMAT "-> %"
5788 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5789 gst_index_add_association (qtdemux->element_index,
5791 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5792 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5793 GST_FORMAT_BYTES, byte_position, NULL);
5798 if (stream->need_clip)
5799 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5801 if (G_UNLIKELY (buf == NULL))
5804 if (G_UNLIKELY (stream->discont)) {
5805 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5806 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5807 stream->discont = FALSE;
5809 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5813 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5814 stream->on_keyframe = FALSE;
5816 stream->on_keyframe = TRUE;
5820 GST_LOG_OBJECT (qtdemux,
5821 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5822 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5823 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5824 GST_PAD_NAME (stream->pad));
5826 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5827 GstStructure *crypto_info;
5828 QtDemuxCencSampleSetInfo *info =
5829 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5833 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5834 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5835 GST_PTR_FORMAT, event);
5836 gst_pad_push_event (stream->pad, event);
5839 if (info->crypto_info == NULL) {
5840 GST_DEBUG_OBJECT (qtdemux,
5841 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5843 /* The end of the crypto_info array matches our n_samples position,
5844 * so count backward from there */
5845 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5846 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5847 /* steal structure from array */
5848 crypto_info = g_ptr_array_index (info->crypto_info, index);
5849 g_ptr_array_index (info->crypto_info, index) = NULL;
5850 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5851 info->crypto_info->len);
5852 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5853 GST_ERROR_OBJECT (qtdemux,
5854 "failed to attach cenc metadata to buffer");
5856 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5857 index, stream->sample_index);
5862 if (stream->alignment > 1)
5863 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5865 ret = gst_pad_push (stream->pad, buf);
5867 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5868 /* mark position in stream, we'll need this to know when to send GAP event */
5869 stream->segment.position = pts + duration;
5876 static const QtDemuxRandomAccessEntry *
5877 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5878 GstClockTime pos, gboolean after)
5880 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5881 guint n_entries = stream->n_ra_entries;
5884 /* we assume the table is sorted */
5885 for (i = 0; i < n_entries; ++i) {
5886 if (entries[i].ts > pos)
5890 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5891 * probably okay to assume that the index lists the very first fragment */
5898 return &entries[i - 1];
5902 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5904 const QtDemuxRandomAccessEntry *best_entry = NULL;
5907 GST_OBJECT_LOCK (qtdemux);
5909 g_assert (qtdemux->n_streams > 0);
5911 /* first see if we can determine where to go to using mfra,
5912 * before we start clearing things */
5913 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5914 const QtDemuxRandomAccessEntry *entry;
5915 QtDemuxStream *stream;
5916 gboolean is_audio_or_video;
5918 stream = QTDEMUX_STREAM (iter->data);
5920 if (stream->ra_entries == NULL)
5923 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5924 is_audio_or_video = TRUE;
5926 is_audio_or_video = FALSE;
5929 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5930 stream->time_position, !is_audio_or_video);
5932 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5933 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5935 stream->pending_seek = entry;
5937 /* decide position to jump to just based on audio/video tracks, not subs */
5938 if (!is_audio_or_video)
5941 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5945 /* no luck, will handle seek otherwise */
5946 if (best_entry == NULL) {
5947 GST_OBJECT_UNLOCK (qtdemux);
5951 /* ok, now we can prepare for processing as of located moof */
5952 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5953 QtDemuxStream *stream;
5955 stream = QTDEMUX_STREAM (iter->data);
5957 g_free (stream->samples);
5958 stream->samples = NULL;
5959 stream->n_samples = 0;
5960 stream->stbl_index = -1; /* no samples have yet been parsed */
5961 stream->sample_index = -1;
5963 if (stream->protection_scheme_info) {
5964 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5965 if (stream->protection_scheme_type == FOURCC_cenc) {
5966 QtDemuxCencSampleSetInfo *info =
5967 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5968 if (info->crypto_info) {
5969 g_ptr_array_free (info->crypto_info, TRUE);
5970 info->crypto_info = NULL;
5976 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5977 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5978 GST_TIME_ARGS (QTDEMUX_FIRST_STREAM (qtdemux)->time_position),
5979 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5981 qtdemux->moof_offset = best_entry->moof_offset;
5983 qtdemux_add_fragmented_samples (qtdemux);
5985 GST_OBJECT_UNLOCK (qtdemux);
5989 static GstFlowReturn
5990 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5992 GstFlowReturn ret = GST_FLOW_OK;
5993 GstBuffer *buf = NULL;
5994 QtDemuxStream *stream, *target_stream = NULL;
5995 GstClockTime min_time;
5997 GstClockTime dts = GST_CLOCK_TIME_NONE;
5998 GstClockTime pts = GST_CLOCK_TIME_NONE;
5999 GstClockTime duration = 0;
6000 gboolean keyframe = FALSE;
6001 guint sample_size = 0;
6006 if (qtdemux->fragmented_seek_pending) {
6007 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6008 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6009 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6010 qtdemux->fragmented_seek_pending = FALSE;
6012 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6016 /* Figure out the next stream sample to output, min_time is expressed in
6017 * global time and runs over the edit list segments. */
6018 min_time = G_MAXUINT64;
6019 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6020 GstClockTime position;
6022 stream = QTDEMUX_STREAM (iter->data);
6023 position = stream->time_position;
6025 /* position of -1 is EOS */
6026 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6027 min_time = position;
6028 target_stream = stream;
6032 if (G_UNLIKELY (target_stream == NULL)) {
6033 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6037 /* check for segment end */
6038 if (G_UNLIKELY (qtdemux->segment.stop != -1
6039 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6040 || (qtdemux->segment.rate < 0
6041 && qtdemux->segment.start > min_time))
6042 && target_stream->on_keyframe)) {
6043 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6044 target_stream->time_position = GST_CLOCK_TIME_NONE;
6048 /* gap events for subtitle streams */
6049 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6050 stream = QTDEMUX_STREAM (iter->data);
6051 if (stream->pad && (stream->subtype == FOURCC_subp
6052 || stream->subtype == FOURCC_text
6053 || stream->subtype == FOURCC_sbtl)) {
6054 /* send one second gap events until the stream catches up */
6055 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6056 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6057 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6058 stream->segment.position + GST_SECOND < min_time) {
6060 gst_event_new_gap (stream->segment.position, GST_SECOND);
6061 gst_pad_push_event (stream->pad, gap);
6062 stream->segment.position += GST_SECOND;
6067 stream = target_stream;
6068 /* fetch info for the current sample of this stream */
6069 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6070 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6073 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6074 if (stream->new_caps) {
6075 gst_qtdemux_configure_stream (qtdemux, stream);
6076 qtdemux_do_allocation (qtdemux, stream);
6079 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6080 if (G_UNLIKELY (qtdemux->
6081 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6082 if (stream->subtype == FOURCC_vide && !keyframe) {
6083 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6089 GST_DEBUG_OBJECT (qtdemux,
6090 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6091 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6092 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6093 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6094 GST_TIME_ARGS (duration));
6096 if (G_UNLIKELY (empty)) {
6097 /* empty segment, push a gap if there's a second or more
6098 * difference and move to the next one */
6099 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6100 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6101 stream->segment.position = pts + duration;
6105 /* hmm, empty sample, skip and move to next sample */
6106 if (G_UNLIKELY (sample_size <= 0))
6109 /* last pushed sample was out of boundary, goto next sample */
6110 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6113 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6116 GST_DEBUG_OBJECT (qtdemux,
6117 "size %d larger than stream max_buffer_size %d, trimming",
6118 sample_size, stream->max_buffer_size);
6120 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6123 if (qtdemux->cenc_aux_info_offset > 0) {
6126 GstBuffer *aux_info = NULL;
6128 /* pull the data stored before the sample */
6130 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6131 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6132 if (G_UNLIKELY (ret != GST_FLOW_OK))
6134 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6135 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6136 gst_byte_reader_init (&br, map.data + 8, map.size);
6137 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6138 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6139 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6140 gst_buffer_unmap (aux_info, &map);
6141 gst_buffer_unref (aux_info);
6142 ret = GST_FLOW_ERROR;
6145 gst_buffer_unmap (aux_info, &map);
6146 gst_buffer_unref (aux_info);
6149 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6152 if (stream->use_allocator) {
6153 /* if we have a per-stream allocator, use it */
6154 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6157 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6159 if (G_UNLIKELY (ret != GST_FLOW_OK))
6162 if (size != sample_size) {
6163 pts += gst_util_uint64_scale_int (GST_SECOND,
6164 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6167 gst_util_uint64_scale_int (GST_SECOND,
6168 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6171 gst_util_uint64_scale_int (GST_SECOND,
6172 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6175 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6176 dts, pts, duration, keyframe, min_time, offset);
6178 if (size != sample_size) {
6179 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6180 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6182 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6184 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6185 if (time_position >= segment->media_start) {
6186 /* inside the segment, update time_position, looks very familiar to
6187 * GStreamer segments, doesn't it? */
6188 stream->time_position = (time_position - segment->media_start) +
6191 /* not yet in segment, time does not yet increment. This means
6192 * that we are still prerolling keyframes to the decoder so it can
6193 * decode the first sample of the segment. */
6194 stream->time_position = segment->time;
6199 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6200 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6201 * we have no more data for the pad to push */
6202 if (ret == GST_FLOW_EOS)
6205 stream->offset_in_sample += size;
6206 if (stream->offset_in_sample >= sample_size) {
6207 gst_qtdemux_advance_sample (qtdemux, stream);
6212 gst_qtdemux_advance_sample (qtdemux, stream);
6220 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6226 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6227 /* EOS will be raised if all are EOS */
6234 gst_qtdemux_loop (GstPad * pad)
6236 GstQTDemux *qtdemux;
6240 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6242 cur_offset = qtdemux->offset;
6243 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6244 cur_offset, qt_demux_state_string (qtdemux->state));
6246 switch (qtdemux->state) {
6247 case QTDEMUX_STATE_INITIAL:
6248 case QTDEMUX_STATE_HEADER:
6249 ret = gst_qtdemux_loop_state_header (qtdemux);
6251 case QTDEMUX_STATE_MOVIE:
6252 ret = gst_qtdemux_loop_state_movie (qtdemux);
6253 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6254 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6262 /* if something went wrong, pause */
6263 if (ret != GST_FLOW_OK)
6267 gst_object_unref (qtdemux);
6273 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6274 (NULL), ("streaming stopped, invalid state"));
6275 gst_pad_pause_task (pad);
6276 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6281 const gchar *reason = gst_flow_get_name (ret);
6283 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6285 gst_pad_pause_task (pad);
6287 /* fatal errors need special actions */
6289 if (ret == GST_FLOW_EOS) {
6290 if (qtdemux->n_streams == 0) {
6291 /* we have no streams, post an error */
6292 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6294 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6297 if ((stop = qtdemux->segment.stop) == -1)
6298 stop = qtdemux->segment.duration;
6300 if (qtdemux->segment.rate >= 0) {
6301 GstMessage *message;
6304 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6305 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6306 GST_FORMAT_TIME, stop);
6307 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6308 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6309 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6310 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6312 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6313 gst_qtdemux_push_event (qtdemux, event);
6315 GstMessage *message;
6318 /* For Reverse Playback */
6319 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6320 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6321 GST_FORMAT_TIME, qtdemux->segment.start);
6322 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6323 qtdemux->segment.start);
6324 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6325 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6326 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6328 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6329 gst_qtdemux_push_event (qtdemux, event);
6334 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6335 event = gst_event_new_eos ();
6336 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6337 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6338 gst_qtdemux_push_event (qtdemux, event);
6340 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6341 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6342 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6351 * Returns if there are samples to be played.
6354 has_next_entry (GstQTDemux * demux)
6356 QtDemuxStream *stream;
6359 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6361 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6362 stream = QTDEMUX_STREAM (iter->data);
6364 if (stream->sample_index == -1) {
6365 stream->sample_index = 0;
6366 stream->offset_in_sample = 0;
6369 if (stream->sample_index >= stream->n_samples) {
6370 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6373 GST_DEBUG_OBJECT (demux, "Found a sample");
6377 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6384 * Returns the size of the first entry at the current offset.
6385 * If -1, there are none (which means EOS or empty file).
6388 next_entry_size (GstQTDemux * demux)
6390 QtDemuxStream *stream, *target_stream = NULL;
6391 guint64 smalloffs = (guint64) - 1;
6392 QtDemuxSample *sample;
6395 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6398 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6399 stream = QTDEMUX_STREAM (iter->data);
6401 if (stream->sample_index == -1) {
6402 stream->sample_index = 0;
6403 stream->offset_in_sample = 0;
6406 if (stream->sample_index >= stream->n_samples) {
6407 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6411 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6412 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6413 stream->sample_index);
6417 sample = &stream->samples[stream->sample_index];
6419 GST_LOG_OBJECT (demux,
6420 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6421 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6422 stream->sample_index, sample->offset, sample->size);
6424 if (((smalloffs == -1)
6425 || (sample->offset < smalloffs)) && (sample->size)) {
6426 smalloffs = sample->offset;
6427 target_stream = stream;
6434 GST_LOG_OBJECT (demux,
6435 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6436 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6438 stream = target_stream;
6439 sample = &stream->samples[stream->sample_index];
6441 if (sample->offset >= demux->offset) {
6442 demux->todrop = sample->offset - demux->offset;
6443 return sample->size + demux->todrop;
6446 GST_DEBUG_OBJECT (demux,
6447 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6452 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6454 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6456 gst_element_post_message (GST_ELEMENT_CAST (demux),
6457 gst_message_new_element (GST_OBJECT_CAST (demux),
6458 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6462 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6467 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6470 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6471 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6472 GST_SEEK_TYPE_NONE, -1);
6474 /* store seqnum to drop flush events, they don't need to reach downstream */
6475 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6476 res = gst_pad_push_event (demux->sinkpad, event);
6477 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6482 /* check for seekable upstream, above and beyond a mere query */
6484 gst_qtdemux_check_seekability (GstQTDemux * demux)
6487 gboolean seekable = FALSE;
6488 gint64 start = -1, stop = -1;
6490 if (demux->upstream_size)
6493 if (demux->upstream_format_is_time)
6496 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6497 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6498 GST_DEBUG_OBJECT (demux, "seeking query failed");
6502 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6504 /* try harder to query upstream size if we didn't get it the first time */
6505 if (seekable && stop == -1) {
6506 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6507 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6510 /* if upstream doesn't know the size, it's likely that it's not seekable in
6511 * practice even if it technically may be seekable */
6512 if (seekable && (start != 0 || stop <= start)) {
6513 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6518 gst_query_unref (query);
6520 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6521 G_GUINT64_FORMAT ")", seekable, start, stop);
6522 demux->upstream_seekable = seekable;
6523 demux->upstream_size = seekable ? stop : -1;
6527 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6529 g_return_if_fail (bytes <= demux->todrop);
6531 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6532 gst_adapter_flush (demux->adapter, bytes);
6533 demux->neededbytes -= bytes;
6534 demux->offset += bytes;
6535 demux->todrop -= bytes;
6538 /* PUSH-MODE only: Send a segment, if not done already. */
6540 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6542 if (G_UNLIKELY (demux->need_segment)) {
6546 if (!demux->upstream_format_is_time) {
6547 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6549 GstEvent *segment_event;
6550 segment_event = gst_event_new_segment (&demux->segment);
6551 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6552 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6553 gst_qtdemux_push_event (demux, segment_event);
6556 demux->need_segment = FALSE;
6558 /* clear to send tags on all streams */
6559 for (iter = demux->active_streams, i = 0; iter;
6560 iter = g_list_next (iter), i++) {
6561 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6562 gst_qtdemux_push_tags (demux, stream);
6563 if (CUR_STREAM (stream)->sparse) {
6564 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6565 gst_pad_push_event (stream->pad,
6566 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6572 /* Used for push mode only. */
6574 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6575 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6577 GstClockTime ts, dur;
6581 stream->segments[segment_index].duration - (pos -
6582 stream->segments[segment_index].time);
6583 stream->time_position += dur;
6585 /* Only gaps with a duration of at least one second are propagated.
6586 * Same workaround as in pull mode.
6587 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6588 if (dur >= GST_SECOND) {
6590 gap = gst_event_new_gap (ts, dur);
6592 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6593 "segment: %" GST_PTR_FORMAT, gap);
6594 gst_pad_push_event (stream->pad, gap);
6598 static GstFlowReturn
6599 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6603 demux = GST_QTDEMUX (parent);
6605 GST_DEBUG_OBJECT (demux,
6606 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6607 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6608 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6609 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6610 gst_buffer_get_size (inbuf), demux->offset);
6612 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6613 gboolean is_gap_input = FALSE;
6616 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6618 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6619 QTDEMUX_STREAM (iter->data)->discont = TRUE;
6622 /* Check if we can land back on our feet in the case where upstream is
6623 * handling the seeking/pushing of samples with gaps in between (like
6624 * in the case of trick-mode DASH for example) */
6625 if (demux->upstream_format_is_time
6626 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6627 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6629 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6630 GST_LOG_OBJECT (demux,
6631 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6632 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6634 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6635 stream, GST_BUFFER_OFFSET (inbuf));
6637 QtDemuxSample *sample = &stream->samples[res];
6638 GST_LOG_OBJECT (demux,
6639 "Checking if sample %d from track-id %u is valid (offset:%"
6640 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6641 stream->track_id, sample->offset, sample->size);
6642 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6643 GST_LOG_OBJECT (demux,
6644 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6646 is_gap_input = TRUE;
6647 /* We can go back to standard playback mode */
6648 demux->state = QTDEMUX_STATE_MOVIE;
6649 /* Remember which sample this stream is at */
6650 stream->sample_index = res;
6651 /* Finally update all push-based values to the expected values */
6652 demux->neededbytes = stream->samples[res].size;
6653 demux->offset = GST_BUFFER_OFFSET (inbuf);
6655 demux->mdatsize - demux->offset + demux->mdatoffset;
6660 if (!is_gap_input) {
6661 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6662 /* Reset state if it's a real discont */
6663 demux->neededbytes = 16;
6664 demux->state = QTDEMUX_STATE_INITIAL;
6665 demux->offset = GST_BUFFER_OFFSET (inbuf);
6666 gst_adapter_clear (demux->adapter);
6669 /* Reverse fragmented playback, need to flush all we have before
6670 * consuming a new fragment.
6671 * The samples array have the timestamps calculated by accumulating the
6672 * durations but this won't work for reverse playback of fragments as
6673 * the timestamps of a subsequent fragment should be smaller than the
6674 * previously received one. */
6675 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6676 gst_qtdemux_process_adapter (demux, TRUE);
6677 g_list_foreach (demux->active_streams,
6678 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6682 gst_adapter_push (demux->adapter, inbuf);
6684 GST_DEBUG_OBJECT (demux,
6685 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6686 demux->neededbytes, gst_adapter_available (demux->adapter));
6688 return gst_qtdemux_process_adapter (demux, FALSE);
6691 static GstFlowReturn
6692 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6694 GstFlowReturn ret = GST_FLOW_OK;
6696 /* we never really mean to buffer that much */
6697 if (demux->neededbytes == -1) {
6701 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6702 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6704 #ifndef GST_DISABLE_GST_DEBUG
6706 guint64 discont_offset, distance_from_discont;
6708 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6709 distance_from_discont =
6710 gst_adapter_distance_from_discont (demux->adapter);
6712 GST_DEBUG_OBJECT (demux,
6713 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6714 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6715 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6716 demux->offset, discont_offset, distance_from_discont);
6720 switch (demux->state) {
6721 case QTDEMUX_STATE_INITIAL:{
6726 gst_qtdemux_check_seekability (demux);
6728 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6730 /* get fourcc/length, set neededbytes */
6731 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6733 gst_adapter_unmap (demux->adapter);
6735 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6736 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6738 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6739 (_("This file is invalid and cannot be played.")),
6740 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6741 GST_FOURCC_ARGS (fourcc)));
6742 ret = GST_FLOW_ERROR;
6745 if (fourcc == FOURCC_mdat) {
6746 gint next_entry = next_entry_size (demux);
6747 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6748 /* we have the headers, start playback */
6749 demux->state = QTDEMUX_STATE_MOVIE;
6750 demux->neededbytes = next_entry;
6751 demux->mdatleft = size;
6752 demux->mdatsize = demux->mdatleft;
6754 /* no headers yet, try to get them */
6757 guint64 old, target;
6760 old = demux->offset;
6761 target = old + size;
6763 /* try to jump over the atom with a seek */
6764 /* only bother if it seems worth doing so,
6765 * and avoids possible upstream/server problems */
6766 if (demux->upstream_seekable &&
6767 demux->upstream_size > 4 * (1 << 20)) {
6768 res = qtdemux_seek_offset (demux, target);
6770 GST_DEBUG_OBJECT (demux, "skipping seek");
6775 GST_DEBUG_OBJECT (demux, "seek success");
6776 /* remember the offset fo the first mdat so we can seek back to it
6777 * after we have the headers */
6778 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6779 demux->first_mdat = old;
6780 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6783 /* seek worked, continue reading */
6784 demux->offset = target;
6785 demux->neededbytes = 16;
6786 demux->state = QTDEMUX_STATE_INITIAL;
6788 /* seek failed, need to buffer */
6789 demux->offset = old;
6790 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6791 /* there may be multiple mdat (or alike) buffers */
6793 if (demux->mdatbuffer)
6794 bs = gst_buffer_get_size (demux->mdatbuffer);
6797 if (size + bs > 10 * (1 << 20))
6799 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6800 demux->neededbytes = size;
6801 if (!demux->mdatbuffer)
6802 demux->mdatoffset = demux->offset;
6805 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6806 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6807 (_("This file is invalid and cannot be played.")),
6808 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6809 GST_FOURCC_ARGS (fourcc), size));
6810 ret = GST_FLOW_ERROR;
6813 /* this means we already started buffering and still no moov header,
6814 * let's continue buffering everything till we get moov */
6815 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6816 || fourcc == FOURCC_moof))
6818 demux->neededbytes = size;
6819 demux->state = QTDEMUX_STATE_HEADER;
6823 case QTDEMUX_STATE_HEADER:{
6827 GST_DEBUG_OBJECT (demux, "In header");
6829 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6831 /* parse the header */
6832 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6834 if (fourcc == FOURCC_moov) {
6835 /* in usual fragmented setup we could try to scan for more
6836 * and end up at the the moov (after mdat) again */
6837 if (demux->got_moov && demux->n_streams > 0 &&
6839 || demux->last_moov_offset == demux->offset)) {
6840 GST_DEBUG_OBJECT (demux,
6841 "Skipping moov atom as we have (this) one already");
6843 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6845 if (demux->got_moov && demux->fragmented) {
6846 GST_DEBUG_OBJECT (demux,
6847 "Got a second moov, clean up data from old one");
6848 if (demux->moov_node_compressed) {
6849 g_node_destroy (demux->moov_node_compressed);
6850 if (demux->moov_node)
6851 g_free (demux->moov_node->data);
6853 demux->moov_node_compressed = NULL;
6854 if (demux->moov_node)
6855 g_node_destroy (demux->moov_node);
6856 demux->moov_node = NULL;
6859 demux->last_moov_offset = demux->offset;
6861 /* Update streams with new moov */
6862 demux->old_streams =
6863 g_list_concat (demux->old_streams, demux->active_streams);
6864 demux->active_streams = NULL;
6866 qtdemux_parse_moov (demux, data, demux->neededbytes);
6867 qtdemux_node_dump (demux, demux->moov_node);
6868 qtdemux_parse_tree (demux);
6869 qtdemux_prepare_streams (demux);
6870 QTDEMUX_EXPOSE_LOCK (demux);
6871 qtdemux_expose_streams (demux);
6872 QTDEMUX_EXPOSE_UNLOCK (demux);
6874 demux->got_moov = TRUE;
6876 gst_qtdemux_check_send_pending_segment (demux);
6878 if (demux->moov_node_compressed) {
6879 g_node_destroy (demux->moov_node_compressed);
6880 g_free (demux->moov_node->data);
6882 demux->moov_node_compressed = NULL;
6883 g_node_destroy (demux->moov_node);
6884 demux->moov_node = NULL;
6885 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6887 } else if (fourcc == FOURCC_moof) {
6888 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6890 GstClockTime prev_pts;
6891 guint64 prev_offset;
6892 guint64 adapter_discont_offset, adapter_discont_dist;
6894 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6897 * The timestamp of the moof buffer is relevant as some scenarios
6898 * won't have the initial timestamp in the atoms. Whenever a new
6899 * buffer has started, we get that buffer's PTS and use it as a base
6900 * timestamp for the trun entries.
6902 * To keep track of the current buffer timestamp and starting point
6903 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6904 * from the beggining of the buffer, with the distance and demux->offset
6905 * we know if it is still the same buffer or not.
6907 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6908 prev_offset = demux->offset - dist;
6909 if (demux->fragment_start_offset == -1
6910 || prev_offset > demux->fragment_start_offset) {
6911 demux->fragment_start_offset = prev_offset;
6912 demux->fragment_start = prev_pts;
6913 GST_DEBUG_OBJECT (demux,
6914 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6915 GST_TIME_FORMAT, demux->fragment_start_offset,
6916 GST_TIME_ARGS (demux->fragment_start));
6919 /* We can't use prev_offset() here because this would require
6920 * upstream to set consistent and correct offsets on all buffers
6921 * since the discont. Nothing ever did that in the past and we
6922 * would break backwards compatibility here then.
6923 * Instead take the offset we had at the last discont and count
6924 * the bytes from there. This works with old code as there would
6925 * be no discont between moov and moof, and also works with
6926 * adaptivedemux which correctly sets offset and will set the
6927 * DISCONT flag accordingly when needed.
6929 * We also only do this for upstream TIME segments as otherwise
6930 * there are potential backwards compatibility problems with
6931 * seeking in PUSH mode and upstream providing inconsistent
6933 adapter_discont_offset =
6934 gst_adapter_offset_at_discont (demux->adapter);
6935 adapter_discont_dist =
6936 gst_adapter_distance_from_discont (demux->adapter);
6938 GST_DEBUG_OBJECT (demux,
6939 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6940 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6941 demux->offset, adapter_discont_offset, adapter_discont_dist);
6943 if (demux->upstream_format_is_time) {
6944 demux->moof_offset = adapter_discont_offset;
6945 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6946 demux->moof_offset += adapter_discont_dist;
6947 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6948 demux->moof_offset = demux->offset;
6950 demux->moof_offset = demux->offset;
6953 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6954 demux->moof_offset, NULL)) {
6955 gst_adapter_unmap (demux->adapter);
6956 ret = GST_FLOW_ERROR;
6960 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6961 if (demux->mss_mode && !demux->exposed) {
6962 QTDEMUX_EXPOSE_LOCK (demux);
6963 qtdemux_expose_streams (demux);
6964 QTDEMUX_EXPOSE_UNLOCK (demux);
6967 gst_qtdemux_check_send_pending_segment (demux);
6969 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6971 } else if (fourcc == FOURCC_ftyp) {
6972 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6973 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6974 } else if (fourcc == FOURCC_uuid) {
6975 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6976 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6977 } else if (fourcc == FOURCC_sidx) {
6978 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6979 qtdemux_parse_sidx (demux, data, demux->neededbytes);
6983 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
6987 /* [free] and [skip] are padding atoms */
6988 GST_DEBUG_OBJECT (demux,
6989 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
6990 GST_FOURCC_ARGS (fourcc));
6993 GST_WARNING_OBJECT (demux,
6994 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6995 GST_FOURCC_ARGS (fourcc));
6996 /* Let's jump that one and go back to initial state */
7000 gst_adapter_unmap (demux->adapter);
7003 if (demux->mdatbuffer && demux->n_streams) {
7004 gsize remaining_data_size = 0;
7006 /* the mdat was before the header */
7007 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7008 demux->n_streams, demux->mdatbuffer);
7009 /* restore our adapter/offset view of things with upstream;
7010 * put preceding buffered data ahead of current moov data.
7011 * This should also handle evil mdat, moov, mdat cases and alike */
7012 gst_adapter_flush (demux->adapter, demux->neededbytes);
7014 /* Store any remaining data after the mdat for later usage */
7015 remaining_data_size = gst_adapter_available (demux->adapter);
7016 if (remaining_data_size > 0) {
7017 g_assert (demux->restoredata_buffer == NULL);
7018 demux->restoredata_buffer =
7019 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7020 demux->restoredata_offset = demux->offset + demux->neededbytes;
7021 GST_DEBUG_OBJECT (demux,
7022 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7023 G_GUINT64_FORMAT, remaining_data_size,
7024 demux->restoredata_offset);
7027 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7028 demux->mdatbuffer = NULL;
7029 demux->offset = demux->mdatoffset;
7030 demux->neededbytes = next_entry_size (demux);
7031 demux->state = QTDEMUX_STATE_MOVIE;
7032 demux->mdatleft = gst_adapter_available (demux->adapter);
7033 demux->mdatsize = demux->mdatleft;
7035 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7036 gst_adapter_flush (demux->adapter, demux->neededbytes);
7038 /* only go back to the mdat if there are samples to play */
7039 if (demux->got_moov && demux->first_mdat != -1
7040 && has_next_entry (demux)) {
7043 /* we need to seek back */
7044 res = qtdemux_seek_offset (demux, demux->first_mdat);
7046 demux->offset = demux->first_mdat;
7048 GST_DEBUG_OBJECT (demux, "Seek back failed");
7051 demux->offset += demux->neededbytes;
7053 demux->neededbytes = 16;
7054 demux->state = QTDEMUX_STATE_INITIAL;
7059 case QTDEMUX_STATE_BUFFER_MDAT:{
7063 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7065 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7066 gst_buffer_extract (buf, 0, fourcc, 4);
7067 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7068 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7069 if (demux->mdatbuffer)
7070 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7072 demux->mdatbuffer = buf;
7073 demux->offset += demux->neededbytes;
7074 demux->neededbytes = 16;
7075 demux->state = QTDEMUX_STATE_INITIAL;
7076 gst_qtdemux_post_progress (demux, 1, 1);
7080 case QTDEMUX_STATE_MOVIE:{
7081 QtDemuxStream *stream = NULL;
7082 QtDemuxSample *sample;
7083 GstClockTime dts, pts, duration;
7087 GST_DEBUG_OBJECT (demux,
7088 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7090 if (demux->fragmented) {
7091 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7093 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7094 /* if needed data starts within this atom,
7095 * then it should not exceed this atom */
7096 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7097 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7098 (_("This file is invalid and cannot be played.")),
7099 ("sample data crosses atom boundary"));
7100 ret = GST_FLOW_ERROR;
7103 demux->mdatleft -= demux->neededbytes;
7105 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7106 /* so we are dropping more than left in this atom */
7107 gst_qtdemux_drop_data (demux, demux->mdatleft);
7108 demux->mdatleft = 0;
7110 /* need to resume atom parsing so we do not miss any other pieces */
7111 demux->state = QTDEMUX_STATE_INITIAL;
7112 demux->neededbytes = 16;
7114 /* check if there was any stored post mdat data from previous buffers */
7115 if (demux->restoredata_buffer) {
7116 g_assert (gst_adapter_available (demux->adapter) == 0);
7118 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7119 demux->restoredata_buffer = NULL;
7120 demux->offset = demux->restoredata_offset;
7127 if (demux->todrop) {
7128 if (demux->cenc_aux_info_offset > 0) {
7132 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7133 data = gst_adapter_map (demux->adapter, demux->todrop);
7134 gst_byte_reader_init (&br, data + 8, demux->todrop);
7135 if (!qtdemux_parse_cenc_aux_info (demux,
7136 QTDEMUX_FIRST_STREAM (demux), &br,
7137 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7138 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7139 ret = GST_FLOW_ERROR;
7140 gst_adapter_unmap (demux->adapter);
7141 g_free (demux->cenc_aux_info_sizes);
7142 demux->cenc_aux_info_sizes = NULL;
7145 demux->cenc_aux_info_offset = 0;
7146 g_free (demux->cenc_aux_info_sizes);
7147 demux->cenc_aux_info_sizes = NULL;
7148 gst_adapter_unmap (demux->adapter);
7150 gst_qtdemux_drop_data (demux, demux->todrop);
7154 /* initial newsegment sent here after having added pads,
7155 * possible others in sink_event */
7156 gst_qtdemux_check_send_pending_segment (demux);
7158 /* Figure out which stream this packet belongs to */
7159 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7160 stream = QTDEMUX_STREAM (iter->data);
7161 if (stream->sample_index >= stream->n_samples) {
7162 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7166 GST_LOG_OBJECT (demux,
7167 "Checking track-id %u (sample_index:%d / offset:%"
7168 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7169 stream->sample_index,
7170 stream->samples[stream->sample_index].offset,
7171 stream->samples[stream->sample_index].size);
7173 if (stream->samples[stream->sample_index].offset == demux->offset)
7177 if (G_UNLIKELY (stream == NULL))
7178 goto unknown_stream;
7180 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7182 if (stream->new_caps) {
7183 gst_qtdemux_configure_stream (demux, stream);
7186 /* Put data in a buffer, set timestamps, caps, ... */
7187 sample = &stream->samples[stream->sample_index];
7189 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7190 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7191 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7193 dts = QTSAMPLE_DTS (stream, sample);
7194 pts = QTSAMPLE_PTS (stream, sample);
7195 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7196 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7198 /* check for segment end */
7199 if (G_UNLIKELY (demux->segment.stop != -1
7200 && demux->segment.stop <= pts && stream->on_keyframe)
7201 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7202 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7203 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7205 /* skip this data, stream is EOS */
7206 gst_adapter_flush (demux->adapter, demux->neededbytes);
7207 demux->offset += demux->neededbytes;
7209 /* check if all streams are eos */
7211 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7212 if (!STREAM_IS_EOS (QTDEMUX_STREAM (iter->data))) {
7221 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7223 /* FIXME: should either be an assert or a plain check */
7224 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7226 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7227 dts, pts, duration, keyframe, dts, demux->offset);
7231 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7233 /* skip this data, stream is EOS */
7234 gst_adapter_flush (demux->adapter, demux->neededbytes);
7237 stream->sample_index++;
7238 stream->offset_in_sample = 0;
7240 /* update current offset and figure out size of next buffer */
7241 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7242 demux->offset, demux->neededbytes);
7243 demux->offset += demux->neededbytes;
7244 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7248 if (ret == GST_FLOW_EOS) {
7249 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7250 demux->neededbytes = -1;
7254 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7255 if (demux->fragmented) {
7256 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7257 /* there may be more to follow, only finish this atom */
7258 demux->todrop = demux->mdatleft;
7259 demux->neededbytes = demux->todrop;
7264 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7265 goto non_ok_unlinked_flow;
7274 /* when buffering movie data, at least show user something is happening */
7275 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7276 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7277 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7278 demux->neededbytes);
7285 non_ok_unlinked_flow:
7287 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7288 gst_flow_get_name (ret));
7293 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7294 ret = GST_FLOW_ERROR;
7299 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7305 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7306 (NULL), ("qtdemuxer invalid state %d", demux->state));
7307 ret = GST_FLOW_ERROR;
7312 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7313 (NULL), ("no 'moov' atom within the first 10 MB"));
7314 ret = GST_FLOW_ERROR;
7320 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7325 query = gst_query_new_scheduling ();
7327 if (!gst_pad_peer_query (sinkpad, query)) {
7328 gst_query_unref (query);
7332 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7333 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7334 gst_query_unref (query);
7339 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7340 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7344 GST_DEBUG_OBJECT (sinkpad, "activating push");
7345 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7350 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7351 GstPadMode mode, gboolean active)
7354 GstQTDemux *demux = GST_QTDEMUX (parent);
7357 case GST_PAD_MODE_PUSH:
7358 demux->pullbased = FALSE;
7361 case GST_PAD_MODE_PULL:
7363 demux->pullbased = TRUE;
7364 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7367 res = gst_pad_stop_task (sinkpad);
7379 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7385 memset (&z, 0, sizeof (z));
7390 if ((ret = inflateInit (&z)) != Z_OK) {
7391 GST_ERROR ("inflateInit() returned %d", ret);
7395 z.next_in = z_buffer;
7396 z.avail_in = z_length;
7398 buffer = (guint8 *) g_malloc (*length);
7399 z.avail_out = *length;
7400 z.next_out = (Bytef *) buffer;
7402 ret = inflate (&z, Z_NO_FLUSH);
7403 if (ret == Z_STREAM_END) {
7405 } else if (ret != Z_OK) {
7406 GST_WARNING ("inflate() returned %d", ret);
7411 buffer = (guint8 *) g_realloc (buffer, *length);
7412 z.next_out = (Bytef *) (buffer + z.total_out);
7413 z.avail_out += 4096;
7414 } while (z.avail_in > 0);
7416 if (ret != Z_STREAM_END) {
7421 *length = z.total_out;
7428 #endif /* HAVE_ZLIB */
7431 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7435 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7437 /* counts as header data */
7438 qtdemux->header_size += length;
7440 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7441 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7443 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7450 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7451 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7452 if (dcom == NULL || cmvd == NULL)
7453 goto invalid_compression;
7455 dcom_len = QT_UINT32 (dcom->data);
7457 goto invalid_compression;
7459 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7463 guint uncompressed_length;
7464 guint compressed_length;
7468 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7470 goto invalid_compression;
7472 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7473 compressed_length = cmvd_len - 12;
7474 GST_LOG ("length = %u", uncompressed_length);
7477 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7478 compressed_length, &uncompressed_length);
7481 qtdemux->moov_node_compressed = qtdemux->moov_node;
7482 qtdemux->moov_node = g_node_new (buf);
7484 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7485 uncompressed_length);
7489 #endif /* HAVE_ZLIB */
7491 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7492 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7499 invalid_compression:
7501 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7507 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7510 while (G_UNLIKELY (buf < end)) {
7514 if (G_UNLIKELY (buf + 4 > end)) {
7515 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7518 len = QT_UINT32 (buf);
7519 if (G_UNLIKELY (len == 0)) {
7520 GST_LOG_OBJECT (qtdemux, "empty container");
7523 if (G_UNLIKELY (len < 8)) {
7524 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7527 if (G_UNLIKELY (len > (end - buf))) {
7528 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7529 (gint) (end - buf));
7533 child = g_node_new ((guint8 *) buf);
7534 g_node_append (node, child);
7535 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7536 qtdemux_parse_node (qtdemux, child, buf, len);
7544 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7547 int len = QT_UINT32 (xdxt->data);
7548 guint8 *buf = xdxt->data;
7549 guint8 *end = buf + len;
7552 /* skip size and type */
7560 size = QT_UINT32 (buf);
7561 type = QT_FOURCC (buf + 4);
7563 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7565 if (buf + size > end || size <= 0)
7571 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7572 GST_FOURCC_ARGS (type));
7576 buffer = gst_buffer_new_and_alloc (size);
7577 gst_buffer_fill (buffer, 0, buf, size);
7578 stream->buffers = g_slist_append (stream->buffers, buffer);
7579 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7582 buffer = gst_buffer_new_and_alloc (size);
7583 gst_buffer_fill (buffer, 0, buf, size);
7584 stream->buffers = g_slist_append (stream->buffers, buffer);
7585 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7588 buffer = gst_buffer_new_and_alloc (size);
7589 gst_buffer_fill (buffer, 0, buf, size);
7590 stream->buffers = g_slist_append (stream->buffers, buffer);
7591 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7594 GST_WARNING_OBJECT (qtdemux,
7595 "unknown theora cookie %" GST_FOURCC_FORMAT,
7596 GST_FOURCC_ARGS (type));
7605 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7609 guint32 node_length = 0;
7610 const QtNodeType *type;
7613 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7615 if (G_UNLIKELY (length < 8))
7616 goto not_enough_data;
7618 node_length = QT_UINT32 (buffer);
7619 fourcc = QT_FOURCC (buffer + 4);
7621 /* ignore empty nodes */
7622 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7625 type = qtdemux_type_get (fourcc);
7627 end = buffer + length;
7629 GST_LOG_OBJECT (qtdemux,
7630 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7631 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7633 if (node_length > length)
7634 goto broken_atom_size;
7636 if (type->flags & QT_FLAG_CONTAINER) {
7637 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7642 if (node_length < 20) {
7643 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7646 GST_DEBUG_OBJECT (qtdemux,
7647 "parsing stsd (sample table, sample description) atom");
7648 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7649 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7660 /* also read alac (or whatever) in stead of mp4a in the following,
7661 * since a similar layout is used in other cases as well */
7662 if (fourcc == FOURCC_mp4a)
7664 else if (fourcc == FOURCC_fLaC)
7669 /* There are two things we might encounter here: a true mp4a atom, and
7670 an mp4a entry in an stsd atom. The latter is what we're interested
7671 in, and it looks like an atom, but isn't really one. The true mp4a
7672 atom is short, so we detect it based on length here. */
7673 if (length < min_size) {
7674 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7675 GST_FOURCC_ARGS (fourcc));
7679 /* 'version' here is the sound sample description version. Types 0 and
7680 1 are documented in the QTFF reference, but type 2 is not: it's
7681 described in Apple header files instead (struct SoundDescriptionV2
7683 version = QT_UINT16 (buffer + 16);
7685 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7686 GST_FOURCC_ARGS (fourcc), version);
7688 /* parse any esds descriptors */
7700 GST_WARNING_OBJECT (qtdemux,
7701 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7702 GST_FOURCC_ARGS (fourcc), version);
7707 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7733 /* codec_data is contained inside these atoms, which all have
7734 * the same format. */
7735 /* video sample description size is 86 bytes without extension.
7736 * node_length have to be bigger than 86 bytes because video sample
7737 * description can include extenstions such as esds, fiel, glbl, etc. */
7738 if (node_length < 86) {
7739 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7740 " sample description length too short (%u < 86)",
7741 GST_FOURCC_ARGS (fourcc), node_length);
7745 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7746 GST_FOURCC_ARGS (fourcc));
7748 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7750 * revision level (2 bytes) : must be set to 0. */
7751 version = QT_UINT32 (buffer + 16);
7752 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7754 /* compressor name : PASCAL string and informative purposes
7755 * first byte : the number of bytes to be displayed.
7756 * it has to be less than 32 because it is reserved
7757 * space of 32 bytes total including itself. */
7758 str_len = QT_UINT8 (buffer + 50);
7760 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7761 (char *) buffer + 51);
7763 GST_WARNING_OBJECT (qtdemux,
7764 "compressorname length too big (%u > 31)", str_len);
7766 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7768 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7773 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7775 /* You are reading this correctly. QTFF specifies that the
7776 * metadata atom is a short atom, whereas ISO BMFF specifies
7777 * it's a full atom. But since so many people are doing things
7778 * differently, we actually peek into the atom to see which
7781 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7782 GST_FOURCC_ARGS (fourcc));
7785 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7786 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7787 * starts with a 'hdlr' atom */
7788 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7789 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7790 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7791 * with version/flags both set to zero */
7792 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7794 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7799 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7800 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7801 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7810 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7811 GST_FOURCC_ARGS (fourcc));
7815 version = QT_UINT32 (buffer + 12);
7816 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7823 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7828 if (length < offset) {
7829 GST_WARNING_OBJECT (qtdemux,
7830 "skipping too small %" GST_FOURCC_FORMAT " box",
7831 GST_FOURCC_ARGS (fourcc));
7834 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7840 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7845 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7850 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7854 if (!strcmp (type->name, "unknown"))
7855 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7859 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7860 GST_FOURCC_ARGS (fourcc));
7866 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7867 (_("This file is corrupt and cannot be played.")),
7868 ("Not enough data for an atom header, got only %u bytes", length));
7873 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7874 (_("This file is corrupt and cannot be played.")),
7875 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7876 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7883 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7887 guint32 child_fourcc;
7889 for (child = g_node_first_child (node); child;
7890 child = g_node_next_sibling (child)) {
7891 buffer = (guint8 *) child->data;
7893 child_fourcc = QT_FOURCC (buffer + 4);
7895 if (G_UNLIKELY (child_fourcc == fourcc)) {
7903 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7904 GstByteReader * parser)
7908 guint32 child_fourcc, child_len;
7910 for (child = g_node_first_child (node); child;
7911 child = g_node_next_sibling (child)) {
7912 buffer = (guint8 *) child->data;
7914 child_len = QT_UINT32 (buffer);
7915 child_fourcc = QT_FOURCC (buffer + 4);
7917 if (G_UNLIKELY (child_fourcc == fourcc)) {
7918 if (G_UNLIKELY (child_len < (4 + 4)))
7920 /* FIXME: must verify if atom length < parent atom length */
7921 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7929 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7931 return g_node_nth_child (node, index);
7935 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7936 GstByteReader * parser)
7940 guint32 child_fourcc, child_len;
7942 for (child = g_node_next_sibling (node); child;
7943 child = g_node_next_sibling (child)) {
7944 buffer = (guint8 *) child->data;
7946 child_fourcc = QT_FOURCC (buffer + 4);
7948 if (child_fourcc == fourcc) {
7950 child_len = QT_UINT32 (buffer);
7951 if (G_UNLIKELY (child_len < (4 + 4)))
7953 /* FIXME: must verify if atom length < parent atom length */
7954 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7963 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7965 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7969 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7971 /* FIXME: This can only reliably work if demuxers have a
7972 * separate streaming thread per srcpad. This should be
7973 * done in a demuxer base class, which integrates parts
7976 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7981 query = gst_query_new_allocation (stream->caps, FALSE);
7983 if (!gst_pad_peer_query (stream->pad, query)) {
7984 /* not a problem, just debug a little */
7985 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7988 if (stream->allocator)
7989 gst_object_unref (stream->allocator);
7991 if (gst_query_get_n_allocation_params (query) > 0) {
7992 /* try the allocator */
7993 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7995 stream->use_allocator = TRUE;
7997 stream->allocator = NULL;
7998 gst_allocation_params_init (&stream->params);
7999 stream->use_allocator = FALSE;
8001 gst_query_unref (query);
8006 pad_query (const GValue * item, GValue * value, gpointer user_data)
8008 GstPad *pad = g_value_get_object (item);
8009 GstQuery *query = user_data;
8012 res = gst_pad_peer_query (pad, query);
8015 g_value_set_boolean (value, TRUE);
8019 GST_INFO_OBJECT (pad, "pad peer query failed");
8024 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8025 GstPadDirection direction)
8028 GstIteratorFoldFunction func = pad_query;
8029 GValue res = { 0, };
8031 g_value_init (&res, G_TYPE_BOOLEAN);
8032 g_value_set_boolean (&res, FALSE);
8035 if (direction == GST_PAD_SRC)
8036 it = gst_element_iterate_src_pads (element);
8038 it = gst_element_iterate_sink_pads (element);
8040 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8041 gst_iterator_resync (it);
8043 gst_iterator_free (it);
8045 return g_value_get_boolean (&res);
8049 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8050 QtDemuxStream * stream)
8054 GstElement *element = GST_ELEMENT (qtdemux);
8056 gchar **filtered_sys_ids;
8057 GValue event_list = G_VALUE_INIT;
8060 /* 1. Check if we already have the context. */
8061 if (qtdemux->preferred_protection_system_id != NULL) {
8062 GST_LOG_OBJECT (element,
8063 "already have the protection context, no need to request it again");
8067 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8068 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8069 (const gchar **) qtdemux->protection_system_ids->pdata);
8071 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8072 qtdemux->protection_system_ids->len - 1);
8073 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8074 "decryptors for %u of them, running context request",
8075 qtdemux->protection_system_ids->len, g_strv_length (filtered_sys_ids));
8077 if (stream->protection_scheme_event_queue.length) {
8078 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8079 stream->protection_scheme_event_queue.length);
8080 walk = stream->protection_scheme_event_queue.tail;
8082 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8083 qtdemux->protection_event_queue.length);
8084 walk = qtdemux->protection_event_queue.tail;
8087 g_value_init (&event_list, GST_TYPE_LIST);
8088 for (; walk; walk = g_list_previous (walk)) {
8089 GValue *event_value = g_new0 (GValue, 1);
8090 g_value_init (event_value, GST_TYPE_EVENT);
8091 g_value_set_boxed (event_value, walk->data);
8092 gst_value_list_append_and_take_value (&event_list, event_value);
8095 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8096 * check if downstream already has a context of the specific type
8097 * 2b) Query upstream as above.
8099 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8100 st = gst_query_writable_structure (query);
8101 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8102 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8104 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8105 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8106 gst_query_parse_context (query, &ctxt);
8107 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8108 gst_element_set_context (element, ctxt);
8109 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8110 gst_query_parse_context (query, &ctxt);
8111 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8112 gst_element_set_context (element, ctxt);
8114 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8115 * the required context type and afterwards check if a
8116 * usable context was set now as in 1). The message could
8117 * be handled by the parent bins of the element and the
8122 GST_INFO_OBJECT (element, "posting need context message");
8123 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8124 "drm-preferred-decryption-system-id");
8125 st = (GstStructure *) gst_message_get_structure (msg);
8126 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8127 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8130 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8131 gst_element_post_message (element, msg);
8134 g_strfreev (filtered_sys_ids);
8135 g_value_unset (&event_list);
8136 gst_query_unref (query);
8140 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8141 QtDemuxStream * stream)
8144 const gchar *selected_system = NULL;
8146 g_return_val_if_fail (qtdemux != NULL, FALSE);
8147 g_return_val_if_fail (stream != NULL, FALSE);
8148 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8151 if (stream->protection_scheme_type != FOURCC_cenc) {
8152 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
8155 if (qtdemux->protection_system_ids == NULL) {
8156 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8157 "cenc protection system information has been found");
8161 gst_qtdemux_request_protection_context (qtdemux, stream);
8162 if (qtdemux->preferred_protection_system_id != NULL) {
8163 const gchar *preferred_system_array[] =
8164 { qtdemux->preferred_protection_system_id, NULL };
8166 selected_system = gst_protection_select_system (preferred_system_array);
8168 if (selected_system) {
8169 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8170 qtdemux->preferred_protection_system_id);
8172 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8173 "because there is no available decryptor",
8174 qtdemux->preferred_protection_system_id);
8178 if (!selected_system) {
8179 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8180 selected_system = gst_protection_select_system ((const gchar **)
8181 qtdemux->protection_system_ids->pdata);
8182 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8183 qtdemux->protection_system_ids->len - 1);
8186 if (!selected_system) {
8187 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8188 "suitable decryptor element has been found");
8192 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8195 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8196 if (!gst_structure_has_name (s, "application/x-cenc")) {
8197 gst_structure_set (s,
8198 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8199 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8201 gst_structure_set_name (s, "application/x-cenc");
8207 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8209 if (stream->subtype == FOURCC_vide) {
8210 /* fps is calculated base on the duration of the average framerate since
8211 * qt does not have a fixed framerate. */
8212 gboolean fps_available = TRUE;
8213 guint32 first_duration = 0;
8215 if (stream->n_samples > 0)
8216 first_duration = stream->samples[0].duration;
8218 if ((stream->n_samples == 1 && first_duration == 0)
8219 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8221 CUR_STREAM (stream)->fps_n = 0;
8222 CUR_STREAM (stream)->fps_d = 1;
8224 if (stream->duration == 0 || stream->n_samples < 2) {
8225 CUR_STREAM (stream)->fps_n = stream->timescale;
8226 CUR_STREAM (stream)->fps_d = 1;
8227 fps_available = FALSE;
8229 GstClockTime avg_duration;
8233 /* duration and n_samples can be updated for fragmented format
8234 * so, framerate of fragmented format is calculated using data in a moof */
8235 if (qtdemux->fragmented && stream->n_samples_moof > 0
8236 && stream->duration_moof > 0) {
8237 n_samples = stream->n_samples_moof;
8238 duration = stream->duration_moof;
8240 n_samples = stream->n_samples;
8241 duration = stream->duration;
8244 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8245 /* stream->duration is guint64, timescale, n_samples are guint32 */
8247 gst_util_uint64_scale_round (duration -
8248 first_duration, GST_SECOND,
8249 (guint64) (stream->timescale) * (n_samples - 1));
8251 GST_LOG_OBJECT (qtdemux,
8252 "Calculating avg sample duration based on stream (or moof) duration %"
8254 " minus first sample %u, leaving %d samples gives %"
8255 GST_TIME_FORMAT, duration, first_duration,
8256 n_samples - 1, GST_TIME_ARGS (avg_duration));
8258 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8259 &CUR_STREAM (stream)->fps_d);
8261 GST_DEBUG_OBJECT (qtdemux,
8262 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8263 stream->timescale, CUR_STREAM (stream)->fps_n,
8264 CUR_STREAM (stream)->fps_d);
8268 if (CUR_STREAM (stream)->caps) {
8269 CUR_STREAM (stream)->caps =
8270 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8272 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8273 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8274 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8276 /* set framerate if calculated framerate is reliable */
8277 if (fps_available) {
8278 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8279 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8280 CUR_STREAM (stream)->fps_d, NULL);
8283 /* calculate pixel-aspect-ratio using display width and height */
8284 GST_DEBUG_OBJECT (qtdemux,
8285 "video size %dx%d, target display size %dx%d",
8286 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8287 stream->display_width, stream->display_height);
8288 /* qt file might have pasp atom */
8289 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8290 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8291 CUR_STREAM (stream)->par_h);
8292 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8293 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8294 CUR_STREAM (stream)->par_h, NULL);
8295 } else if (stream->display_width > 0 && stream->display_height > 0
8296 && CUR_STREAM (stream)->width > 0
8297 && CUR_STREAM (stream)->height > 0) {
8300 /* calculate the pixel aspect ratio using the display and pixel w/h */
8301 n = stream->display_width * CUR_STREAM (stream)->height;
8302 d = stream->display_height * CUR_STREAM (stream)->width;
8305 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8306 CUR_STREAM (stream)->par_w = n;
8307 CUR_STREAM (stream)->par_h = d;
8308 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8309 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8310 CUR_STREAM (stream)->par_h, NULL);
8313 if (CUR_STREAM (stream)->interlace_mode > 0) {
8314 if (CUR_STREAM (stream)->interlace_mode == 1) {
8315 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8316 G_TYPE_STRING, "progressive", NULL);
8317 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8318 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8319 G_TYPE_STRING, "interleaved", NULL);
8320 if (CUR_STREAM (stream)->field_order == 9) {
8321 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8322 G_TYPE_STRING, "top-field-first", NULL);
8323 } else if (CUR_STREAM (stream)->field_order == 14) {
8324 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8325 G_TYPE_STRING, "bottom-field-first", NULL);
8330 /* Create incomplete colorimetry here if needed */
8331 if (CUR_STREAM (stream)->colorimetry.range ||
8332 CUR_STREAM (stream)->colorimetry.matrix ||
8333 CUR_STREAM (stream)->colorimetry.transfer
8334 || CUR_STREAM (stream)->colorimetry.primaries) {
8335 gchar *colorimetry =
8336 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8337 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8338 G_TYPE_STRING, colorimetry, NULL);
8339 g_free (colorimetry);
8342 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8343 guint par_w = 1, par_h = 1;
8345 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8346 par_w = CUR_STREAM (stream)->par_w;
8347 par_h = CUR_STREAM (stream)->par_h;
8350 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8351 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8353 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8356 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8357 "multiview-mode", G_TYPE_STRING,
8358 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8359 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8360 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8365 else if (stream->subtype == FOURCC_soun) {
8366 if (CUR_STREAM (stream)->caps) {
8367 CUR_STREAM (stream)->caps =
8368 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8369 if (CUR_STREAM (stream)->rate > 0)
8370 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8371 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8372 if (CUR_STREAM (stream)->n_channels > 0)
8373 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8374 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8375 if (CUR_STREAM (stream)->n_channels > 2) {
8376 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8377 * correctly; this is just the minimum we can do - assume
8378 * we don't actually have any channel positions. */
8379 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8380 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8386 GstCaps *prev_caps = NULL;
8388 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8389 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8390 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8391 gst_pad_set_active (stream->pad, TRUE);
8393 gst_pad_use_fixed_caps (stream->pad);
8395 if (stream->protected) {
8396 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8397 GST_ERROR_OBJECT (qtdemux,
8398 "Failed to configure protected stream caps.");
8403 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8404 CUR_STREAM (stream)->caps);
8405 if (stream->new_stream) {
8407 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8410 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8413 gst_event_parse_stream_flags (event, &stream_flags);
8414 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8415 qtdemux->have_group_id = TRUE;
8417 qtdemux->have_group_id = FALSE;
8418 gst_event_unref (event);
8419 } else if (!qtdemux->have_group_id) {
8420 qtdemux->have_group_id = TRUE;
8421 qtdemux->group_id = gst_util_group_id_next ();
8424 stream->new_stream = FALSE;
8425 event = gst_event_new_stream_start (stream->stream_id);
8426 if (qtdemux->have_group_id)
8427 gst_event_set_group_id (event, qtdemux->group_id);
8428 if (stream->disabled)
8429 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8430 if (CUR_STREAM (stream)->sparse) {
8431 stream_flags |= GST_STREAM_FLAG_SPARSE;
8433 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8435 gst_event_set_stream_flags (event, stream_flags);
8436 gst_pad_push_event (stream->pad, event);
8439 prev_caps = gst_pad_get_current_caps (stream->pad);
8441 if (CUR_STREAM (stream)->caps) {
8443 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8444 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8445 CUR_STREAM (stream)->caps);
8446 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8448 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8451 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8455 gst_caps_unref (prev_caps);
8456 stream->new_caps = FALSE;
8462 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8463 QtDemuxStream * stream)
8465 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8468 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8469 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8470 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8471 stream->stsd_entries_length)) {
8472 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8473 (_("This file is invalid and cannot be played.")),
8474 ("New sample description id is out of bounds (%d >= %d)",
8475 stream->stsd_sample_description_id, stream->stsd_entries_length));
8477 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8478 stream->new_caps = TRUE;
8483 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8484 QtDemuxStream * stream, GstTagList * list)
8486 gboolean ret = TRUE;
8487 /* consistent default for push based mode */
8488 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8490 if (stream->subtype == FOURCC_vide) {
8491 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8494 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8497 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8498 gst_object_unref (stream->pad);
8504 qtdemux->n_video_streams++;
8505 } else if (stream->subtype == FOURCC_soun) {
8506 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8509 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8511 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8512 gst_object_unref (stream->pad);
8517 qtdemux->n_audio_streams++;
8518 } else if (stream->subtype == FOURCC_strm) {
8519 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8520 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8521 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8522 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8525 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8527 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8528 gst_object_unref (stream->pad);
8533 qtdemux->n_sub_streams++;
8534 } else if (CUR_STREAM (stream)->caps) {
8535 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8538 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8540 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8541 gst_object_unref (stream->pad);
8546 qtdemux->n_video_streams++;
8548 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8555 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8556 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8557 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8558 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8560 if (stream->stream_tags)
8561 gst_tag_list_unref (stream->stream_tags);
8562 stream->stream_tags = list;
8564 /* global tags go on each pad anyway */
8565 stream->send_global_tags = TRUE;
8566 /* send upstream GST_EVENT_PROTECTION events that were received before
8567 this source pad was created */
8568 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8569 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8573 gst_tag_list_unref (list);
8577 /* find next atom with @fourcc starting at @offset */
8578 static GstFlowReturn
8579 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8580 guint64 * length, guint32 fourcc)
8586 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8587 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8593 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8594 if (G_UNLIKELY (ret != GST_FLOW_OK))
8596 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8599 gst_buffer_unref (buf);
8602 gst_buffer_map (buf, &map, GST_MAP_READ);
8603 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8604 gst_buffer_unmap (buf, &map);
8605 gst_buffer_unref (buf);
8607 if (G_UNLIKELY (*length == 0)) {
8608 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8609 ret = GST_FLOW_ERROR;
8613 if (lfourcc == fourcc) {
8614 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8618 GST_LOG_OBJECT (qtdemux,
8619 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8620 GST_FOURCC_ARGS (fourcc), *offset);
8629 /* might simply have had last one */
8630 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8635 /* should only do something in pull mode */
8636 /* call with OBJECT lock */
8637 static GstFlowReturn
8638 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8640 guint64 length, offset;
8641 GstBuffer *buf = NULL;
8642 GstFlowReturn ret = GST_FLOW_OK;
8643 GstFlowReturn res = GST_FLOW_OK;
8646 offset = qtdemux->moof_offset;
8647 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8650 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8651 return GST_FLOW_EOS;
8654 /* best not do pull etc with lock held */
8655 GST_OBJECT_UNLOCK (qtdemux);
8657 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8658 if (ret != GST_FLOW_OK)
8661 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8662 if (G_UNLIKELY (ret != GST_FLOW_OK))
8664 gst_buffer_map (buf, &map, GST_MAP_READ);
8665 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8666 gst_buffer_unmap (buf, &map);
8667 gst_buffer_unref (buf);
8672 gst_buffer_unmap (buf, &map);
8673 gst_buffer_unref (buf);
8677 /* look for next moof */
8678 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8679 if (G_UNLIKELY (ret != GST_FLOW_OK))
8683 GST_OBJECT_LOCK (qtdemux);
8685 qtdemux->moof_offset = offset;
8691 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8693 res = GST_FLOW_ERROR;
8698 /* maybe upstream temporarily flushing */
8699 if (ret != GST_FLOW_FLUSHING) {
8700 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8703 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8704 /* resume at current position next time */
8711 /* initialise bytereaders for stbl sub-atoms */
8713 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8715 stream->stbl_index = -1; /* no samples have yet been parsed */
8716 stream->sample_index = -1;
8718 /* time-to-sample atom */
8719 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8722 /* copy atom data into a new buffer for later use */
8723 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8725 /* skip version + flags */
8726 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8727 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8729 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8731 /* make sure there's enough data */
8732 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8733 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8734 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8735 stream->n_sample_times);
8736 if (!stream->n_sample_times)
8740 /* sync sample atom */
8741 stream->stps_present = FALSE;
8742 if ((stream->stss_present =
8743 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8744 &stream->stss) ? TRUE : FALSE) == TRUE) {
8745 /* copy atom data into a new buffer for later use */
8746 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8748 /* skip version + flags */
8749 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8750 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8753 if (stream->n_sample_syncs) {
8754 /* make sure there's enough data */
8755 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8759 /* partial sync sample atom */
8760 if ((stream->stps_present =
8761 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8762 &stream->stps) ? TRUE : FALSE) == TRUE) {
8763 /* copy atom data into a new buffer for later use */
8764 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8766 /* skip version + flags */
8767 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8768 !gst_byte_reader_get_uint32_be (&stream->stps,
8769 &stream->n_sample_partial_syncs))
8772 /* if there are no entries, the stss table contains the real
8774 if (stream->n_sample_partial_syncs) {
8775 /* make sure there's enough data */
8776 if (!qt_atom_parser_has_chunks (&stream->stps,
8777 stream->n_sample_partial_syncs, 4))
8784 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8787 /* copy atom data into a new buffer for later use */
8788 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8790 /* skip version + flags */
8791 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8792 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8795 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8798 if (!stream->n_samples)
8801 /* sample-to-chunk atom */
8802 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8805 /* copy atom data into a new buffer for later use */
8806 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8808 /* skip version + flags */
8809 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8810 !gst_byte_reader_get_uint32_be (&stream->stsc,
8811 &stream->n_samples_per_chunk))
8814 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8815 stream->n_samples_per_chunk);
8817 /* make sure there's enough data */
8818 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8824 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8825 stream->co_size = sizeof (guint32);
8826 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8828 stream->co_size = sizeof (guint64);
8832 /* copy atom data into a new buffer for later use */
8833 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8835 /* skip version + flags */
8836 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8839 /* chunks_are_samples == TRUE means treat chunks as samples */
8840 stream->chunks_are_samples = stream->sample_size
8841 && !CUR_STREAM (stream)->sampled;
8842 if (stream->chunks_are_samples) {
8843 /* treat chunks as samples */
8844 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8847 /* skip number of entries */
8848 if (!gst_byte_reader_skip (&stream->stco, 4))
8851 /* make sure there are enough data in the stsz atom */
8852 if (!stream->sample_size) {
8853 /* different sizes for each sample */
8854 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8859 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8860 stream->n_samples, (guint) sizeof (QtDemuxSample),
8861 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8863 if (stream->n_samples >=
8864 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8865 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8866 "be larger than %uMB (broken file?)", stream->n_samples,
8867 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8871 g_assert (stream->samples == NULL);
8872 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8873 if (!stream->samples) {
8874 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8879 /* composition time-to-sample */
8880 if ((stream->ctts_present =
8881 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8882 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8883 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8885 /* copy atom data into a new buffer for later use */
8886 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8888 /* skip version + flags */
8889 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8890 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8891 &stream->n_composition_times))
8894 /* make sure there's enough data */
8895 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8899 /* This is optional, if missing we iterate the ctts */
8900 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8901 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8902 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8903 g_free ((gpointer) cslg.data);
8907 gint32 cslg_least = 0;
8908 guint num_entries, pos;
8911 pos = gst_byte_reader_get_pos (&stream->ctts);
8912 num_entries = stream->n_composition_times;
8914 stream->cslg_shift = 0;
8916 for (i = 0; i < num_entries; i++) {
8919 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8920 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8922 if (offset < cslg_least)
8923 cslg_least = offset;
8927 stream->cslg_shift = ABS (cslg_least);
8929 stream->cslg_shift = 0;
8931 /* reset the reader so we can generate sample table */
8932 gst_byte_reader_set_pos (&stream->ctts, pos);
8935 /* Ensure the cslg_shift value is consistent so we can use it
8936 * unconditionnally to produce TS and Segment */
8937 stream->cslg_shift = 0;
8944 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8945 (_("This file is corrupt and cannot be played.")), (NULL));
8950 gst_qtdemux_stbl_free (stream);
8951 if (!qtdemux->fragmented) {
8952 /* not quite good */
8953 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8956 /* may pick up samples elsewhere */
8962 /* collect samples from the next sample to be parsed up to sample @n for @stream
8963 * by reading the info from @stbl
8965 * This code can be executed from both the streaming thread and the seeking
8966 * thread so it takes the object lock to protect itself
8969 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8972 QtDemuxSample *samples, *first, *cur, *last;
8973 guint32 n_samples_per_chunk;
8976 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
8977 GST_FOURCC_FORMAT ", pad %s",
8978 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
8979 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8981 n_samples = stream->n_samples;
8984 goto out_of_samples;
8986 GST_OBJECT_LOCK (qtdemux);
8987 if (n <= stream->stbl_index)
8988 goto already_parsed;
8990 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8992 if (!stream->stsz.data) {
8993 /* so we already parsed and passed all the moov samples;
8994 * onto fragmented ones */
8995 g_assert (qtdemux->fragmented);
8999 /* pointer to the sample table */
9000 samples = stream->samples;
9002 /* starts from -1, moves to the next sample index to parse */
9003 stream->stbl_index++;
9005 /* keep track of the first and last sample to fill */
9006 first = &samples[stream->stbl_index];
9009 if (!stream->chunks_are_samples) {
9010 /* set the sample sizes */
9011 if (stream->sample_size == 0) {
9012 /* different sizes for each sample */
9013 for (cur = first; cur <= last; cur++) {
9014 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9015 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9016 (guint) (cur - samples), cur->size);
9019 /* samples have the same size */
9020 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9021 for (cur = first; cur <= last; cur++)
9022 cur->size = stream->sample_size;
9026 n_samples_per_chunk = stream->n_samples_per_chunk;
9029 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9032 if (stream->stsc_chunk_index >= stream->last_chunk
9033 || stream->stsc_chunk_index < stream->first_chunk) {
9034 stream->first_chunk =
9035 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9036 stream->samples_per_chunk =
9037 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9039 stream->stsd_sample_description_id =
9040 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9042 /* chunk numbers are counted from 1 it seems */
9043 if (G_UNLIKELY (stream->first_chunk == 0))
9046 --stream->first_chunk;
9048 /* the last chunk of each entry is calculated by taking the first chunk
9049 * of the next entry; except if there is no next, where we fake it with
9051 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9052 stream->last_chunk = G_MAXUINT32;
9054 stream->last_chunk =
9055 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9056 if (G_UNLIKELY (stream->last_chunk == 0))
9059 --stream->last_chunk;
9062 GST_LOG_OBJECT (qtdemux,
9063 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9064 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9065 stream->samples_per_chunk, stream->stsd_sample_description_id);
9067 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9070 if (stream->last_chunk != G_MAXUINT32) {
9071 if (!qt_atom_parser_peek_sub (&stream->stco,
9072 stream->first_chunk * stream->co_size,
9073 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9078 stream->co_chunk = stream->stco;
9079 if (!gst_byte_reader_skip (&stream->co_chunk,
9080 stream->first_chunk * stream->co_size))
9084 stream->stsc_chunk_index = stream->first_chunk;
9087 last_chunk = stream->last_chunk;
9089 if (stream->chunks_are_samples) {
9090 cur = &samples[stream->stsc_chunk_index];
9092 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9095 stream->stsc_chunk_index = j;
9100 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9103 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9104 "%" G_GUINT64_FORMAT, j, cur->offset);
9106 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9107 CUR_STREAM (stream)->bytes_per_frame > 0) {
9109 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9110 CUR_STREAM (stream)->samples_per_frame *
9111 CUR_STREAM (stream)->bytes_per_frame;
9113 cur->size = stream->samples_per_chunk;
9116 GST_DEBUG_OBJECT (qtdemux,
9117 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9118 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9119 stream->stco_sample_index)), cur->size);
9121 cur->timestamp = stream->stco_sample_index;
9122 cur->duration = stream->samples_per_chunk;
9123 cur->keyframe = TRUE;
9126 stream->stco_sample_index += stream->samples_per_chunk;
9128 stream->stsc_chunk_index = j;
9130 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9131 guint32 samples_per_chunk;
9132 guint64 chunk_offset;
9134 if (!stream->stsc_sample_index
9135 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9136 &stream->chunk_offset))
9139 samples_per_chunk = stream->samples_per_chunk;
9140 chunk_offset = stream->chunk_offset;
9142 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9143 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9144 G_GUINT64_FORMAT " and size %d",
9145 (guint) (cur - samples), chunk_offset, cur->size);
9147 cur->offset = chunk_offset;
9148 chunk_offset += cur->size;
9151 if (G_UNLIKELY (cur > last)) {
9153 stream->stsc_sample_index = k + 1;
9154 stream->chunk_offset = chunk_offset;
9155 stream->stsc_chunk_index = j;
9159 stream->stsc_sample_index = 0;
9161 stream->stsc_chunk_index = j;
9163 stream->stsc_index++;
9166 if (stream->chunks_are_samples)
9170 guint32 n_sample_times;
9172 n_sample_times = stream->n_sample_times;
9175 for (i = stream->stts_index; i < n_sample_times; i++) {
9176 guint32 stts_samples;
9177 gint32 stts_duration;
9180 if (stream->stts_sample_index >= stream->stts_samples
9181 || !stream->stts_sample_index) {
9183 stream->stts_samples =
9184 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9185 stream->stts_duration =
9186 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9188 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9189 i, stream->stts_samples, stream->stts_duration);
9191 stream->stts_sample_index = 0;
9194 stts_samples = stream->stts_samples;
9195 stts_duration = stream->stts_duration;
9196 stts_time = stream->stts_time;
9198 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9199 GST_DEBUG_OBJECT (qtdemux,
9200 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9201 (guint) (cur - samples), j,
9202 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9204 cur->timestamp = stts_time;
9205 cur->duration = stts_duration;
9207 /* avoid 32-bit wrap-around,
9208 * but still mind possible 'negative' duration */
9209 stts_time += (gint64) stts_duration;
9212 if (G_UNLIKELY (cur > last)) {
9214 stream->stts_time = stts_time;
9215 stream->stts_sample_index = j + 1;
9216 if (stream->stts_sample_index >= stream->stts_samples)
9217 stream->stts_index++;
9221 stream->stts_sample_index = 0;
9222 stream->stts_time = stts_time;
9223 stream->stts_index++;
9225 /* fill up empty timestamps with the last timestamp, this can happen when
9226 * the last samples do not decode and so we don't have timestamps for them.
9227 * We however look at the last timestamp to estimate the track length so we
9228 * need something in here. */
9229 for (; cur < last; cur++) {
9230 GST_DEBUG_OBJECT (qtdemux,
9231 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9232 (guint) (cur - samples),
9233 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9234 cur->timestamp = stream->stts_time;
9240 /* sample sync, can be NULL */
9241 if (stream->stss_present == TRUE) {
9242 guint32 n_sample_syncs;
9244 n_sample_syncs = stream->n_sample_syncs;
9246 if (!n_sample_syncs) {
9247 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9248 stream->all_keyframe = TRUE;
9250 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9251 /* note that the first sample is index 1, not 0 */
9254 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9256 if (G_LIKELY (index > 0 && index <= n_samples)) {
9258 samples[index].keyframe = TRUE;
9259 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9260 /* and exit if we have enough samples */
9261 if (G_UNLIKELY (index >= n)) {
9268 stream->stss_index = i;
9271 /* stps marks partial sync frames like open GOP I-Frames */
9272 if (stream->stps_present == TRUE) {
9273 guint32 n_sample_partial_syncs;
9275 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9277 /* if there are no entries, the stss table contains the real
9279 if (n_sample_partial_syncs) {
9280 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9281 /* note that the first sample is index 1, not 0 */
9284 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9286 if (G_LIKELY (index > 0 && index <= n_samples)) {
9288 samples[index].keyframe = TRUE;
9289 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9290 /* and exit if we have enough samples */
9291 if (G_UNLIKELY (index >= n)) {
9298 stream->stps_index = i;
9302 /* no stss, all samples are keyframes */
9303 stream->all_keyframe = TRUE;
9304 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9309 /* composition time to sample */
9310 if (stream->ctts_present == TRUE) {
9311 guint32 n_composition_times;
9313 gint32 ctts_soffset;
9315 /* Fill in the pts_offsets */
9317 n_composition_times = stream->n_composition_times;
9319 for (i = stream->ctts_index; i < n_composition_times; i++) {
9320 if (stream->ctts_sample_index >= stream->ctts_count
9321 || !stream->ctts_sample_index) {
9322 stream->ctts_count =
9323 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9324 stream->ctts_soffset =
9325 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9326 stream->ctts_sample_index = 0;
9329 ctts_count = stream->ctts_count;
9330 ctts_soffset = stream->ctts_soffset;
9332 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9333 cur->pts_offset = ctts_soffset;
9336 if (G_UNLIKELY (cur > last)) {
9338 stream->ctts_sample_index = j + 1;
9342 stream->ctts_sample_index = 0;
9343 stream->ctts_index++;
9347 stream->stbl_index = n;
9348 /* if index has been completely parsed, free data that is no-longer needed */
9349 if (n + 1 == stream->n_samples) {
9350 gst_qtdemux_stbl_free (stream);
9351 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9352 if (qtdemux->pullbased) {
9353 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9354 while (n + 1 == stream->n_samples)
9355 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9359 GST_OBJECT_UNLOCK (qtdemux);
9366 GST_LOG_OBJECT (qtdemux,
9367 "Tried to parse up to sample %u but this sample has already been parsed",
9369 /* if fragmented, there may be more */
9370 if (qtdemux->fragmented && n == stream->stbl_index)
9372 GST_OBJECT_UNLOCK (qtdemux);
9378 GST_LOG_OBJECT (qtdemux,
9379 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9381 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9382 (_("This file is corrupt and cannot be played.")), (NULL));
9387 GST_OBJECT_UNLOCK (qtdemux);
9388 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9389 (_("This file is corrupt and cannot be played.")), (NULL));
9394 /* collect all segment info for @stream.
9397 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9401 /* accept edts if they contain gaps at start and there is only
9402 * one media segment */
9403 gboolean allow_pushbased_edts = TRUE;
9404 gint media_segments_count = 0;
9406 /* parse and prepare segment info from the edit list */
9407 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9408 stream->n_segments = 0;
9409 stream->segments = NULL;
9410 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9413 gint segment_number, entry_size;
9416 const guint8 *buffer;
9420 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9421 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9424 buffer = elst->data;
9426 size = QT_UINT32 (buffer);
9427 /* version, flags, n_segments */
9429 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9432 version = QT_UINT8 (buffer + 8);
9433 entry_size = (version == 1) ? 20 : 12;
9435 n_segments = QT_UINT32 (buffer + 12);
9437 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9438 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9442 /* we might allocate a bit too much, at least allocate 1 segment */
9443 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9445 /* segments always start from 0 */
9449 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9452 gboolean empty_edit = FALSE;
9453 QtDemuxSegment *segment;
9455 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9458 media_time = QT_UINT64 (buffer + 8);
9459 duration = QT_UINT64 (buffer);
9460 if (media_time == G_MAXUINT64)
9463 media_time = QT_UINT32 (buffer + 4);
9464 duration = QT_UINT32 (buffer);
9465 if (media_time == G_MAXUINT32)
9470 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9472 segment = &stream->segments[segment_number];
9474 /* time and duration expressed in global timescale */
9475 segment->time = stime;
9476 if (duration != 0 || empty_edit) {
9477 /* edge case: empty edits with duration=zero are treated here.
9478 * (files should not have these anyway). */
9480 /* add non scaled values so we don't cause roundoff errors */
9482 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9483 segment->duration = stime - segment->time;
9485 /* zero duration does not imply media_start == media_stop
9486 * but, only specify media_start. The edit ends with the track. */
9487 stime = segment->duration = GST_CLOCK_TIME_NONE;
9488 /* Don't allow more edits after this one. */
9489 n_segments = segment_number + 1;
9491 segment->stop_time = stime;
9493 segment->trak_media_start = media_time;
9494 /* media_time expressed in stream timescale */
9496 segment->media_start = media_start;
9497 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9498 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9499 media_segments_count++;
9501 segment->media_start = GST_CLOCK_TIME_NONE;
9502 segment->media_stop = GST_CLOCK_TIME_NONE;
9504 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9506 if (rate_int <= 1) {
9507 /* 0 is not allowed, some programs write 1 instead of the floating point
9509 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9513 segment->rate = rate_int / 65536.0;
9516 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9517 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9518 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9519 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9520 segment_number, GST_TIME_ARGS (segment->time),
9521 GST_TIME_ARGS (segment->duration),
9522 GST_TIME_ARGS (segment->media_start), media_time,
9523 GST_TIME_ARGS (segment->media_stop),
9524 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9526 if (segment->stop_time > qtdemux->segment.stop &&
9527 !qtdemux->upstream_format_is_time) {
9528 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9529 " extends to %" GST_TIME_FORMAT
9530 " past the end of the declared movie duration %" GST_TIME_FORMAT
9531 " movie segment will be extended", segment_number,
9532 GST_TIME_ARGS (segment->stop_time),
9533 GST_TIME_ARGS (qtdemux->segment.stop));
9534 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9537 buffer += entry_size;
9539 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9540 stream->n_segments = n_segments;
9541 if (media_segments_count != 1)
9542 allow_pushbased_edts = FALSE;
9546 /* push based does not handle segments, so act accordingly here,
9547 * and warn if applicable */
9548 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9549 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9550 /* remove and use default one below, we stream like it anyway */
9551 g_free (stream->segments);
9552 stream->segments = NULL;
9553 stream->n_segments = 0;
9556 /* no segments, create one to play the complete trak */
9557 if (stream->n_segments == 0) {
9558 GstClockTime stream_duration =
9559 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9561 if (stream->segments == NULL)
9562 stream->segments = g_new (QtDemuxSegment, 1);
9564 /* represent unknown our way */
9565 if (stream_duration == 0)
9566 stream_duration = GST_CLOCK_TIME_NONE;
9568 stream->segments[0].time = 0;
9569 stream->segments[0].stop_time = stream_duration;
9570 stream->segments[0].duration = stream_duration;
9571 stream->segments[0].media_start = 0;
9572 stream->segments[0].media_stop = stream_duration;
9573 stream->segments[0].rate = 1.0;
9574 stream->segments[0].trak_media_start = 0;
9576 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9577 GST_TIME_ARGS (stream_duration));
9578 stream->n_segments = 1;
9579 stream->dummy_segment = TRUE;
9581 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9587 * Parses the stsd atom of a svq3 trak looking for
9588 * the SMI and gama atoms.
9591 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9592 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9594 const guint8 *_gamma = NULL;
9595 GstBuffer *_seqh = NULL;
9596 const guint8 *stsd_data = stsd_entry_data;
9597 guint32 length = QT_UINT32 (stsd_data);
9601 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9607 version = QT_UINT16 (stsd_data);
9612 while (length > 8) {
9613 guint32 fourcc, size;
9615 size = QT_UINT32 (stsd_data);
9616 fourcc = QT_FOURCC (stsd_data + 4);
9617 data = stsd_data + 8;
9620 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9621 "svq3 atom parsing");
9630 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9631 " for gama atom, expected 12", size);
9636 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9638 if (_seqh != NULL) {
9639 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9640 " found, ignoring");
9642 seqh_size = QT_UINT32 (data + 4);
9643 if (seqh_size > 0) {
9644 _seqh = gst_buffer_new_and_alloc (seqh_size);
9645 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9652 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9653 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9657 if (size <= length) {
9663 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9666 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9667 G_GUINT16_FORMAT, version);
9678 gst_buffer_unref (_seqh);
9683 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9690 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9691 * atom that might contain a 'data' atom with the rtsp uri.
9692 * This case was reported in bug #597497, some info about
9693 * the hndl atom can be found in TN1195
9695 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9696 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9699 guint32 dref_num_entries = 0;
9700 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9701 gst_byte_reader_skip (&dref, 4) &&
9702 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9705 /* search dref entries for hndl atom */
9706 for (i = 0; i < dref_num_entries; i++) {
9707 guint32 size = 0, type;
9708 guint8 string_len = 0;
9709 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9710 qt_atom_parser_get_fourcc (&dref, &type)) {
9711 if (type == FOURCC_hndl) {
9712 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9714 /* skip data reference handle bytes and the
9715 * following pascal string and some extra 4
9716 * bytes I have no idea what are */
9717 if (!gst_byte_reader_skip (&dref, 4) ||
9718 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9719 !gst_byte_reader_skip (&dref, string_len + 4)) {
9720 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9724 /* iterate over the atoms to find the data atom */
9725 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9729 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9730 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9731 if (atom_type == FOURCC_data) {
9732 const guint8 *uri_aux = NULL;
9734 /* found the data atom that might contain the rtsp uri */
9735 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9736 "hndl atom, interpreting it as an URI");
9737 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9739 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9740 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9742 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9743 "didn't contain a rtsp address");
9745 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9750 /* skipping to the next entry */
9751 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9754 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9761 /* skip to the next entry */
9762 if (!gst_byte_reader_skip (&dref, size - 8))
9765 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9768 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9774 #define AMR_NB_ALL_MODES 0x81ff
9775 #define AMR_WB_ALL_MODES 0x83ff
9777 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9779 /* The 'damr' atom is of the form:
9781 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9782 * 32 b 8 b 16 b 8 b 8 b
9784 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9785 * represents the highest mode used in the stream (and thus the maximum
9786 * bitrate), with a couple of special cases as seen below.
9789 /* Map of frame type ID -> bitrate */
9790 static const guint nb_bitrates[] = {
9791 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9793 static const guint wb_bitrates[] = {
9794 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9800 gst_buffer_map (buf, &map, GST_MAP_READ);
9802 if (map.size != 0x11) {
9803 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9807 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9808 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9809 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9813 mode_set = QT_UINT16 (map.data + 13);
9815 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9816 max_mode = 7 + (wb ? 1 : 0);
9818 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9819 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9821 if (max_mode == -1) {
9822 GST_DEBUG ("No mode indication was found (mode set) = %x",
9827 gst_buffer_unmap (buf, &map);
9828 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9831 gst_buffer_unmap (buf, &map);
9836 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9837 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9840 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9846 if (gst_byte_reader_get_remaining (reader) < 36)
9849 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9850 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9851 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9852 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9853 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9854 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9855 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9856 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9857 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9859 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9860 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9861 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9863 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9864 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9866 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9867 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9874 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9875 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9882 * This macro will only compare value abdegh, it expects cfi to have already
9885 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9886 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9888 /* only handle the cases where the last column has standard values */
9889 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9890 const gchar *rotation_tag = NULL;
9892 /* no rotation needed */
9893 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9895 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9896 rotation_tag = "rotate-90";
9897 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9898 rotation_tag = "rotate-180";
9899 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9900 rotation_tag = "rotate-270";
9902 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9905 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9907 if (rotation_tag != NULL) {
9908 if (*taglist == NULL)
9909 *taglist = gst_tag_list_new_empty ();
9910 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9911 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9914 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9918 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9919 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9920 * Common Encryption (cenc), the function will also parse the tenc box (defined
9921 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9922 * (typically an enc[v|a|t|s] sample entry); the function will set
9923 * @original_fmt to the fourcc of the original unencrypted stream format.
9924 * Returns TRUE if successful; FALSE otherwise. */
9926 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9927 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9934 g_return_val_if_fail (qtdemux != NULL, FALSE);
9935 g_return_val_if_fail (stream != NULL, FALSE);
9936 g_return_val_if_fail (container != NULL, FALSE);
9937 g_return_val_if_fail (original_fmt != NULL, FALSE);
9939 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9940 if (G_UNLIKELY (!sinf)) {
9941 if (stream->protection_scheme_type == FOURCC_cenc) {
9942 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9943 "mandatory for Common Encryption");
9949 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9950 if (G_UNLIKELY (!frma)) {
9951 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9955 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9956 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9957 GST_FOURCC_ARGS (*original_fmt));
9959 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9961 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9964 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9965 stream->protection_scheme_version =
9966 QT_UINT32 ((const guint8 *) schm->data + 16);
9968 GST_DEBUG_OBJECT (qtdemux,
9969 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9970 "protection_scheme_version: %#010x",
9971 GST_FOURCC_ARGS (stream->protection_scheme_type),
9972 stream->protection_scheme_version);
9974 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9976 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
9979 if (stream->protection_scheme_type == FOURCC_cenc) {
9980 QtDemuxCencSampleSetInfo *info;
9982 const guint8 *tenc_data;
9983 guint32 isEncrypted;
9985 const guint8 *default_kid;
9988 if (G_UNLIKELY (!stream->protection_scheme_info))
9989 stream->protection_scheme_info =
9990 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
9992 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
9994 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
9996 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
9997 "which is mandatory for Common Encryption");
10000 tenc_data = (const guint8 *) tenc->data + 12;
10001 isEncrypted = QT_UINT24 (tenc_data);
10002 iv_size = QT_UINT8 (tenc_data + 3);
10003 default_kid = (tenc_data + 4);
10004 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
10005 gst_buffer_fill (kid_buf, 0, default_kid, 16);
10006 if (info->default_properties)
10007 gst_structure_free (info->default_properties);
10008 info->default_properties =
10009 gst_structure_new ("application/x-cenc",
10010 "iv_size", G_TYPE_UINT, iv_size,
10011 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
10012 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
10013 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
10014 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
10015 gst_buffer_unref (kid_buf);
10021 qtdemux_track_id_compare_func (QtDemuxStream * stream1, QtDemuxStream * stream2)
10023 return (gint) stream1->track_id - (gint) stream2->track_id;
10026 /* parse the traks.
10027 * With each track we associate a new QtDemuxStream that contains all the info
10029 * traks that do not decode to something (like strm traks) will not have a pad.
10032 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10034 GstByteReader tkhd;
10049 QtDemuxStream *stream = NULL;
10050 const guint8 *stsd_data;
10051 const guint8 *stsd_entry_data;
10052 guint remaining_stsd_len;
10053 guint stsd_entry_count;
10055 guint16 lang_code; /* quicktime lang code or packed iso code */
10057 guint32 tkhd_flags = 0;
10058 guint8 tkhd_version = 0;
10059 guint32 w = 0, h = 0;
10060 guint value_size, stsd_len, len;
10064 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10066 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10067 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10068 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10071 /* pick between 64 or 32 bits */
10072 value_size = tkhd_version == 1 ? 8 : 4;
10073 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10074 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10077 /* Check if current moov has duplicated track_id */
10078 if (qtdemux_find_stream (qtdemux, track_id))
10079 goto existing_stream;
10081 stream = _create_stream (qtdemux, track_id);
10082 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10084 /* need defaults for fragments */
10085 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10087 if ((tkhd_flags & 1) == 0)
10088 stream->disabled = TRUE;
10090 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10091 tkhd_version, tkhd_flags, stream->track_id);
10093 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10096 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10097 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10098 if (qtdemux->major_brand != FOURCC_mjp2 ||
10099 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10103 len = QT_UINT32 ((guint8 *) mdhd->data);
10104 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10105 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10106 if (version == 0x01000000) {
10109 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10110 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10111 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10115 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10116 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10117 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10120 if (lang_code < 0x400) {
10121 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10122 } else if (lang_code == 0x7fff) {
10123 stream->lang_id[0] = 0; /* unspecified */
10125 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10126 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10127 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10128 stream->lang_id[3] = 0;
10131 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10132 stream->timescale);
10133 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10135 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10136 lang_code, stream->lang_id);
10138 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10141 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10142 /* chapters track reference */
10143 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10145 gsize length = GST_READ_UINT32_BE (chap->data);
10146 if (qtdemux->chapters_track_id)
10147 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10149 if (length >= 12) {
10150 qtdemux->chapters_track_id =
10151 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10156 /* fragmented files may have bogus duration in moov */
10157 if (!qtdemux->fragmented &&
10158 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10159 guint64 tdur1, tdur2;
10161 /* don't overflow */
10162 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10163 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10166 * some of those trailers, nowadays, have prologue images that are
10167 * themselves video tracks as well. I haven't really found a way to
10168 * identify those yet, except for just looking at their duration. */
10169 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10170 GST_WARNING_OBJECT (qtdemux,
10171 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10172 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10173 "found, assuming preview image or something; skipping track",
10174 stream->duration, stream->timescale, qtdemux->duration,
10175 qtdemux->timescale);
10176 gst_qtdemux_stream_free (stream);
10181 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10184 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10185 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10187 len = QT_UINT32 ((guint8 *) hdlr->data);
10189 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10190 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10191 GST_FOURCC_ARGS (stream->subtype));
10193 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10196 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10199 /*parse svmi header if existing */
10200 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10202 len = QT_UINT32 ((guint8 *) svmi->data);
10203 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10205 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10206 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10207 guint8 frame_type, frame_layout;
10209 /* MPEG-A stereo video */
10210 if (qtdemux->major_brand == FOURCC_ss02)
10211 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10213 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10214 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10215 switch (frame_type) {
10217 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10220 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10223 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10226 /* mode 3 is primary/secondary view sequence, ie
10227 * left/right views in separate tracks. See section 7.2
10228 * of ISO/IEC 23000-11:2009 */
10229 GST_FIXME_OBJECT (qtdemux,
10230 "Implement stereo video in separate streams");
10233 if ((frame_layout & 0x1) == 0)
10234 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10236 GST_LOG_OBJECT (qtdemux,
10237 "StereoVideo: composition type: %u, is_left_first: %u",
10238 frame_type, frame_layout);
10239 stream->multiview_mode = mode;
10240 stream->multiview_flags = flags;
10244 /* parse rest of tkhd */
10245 if (stream->subtype == FOURCC_vide) {
10248 /* version 1 uses some 64-bit ints */
10249 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10252 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10255 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10256 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10259 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10260 &stream->stream_tags);
10264 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10266 stsd_data = (const guint8 *) stsd->data;
10268 /* stsd should at least have one entry */
10269 stsd_len = QT_UINT32 (stsd_data);
10270 if (stsd_len < 24) {
10271 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10272 if (stream->subtype == FOURCC_vivo) {
10273 gst_qtdemux_stream_free (stream);
10280 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10281 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10282 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10283 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10285 stsd_entry_data = stsd_data + 16;
10286 remaining_stsd_len = stsd_len - 16;
10287 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10289 gchar *codec = NULL;
10290 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10292 /* and that entry should fit within stsd */
10293 len = QT_UINT32 (stsd_entry_data);
10294 if (len > remaining_stsd_len)
10297 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10298 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10299 GST_FOURCC_ARGS (entry->fourcc));
10300 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10302 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10303 goto error_encrypted;
10305 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10306 /* FIXME this looks wrong, there might be multiple children
10307 * with the same type */
10308 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10309 stream->protected = TRUE;
10310 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10311 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10314 if (stream->subtype == FOURCC_vide) {
10319 gint depth, palette_size, palette_count;
10320 guint32 *palette_data = NULL;
10322 entry->sampled = TRUE;
10324 stream->display_width = w >> 16;
10325 stream->display_height = h >> 16;
10328 if (len < 86) /* TODO verify */
10331 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10332 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10333 entry->fps_n = 0; /* this is filled in later */
10334 entry->fps_d = 0; /* this is filled in later */
10335 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10336 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10338 /* if color_table_id is 0, ctab atom must follow; however some files
10339 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10340 * if color table is not present we'll correct the value */
10341 if (entry->color_table_id == 0 &&
10343 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10344 entry->color_table_id = -1;
10347 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10348 entry->width, entry->height, entry->bits_per_sample,
10349 entry->color_table_id);
10351 depth = entry->bits_per_sample;
10353 /* more than 32 bits means grayscale */
10354 gray = (depth > 32);
10355 /* low 32 bits specify the depth */
10358 /* different number of palette entries is determined by depth. */
10360 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10361 palette_count = (1 << depth);
10362 palette_size = palette_count * 4;
10364 if (entry->color_table_id) {
10365 switch (palette_count) {
10369 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10372 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10377 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10379 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10384 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10386 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10389 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10390 (_("The video in this file might not play correctly.")),
10391 ("unsupported palette depth %d", depth));
10395 gint i, j, start, end;
10401 start = QT_UINT32 (stsd_entry_data + offset + 70);
10402 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10403 end = QT_UINT16 (stsd_entry_data + offset + 76);
10405 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10406 start, end, palette_count);
10413 if (len < 94 + (end - start) * 8)
10416 /* palette is always the same size */
10417 palette_data = g_malloc0 (256 * 4);
10418 palette_size = 256 * 4;
10420 for (j = 0, i = start; i <= end; j++, i++) {
10421 guint32 a, r, g, b;
10423 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10424 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10425 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10426 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10428 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10429 (g & 0xff00) | (b >> 8);
10434 gst_caps_unref (entry->caps);
10437 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10439 if (G_UNLIKELY (!entry->caps)) {
10440 g_free (palette_data);
10441 goto unknown_stream;
10445 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10446 GST_TAG_VIDEO_CODEC, codec, NULL);
10451 if (palette_data) {
10454 if (entry->rgb8_palette)
10455 gst_memory_unref (entry->rgb8_palette);
10456 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10457 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10459 s = gst_caps_get_structure (entry->caps, 0);
10461 /* non-raw video has a palette_data property. raw video has the palette as
10462 * an extra plane that we append to the output buffers before we push
10464 if (!gst_structure_has_name (s, "video/x-raw")) {
10465 GstBuffer *palette;
10467 palette = gst_buffer_new ();
10468 gst_buffer_append_memory (palette, entry->rgb8_palette);
10469 entry->rgb8_palette = NULL;
10471 gst_caps_set_simple (entry->caps, "palette_data",
10472 GST_TYPE_BUFFER, palette, NULL);
10473 gst_buffer_unref (palette);
10475 } else if (palette_count != 0) {
10476 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10477 (NULL), ("Unsupported palette depth %d", depth));
10480 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10481 QT_UINT16 (stsd_entry_data + offset + 32));
10487 /* pick 'the' stsd child */
10488 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10489 if (!stream->protected) {
10490 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10494 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10500 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10501 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10502 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10503 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10507 const guint8 *pasp_data = (const guint8 *) pasp->data;
10508 gint len = QT_UINT32 (pasp_data);
10511 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10512 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10514 CUR_STREAM (stream)->par_w = 0;
10515 CUR_STREAM (stream)->par_h = 0;
10518 CUR_STREAM (stream)->par_w = 0;
10519 CUR_STREAM (stream)->par_h = 0;
10523 const guint8 *fiel_data = (const guint8 *) fiel->data;
10524 gint len = QT_UINT32 (fiel_data);
10527 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10528 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10533 const guint8 *colr_data = (const guint8 *) colr->data;
10534 gint len = QT_UINT32 (colr_data);
10536 if (len == 19 || len == 18) {
10537 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10539 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10540 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10541 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10542 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10543 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10545 switch (primaries) {
10547 CUR_STREAM (stream)->colorimetry.primaries =
10548 GST_VIDEO_COLOR_PRIMARIES_BT709;
10551 CUR_STREAM (stream)->colorimetry.primaries =
10552 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10555 CUR_STREAM (stream)->colorimetry.primaries =
10556 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10559 CUR_STREAM (stream)->colorimetry.primaries =
10560 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10566 switch (transfer_function) {
10568 CUR_STREAM (stream)->colorimetry.transfer =
10569 GST_VIDEO_TRANSFER_BT709;
10572 CUR_STREAM (stream)->colorimetry.transfer =
10573 GST_VIDEO_TRANSFER_SMPTE240M;
10581 CUR_STREAM (stream)->colorimetry.matrix =
10582 GST_VIDEO_COLOR_MATRIX_BT709;
10585 CUR_STREAM (stream)->colorimetry.matrix =
10586 GST_VIDEO_COLOR_MATRIX_BT601;
10589 CUR_STREAM (stream)->colorimetry.matrix =
10590 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10593 CUR_STREAM (stream)->colorimetry.matrix =
10594 GST_VIDEO_COLOR_MATRIX_BT2020;
10600 CUR_STREAM (stream)->colorimetry.range =
10601 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10602 GST_VIDEO_COLOR_RANGE_16_235;
10604 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10607 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10612 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10613 stream->stream_tags);
10620 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10621 const guint8 *avc_data = stsd_entry_data + 0x56;
10624 while (len >= 0x8) {
10627 if (QT_UINT32 (avc_data) <= len)
10628 size = QT_UINT32 (avc_data) - 0x8;
10633 /* No real data, so break out */
10636 switch (QT_FOURCC (avc_data + 0x4)) {
10639 /* parse, if found */
10642 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10644 /* First 4 bytes are the length of the atom, the next 4 bytes
10645 * are the fourcc, the next 1 byte is the version, and the
10646 * subsequent bytes are profile_tier_level structure like data. */
10647 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10648 avc_data + 8 + 1, size - 1);
10649 buf = gst_buffer_new_and_alloc (size);
10650 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10651 gst_caps_set_simple (entry->caps,
10652 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10653 gst_buffer_unref (buf);
10661 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10663 /* First 4 bytes are the length of the atom, the next 4 bytes
10664 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10665 * next 1 byte is the version, and the
10666 * subsequent bytes are sequence parameter set like data. */
10668 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10670 gst_codec_utils_h264_caps_set_level_and_profile
10671 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10673 buf = gst_buffer_new_and_alloc (size);
10674 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10675 gst_caps_set_simple (entry->caps,
10676 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10677 gst_buffer_unref (buf);
10683 guint avg_bitrate, max_bitrate;
10685 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10689 max_bitrate = QT_UINT32 (avc_data + 0xc);
10690 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10692 if (!max_bitrate && !avg_bitrate)
10695 /* Some muxers seem to swap the average and maximum bitrates
10696 * (I'm looking at you, YouTube), so we swap for sanity. */
10697 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10698 guint temp = avg_bitrate;
10700 avg_bitrate = max_bitrate;
10701 max_bitrate = temp;
10704 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10705 gst_tag_list_add (stream->stream_tags,
10706 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10707 max_bitrate, NULL);
10709 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10710 gst_tag_list_add (stream->stream_tags,
10711 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10723 avc_data += size + 8;
10732 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10733 const guint8 *hevc_data = stsd_entry_data + 0x56;
10736 while (len >= 0x8) {
10739 if (QT_UINT32 (hevc_data) <= len)
10740 size = QT_UINT32 (hevc_data) - 0x8;
10745 /* No real data, so break out */
10748 switch (QT_FOURCC (hevc_data + 0x4)) {
10751 /* parse, if found */
10754 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10756 /* First 4 bytes are the length of the atom, the next 4 bytes
10757 * are the fourcc, the next 1 byte is the version, and the
10758 * subsequent bytes are sequence parameter set like data. */
10759 gst_codec_utils_h265_caps_set_level_tier_and_profile
10760 (entry->caps, hevc_data + 8 + 1, size - 1);
10762 buf = gst_buffer_new_and_alloc (size);
10763 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10764 gst_caps_set_simple (entry->caps,
10765 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10766 gst_buffer_unref (buf);
10773 hevc_data += size + 8;
10786 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10787 GST_FOURCC_ARGS (fourcc));
10789 /* codec data might be in glbl extension atom */
10791 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10797 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10799 len = QT_UINT32 (data);
10802 buf = gst_buffer_new_and_alloc (len);
10803 gst_buffer_fill (buf, 0, data + 8, len);
10804 gst_caps_set_simple (entry->caps,
10805 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10806 gst_buffer_unref (buf);
10813 /* see annex I of the jpeg2000 spec */
10814 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10815 const guint8 *data;
10816 const gchar *colorspace = NULL;
10818 guint32 ncomp_map = 0;
10819 gint32 *comp_map = NULL;
10820 guint32 nchan_def = 0;
10821 gint32 *chan_def = NULL;
10823 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10824 /* some required atoms */
10825 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10828 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10832 /* number of components; redundant with info in codestream, but useful
10834 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10835 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10837 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10839 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10842 GST_DEBUG_OBJECT (qtdemux, "found colr");
10843 /* extract colour space info */
10844 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10845 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10847 colorspace = "sRGB";
10850 colorspace = "GRAY";
10853 colorspace = "sYUV";
10861 /* colr is required, and only values 16, 17, and 18 are specified,
10862 so error if we have no colorspace */
10865 /* extract component mapping */
10866 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10868 guint32 cmap_len = 0;
10870 cmap_len = QT_UINT32 (cmap->data);
10871 if (cmap_len >= 8) {
10872 /* normal box, subtract off header */
10874 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10875 if (cmap_len % 4 == 0) {
10876 ncomp_map = (cmap_len / 4);
10877 comp_map = g_new0 (gint32, ncomp_map);
10878 for (i = 0; i < ncomp_map; i++) {
10881 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10882 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10883 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10884 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10889 /* extract channel definitions */
10890 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10892 guint32 cdef_len = 0;
10894 cdef_len = QT_UINT32 (cdef->data);
10895 if (cdef_len >= 10) {
10896 /* normal box, subtract off header and len */
10898 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10899 if (cdef_len % 6 == 0) {
10900 nchan_def = (cdef_len / 6);
10901 chan_def = g_new0 (gint32, nchan_def);
10902 for (i = 0; i < nchan_def; i++)
10904 for (i = 0; i < nchan_def; i++) {
10905 guint16 cn, typ, asoc;
10906 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10907 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10908 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10909 if (cn < nchan_def) {
10912 chan_def[cn] = asoc;
10915 chan_def[cn] = 0; /* alpha */
10918 chan_def[cn] = -typ;
10926 gst_caps_set_simple (entry->caps,
10927 "num-components", G_TYPE_INT, ncomp, NULL);
10928 gst_caps_set_simple (entry->caps,
10929 "colorspace", G_TYPE_STRING, colorspace, NULL);
10932 GValue arr = { 0, };
10933 GValue elt = { 0, };
10935 g_value_init (&arr, GST_TYPE_ARRAY);
10936 g_value_init (&elt, G_TYPE_INT);
10937 for (i = 0; i < ncomp_map; i++) {
10938 g_value_set_int (&elt, comp_map[i]);
10939 gst_value_array_append_value (&arr, &elt);
10941 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10942 "component-map", &arr);
10943 g_value_unset (&elt);
10944 g_value_unset (&arr);
10949 GValue arr = { 0, };
10950 GValue elt = { 0, };
10952 g_value_init (&arr, GST_TYPE_ARRAY);
10953 g_value_init (&elt, G_TYPE_INT);
10954 for (i = 0; i < nchan_def; i++) {
10955 g_value_set_int (&elt, chan_def[i]);
10956 gst_value_array_append_value (&arr, &elt);
10958 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10959 "channel-definitions", &arr);
10960 g_value_unset (&elt);
10961 g_value_unset (&arr);
10965 /* some optional atoms */
10966 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10967 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10969 /* indicate possible fields in caps */
10971 data = (guint8 *) field->data + 8;
10973 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10974 (gint) * data, NULL);
10976 /* add codec_data if provided */
10981 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
10982 data = prefix->data;
10983 len = QT_UINT32 (data);
10986 buf = gst_buffer_new_and_alloc (len);
10987 gst_buffer_fill (buf, 0, data + 8, len);
10988 gst_caps_set_simple (entry->caps,
10989 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10990 gst_buffer_unref (buf);
10999 GstBuffer *seqh = NULL;
11000 const guint8 *gamma_data = NULL;
11001 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11003 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11006 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11007 QT_FP32 (gamma_data), NULL);
11010 /* sorry for the bad name, but we don't know what this is, other
11011 * than its own fourcc */
11012 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11014 gst_buffer_unref (seqh);
11017 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11018 buf = gst_buffer_new_and_alloc (len);
11019 gst_buffer_fill (buf, 0, stsd_data, len);
11020 gst_caps_set_simple (entry->caps,
11021 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11022 gst_buffer_unref (buf);
11027 /* https://developer.apple.com/standards/qtff-2001.pdf,
11028 * page 92, "Video Sample Description", under table 3.1 */
11031 const gint compressor_offset =
11032 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11033 const gint min_size = compressor_offset + 32 + 2 + 2;
11036 guint16 color_table_id = 0;
11039 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11041 /* recover information on interlaced/progressive */
11042 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11046 len = QT_UINT32 (jpeg->data);
11047 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11049 if (len >= min_size) {
11050 gst_byte_reader_init (&br, jpeg->data, len);
11052 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11053 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11054 if (color_table_id != 0) {
11055 /* the spec says there can be concatenated chunks in the data, and we want
11056 * to find one called field. Walk through them. */
11057 gint offset = min_size;
11058 while (offset + 8 < len) {
11059 guint32 size = 0, tag;
11060 ok = gst_byte_reader_get_uint32_le (&br, &size);
11061 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11062 if (!ok || size < 8) {
11063 GST_WARNING_OBJECT (qtdemux,
11064 "Failed to walk optional chunk list");
11067 GST_DEBUG_OBJECT (qtdemux,
11068 "Found optional %4.4s chunk, size %u",
11069 (const char *) &tag, size);
11070 if (tag == FOURCC_fiel) {
11071 guint8 n_fields = 0, ordering = 0;
11072 gst_byte_reader_get_uint8 (&br, &n_fields);
11073 gst_byte_reader_get_uint8 (&br, &ordering);
11074 if (n_fields == 1 || n_fields == 2) {
11075 GST_DEBUG_OBJECT (qtdemux,
11076 "Found fiel tag with %u fields, ordering %u",
11077 n_fields, ordering);
11079 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11080 "interlace-mode", G_TYPE_STRING, "interleaved",
11083 GST_WARNING_OBJECT (qtdemux,
11084 "Found fiel tag with invalid fields (%u)", n_fields);
11090 GST_DEBUG_OBJECT (qtdemux,
11091 "Color table ID is 0, not trying to get interlacedness");
11094 GST_WARNING_OBJECT (qtdemux,
11095 "Length of jpeg chunk is too small, not trying to get interlacedness");
11103 gst_caps_set_simple (entry->caps,
11104 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11110 GNode *xith, *xdxt;
11112 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11113 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11117 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11121 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11122 /* collect the headers and store them in a stream list so that we can
11123 * send them out first */
11124 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11134 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11135 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11138 ovc1_data = ovc1->data;
11139 ovc1_len = QT_UINT32 (ovc1_data);
11140 if (ovc1_len <= 198) {
11141 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11144 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11145 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11146 gst_caps_set_simple (entry->caps,
11147 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11148 gst_buffer_unref (buf);
11153 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11154 const guint8 *vc1_data = stsd_entry_data + 0x56;
11160 if (QT_UINT32 (vc1_data) <= len)
11161 size = QT_UINT32 (vc1_data) - 8;
11166 /* No real data, so break out */
11169 switch (QT_FOURCC (vc1_data + 0x4)) {
11170 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11174 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11175 buf = gst_buffer_new_and_alloc (size);
11176 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11177 gst_caps_set_simple (entry->caps,
11178 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11179 gst_buffer_unref (buf);
11186 vc1_data += size + 8;
11192 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11193 const guint8 *av1_data = stsd_entry_data + 0x56;
11196 while (len >= 0x8) {
11199 if (QT_UINT32 (av1_data) <= len)
11200 size = QT_UINT32 (av1_data) - 0x8;
11205 /* No real data, so break out */
11208 switch (QT_FOURCC (av1_data + 0x4)) {
11211 /* parse, if found */
11213 guint8 pres_delay_field;
11215 GST_DEBUG_OBJECT (qtdemux,
11216 "found av1C codec_data in stsd of size %d", size);
11218 /* not enough data, just ignore and hope for the best */
11223 * 4 bytes: atom length
11228 * 1 bits: initial_presentation_delay_present
11229 * 4 bits: initial_presentation_delay (if present else reserved
11233 if (av1_data[9] != 0) {
11234 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11238 /* We skip initial_presentation_delay* for now */
11239 pres_delay_field = *(av1_data + 12);
11240 if (pres_delay_field & (1 << 5)) {
11241 gst_caps_set_simple (entry->caps,
11242 "presentation-delay", G_TYPE_INT,
11243 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11246 buf = gst_buffer_new_and_alloc (size - 5);
11247 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11248 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11249 gst_caps_set_simple (entry->caps,
11250 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11251 gst_buffer_unref (buf);
11260 av1_data += size + 8;
11270 GST_INFO_OBJECT (qtdemux,
11271 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11272 GST_FOURCC_ARGS (fourcc), entry->caps);
11274 } else if (stream->subtype == FOURCC_soun) {
11276 int version, samplesize;
11277 guint16 compression_id;
11278 gboolean amrwb = FALSE;
11281 /* sample description entry (16) + sound sample description v0 (20) */
11285 version = QT_UINT32 (stsd_entry_data + offset);
11286 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11287 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11288 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11289 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11291 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11292 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11293 QT_UINT32 (stsd_entry_data + offset + 4));
11294 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11295 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11296 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11297 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11298 QT_UINT16 (stsd_entry_data + offset + 14));
11299 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11301 if (compression_id == 0xfffe)
11302 entry->sampled = TRUE;
11304 /* first assume uncompressed audio */
11305 entry->bytes_per_sample = samplesize / 8;
11306 entry->samples_per_frame = entry->n_channels;
11307 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11308 entry->samples_per_packet = entry->samples_per_frame;
11309 entry->bytes_per_packet = entry->bytes_per_sample;
11313 /* Yes, these have to be hard-coded */
11316 entry->samples_per_packet = 6;
11317 entry->bytes_per_packet = 1;
11318 entry->bytes_per_frame = 1 * entry->n_channels;
11319 entry->bytes_per_sample = 1;
11320 entry->samples_per_frame = 6 * entry->n_channels;
11325 entry->samples_per_packet = 3;
11326 entry->bytes_per_packet = 1;
11327 entry->bytes_per_frame = 1 * entry->n_channels;
11328 entry->bytes_per_sample = 1;
11329 entry->samples_per_frame = 3 * entry->n_channels;
11334 entry->samples_per_packet = 64;
11335 entry->bytes_per_packet = 34;
11336 entry->bytes_per_frame = 34 * entry->n_channels;
11337 entry->bytes_per_sample = 2;
11338 entry->samples_per_frame = 64 * entry->n_channels;
11344 entry->samples_per_packet = 1;
11345 entry->bytes_per_packet = 1;
11346 entry->bytes_per_frame = 1 * entry->n_channels;
11347 entry->bytes_per_sample = 1;
11348 entry->samples_per_frame = 1 * entry->n_channels;
11353 entry->samples_per_packet = 160;
11354 entry->bytes_per_packet = 33;
11355 entry->bytes_per_frame = 33 * entry->n_channels;
11356 entry->bytes_per_sample = 2;
11357 entry->samples_per_frame = 160 * entry->n_channels;
11364 if (version == 0x00010000) {
11365 /* sample description entry (16) + sound sample description v1 (20+16) */
11377 /* only parse extra decoding config for non-pcm audio */
11378 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11379 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11380 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11381 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11383 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11384 entry->samples_per_packet);
11385 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11386 entry->bytes_per_packet);
11387 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11388 entry->bytes_per_frame);
11389 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11390 entry->bytes_per_sample);
11392 if (!entry->sampled && entry->bytes_per_packet) {
11393 entry->samples_per_frame = (entry->bytes_per_frame /
11394 entry->bytes_per_packet) * entry->samples_per_packet;
11395 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11396 entry->samples_per_frame);
11401 } else if (version == 0x00020000) {
11408 /* sample description entry (16) + sound sample description v2 (56) */
11412 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11413 entry->rate = qtfp.fp;
11414 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11416 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11417 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11418 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11419 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11420 QT_UINT32 (stsd_entry_data + offset + 20));
11421 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11422 QT_UINT32 (stsd_entry_data + offset + 24));
11423 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11424 QT_UINT32 (stsd_entry_data + offset + 28));
11425 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11426 QT_UINT32 (stsd_entry_data + offset + 32));
11427 } else if (version != 0x00000) {
11428 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11433 gst_caps_unref (entry->caps);
11435 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11436 stsd_entry_data + 32, len - 16, &codec);
11444 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11446 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11448 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11450 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11453 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11454 gst_caps_set_simple (entry->caps,
11455 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11462 const guint8 *owma_data;
11463 const gchar *codec_name = NULL;
11467 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11468 /* FIXME this should also be gst_riff_strf_auds,
11469 * but the latter one is actually missing bits-per-sample :( */
11474 gint32 nSamplesPerSec;
11475 gint32 nAvgBytesPerSec;
11476 gint16 nBlockAlign;
11477 gint16 wBitsPerSample;
11480 WAVEFORMATEX *wfex;
11482 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11483 owma_data = stsd_entry_data;
11484 owma_len = QT_UINT32 (owma_data);
11485 if (owma_len <= 54) {
11486 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11489 wfex = (WAVEFORMATEX *) (owma_data + 36);
11490 buf = gst_buffer_new_and_alloc (owma_len - 54);
11491 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11492 if (wfex->wFormatTag == 0x0161) {
11493 codec_name = "Windows Media Audio";
11495 } else if (wfex->wFormatTag == 0x0162) {
11496 codec_name = "Windows Media Audio 9 Pro";
11498 } else if (wfex->wFormatTag == 0x0163) {
11499 codec_name = "Windows Media Audio 9 Lossless";
11500 /* is that correct? gstffmpegcodecmap.c is missing it, but
11501 * fluendo codec seems to support it */
11505 gst_caps_set_simple (entry->caps,
11506 "codec_data", GST_TYPE_BUFFER, buf,
11507 "wmaversion", G_TYPE_INT, version,
11508 "block_align", G_TYPE_INT,
11509 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11510 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11511 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11512 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11513 gst_buffer_unref (buf);
11517 codec = g_strdup (codec_name);
11523 gint len = QT_UINT32 (stsd_entry_data) - offset;
11524 const guint8 *wfex_data = stsd_entry_data + offset;
11525 const gchar *codec_name = NULL;
11527 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11528 /* FIXME this should also be gst_riff_strf_auds,
11529 * but the latter one is actually missing bits-per-sample :( */
11534 gint32 nSamplesPerSec;
11535 gint32 nAvgBytesPerSec;
11536 gint16 nBlockAlign;
11537 gint16 wBitsPerSample;
11542 /* FIXME: unify with similar wavformatex parsing code above */
11543 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11549 if (QT_UINT32 (wfex_data) <= len)
11550 size = QT_UINT32 (wfex_data) - 8;
11555 /* No real data, so break out */
11558 switch (QT_FOURCC (wfex_data + 4)) {
11559 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11561 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11566 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11567 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11568 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11569 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11570 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11571 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11572 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11574 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11575 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11576 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11577 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11578 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11579 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11581 if (wfex.wFormatTag == 0x0161) {
11582 codec_name = "Windows Media Audio";
11584 } else if (wfex.wFormatTag == 0x0162) {
11585 codec_name = "Windows Media Audio 9 Pro";
11587 } else if (wfex.wFormatTag == 0x0163) {
11588 codec_name = "Windows Media Audio 9 Lossless";
11589 /* is that correct? gstffmpegcodecmap.c is missing it, but
11590 * fluendo codec seems to support it */
11594 gst_caps_set_simple (entry->caps,
11595 "wmaversion", G_TYPE_INT, version,
11596 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11597 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11598 "width", G_TYPE_INT, wfex.wBitsPerSample,
11599 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11601 if (size > wfex.cbSize) {
11604 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11605 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11606 size - wfex.cbSize);
11607 gst_caps_set_simple (entry->caps,
11608 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11609 gst_buffer_unref (buf);
11611 GST_WARNING_OBJECT (qtdemux, "no codec data");
11616 codec = g_strdup (codec_name);
11624 wfex_data += size + 8;
11630 const guint8 *opus_data;
11631 guint8 *channel_mapping = NULL;
11634 guint8 channel_mapping_family;
11635 guint8 stream_count;
11636 guint8 coupled_count;
11639 opus_data = stsd_entry_data;
11641 channels = GST_READ_UINT8 (opus_data + 45);
11642 rate = GST_READ_UINT32_LE (opus_data + 48);
11643 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11644 stream_count = GST_READ_UINT8 (opus_data + 55);
11645 coupled_count = GST_READ_UINT8 (opus_data + 56);
11647 if (channels > 0) {
11648 channel_mapping = g_malloc (channels * sizeof (guint8));
11649 for (i = 0; i < channels; i++)
11650 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11653 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11654 channel_mapping_family, stream_count, coupled_count,
11666 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11667 GST_TAG_AUDIO_CODEC, codec, NULL);
11671 /* some bitrate info may have ended up in caps */
11672 s = gst_caps_get_structure (entry->caps, 0);
11673 gst_structure_get_int (s, "bitrate", &bitrate);
11675 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11676 GST_TAG_BITRATE, bitrate, NULL);
11679 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11680 if (!stream->protected) {
11682 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11686 if (stream->protected && fourcc == FOURCC_mp4a) {
11687 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11691 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11699 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11701 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11703 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11707 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11708 16 bits is a byte-swapped wave-style codec identifier,
11709 and we can find a WAVE header internally to a 'wave' atom here.
11710 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11711 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11714 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11715 if (len < offset + 20) {
11716 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11718 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11719 const guint8 *data = stsd_entry_data + offset + 16;
11721 GNode *waveheadernode;
11723 wavenode = g_node_new ((guint8 *) data);
11724 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11725 const guint8 *waveheader;
11728 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11729 if (waveheadernode) {
11730 waveheader = (const guint8 *) waveheadernode->data;
11731 headerlen = QT_UINT32 (waveheader);
11733 if (headerlen > 8) {
11734 gst_riff_strf_auds *header = NULL;
11735 GstBuffer *headerbuf;
11741 headerbuf = gst_buffer_new_and_alloc (headerlen);
11742 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11744 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11745 headerbuf, &header, &extra)) {
11746 gst_caps_unref (entry->caps);
11747 /* FIXME: Need to do something with the channel reorder map */
11749 gst_riff_create_audio_caps (header->format, NULL, header,
11750 extra, NULL, NULL, NULL);
11753 gst_buffer_unref (extra);
11758 GST_DEBUG ("Didn't find waveheadernode for this codec");
11760 g_node_destroy (wavenode);
11763 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11764 stream->stream_tags);
11768 /* FIXME: what is in the chunk? */
11771 gint len = QT_UINT32 (stsd_data);
11773 /* seems to be always = 116 = 0x74 */
11779 gint len = QT_UINT32 (stsd_entry_data);
11782 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11784 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11785 gst_caps_set_simple (entry->caps,
11786 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11787 gst_buffer_unref (buf);
11789 gst_caps_set_simple (entry->caps,
11790 "samplesize", G_TYPE_INT, samplesize, NULL);
11795 GNode *alac, *wave = NULL;
11797 /* apparently, m4a has this atom appended directly in the stsd entry,
11798 * while mov has it in a wave atom */
11799 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11801 /* alac now refers to stsd entry atom */
11802 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11804 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11806 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11809 const guint8 *alac_data = alac->data;
11810 gint len = QT_UINT32 (alac->data);
11814 GST_DEBUG_OBJECT (qtdemux,
11815 "discarding alac atom with unexpected len %d", len);
11817 /* codec-data contains alac atom size and prefix,
11818 * ffmpeg likes it that way, not quite gst-ish though ...*/
11819 buf = gst_buffer_new_and_alloc (len);
11820 gst_buffer_fill (buf, 0, alac->data, len);
11821 gst_caps_set_simple (entry->caps,
11822 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11823 gst_buffer_unref (buf);
11825 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11826 entry->n_channels = QT_UINT8 (alac_data + 21);
11827 entry->rate = QT_UINT32 (alac_data + 32);
11830 gst_caps_set_simple (entry->caps,
11831 "samplesize", G_TYPE_INT, samplesize, NULL);
11836 /* The codingname of the sample entry is 'fLaC' */
11837 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11840 /* The 'dfLa' box is added to the sample entry to convey
11841 initializing information for the decoder. */
11842 const GNode *dfla =
11843 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11846 const guint32 len = QT_UINT32 (dfla->data);
11848 /* Must contain at least dfLa box header (12),
11849 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11851 GST_DEBUG_OBJECT (qtdemux,
11852 "discarding dfla atom with unexpected len %d", len);
11854 /* skip dfLa header to get the METADATA_BLOCKs */
11855 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11856 const guint32 metadata_blocks_len = len - 12;
11858 gchar *stream_marker = g_strdup ("fLaC");
11859 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11860 strlen (stream_marker));
11863 guint32 remainder = 0;
11864 guint32 block_size = 0;
11865 gboolean is_last = FALSE;
11867 GValue array = G_VALUE_INIT;
11868 GValue value = G_VALUE_INIT;
11870 g_value_init (&array, GST_TYPE_ARRAY);
11871 g_value_init (&value, GST_TYPE_BUFFER);
11873 gst_value_set_buffer (&value, block);
11874 gst_value_array_append_value (&array, &value);
11875 g_value_reset (&value);
11877 gst_buffer_unref (block);
11879 /* check there's at least one METADATA_BLOCK_HEADER's worth
11880 * of data, and we haven't already finished parsing */
11881 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11882 remainder = metadata_blocks_len - index;
11884 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11886 (metadata_blocks[index + 1] << 16) +
11887 (metadata_blocks[index + 2] << 8) +
11888 metadata_blocks[index + 3];
11890 /* be careful not to read off end of box */
11891 if (block_size > remainder) {
11895 is_last = metadata_blocks[index] >> 7;
11897 block = gst_buffer_new_and_alloc (block_size);
11899 gst_buffer_fill (block, 0, &metadata_blocks[index],
11902 gst_value_set_buffer (&value, block);
11903 gst_value_array_append_value (&array, &value);
11904 g_value_reset (&value);
11906 gst_buffer_unref (block);
11908 index += block_size;
11911 /* only append the metadata if we successfully read all of it */
11913 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11914 (stream)->caps, 0), "streamheader", &array);
11916 GST_WARNING_OBJECT (qtdemux,
11917 "discarding all METADATA_BLOCKs due to invalid "
11918 "block_size %d at idx %d, rem %d", block_size, index,
11922 g_value_unset (&value);
11923 g_value_unset (&array);
11925 /* The sample rate obtained from the stsd may not be accurate
11926 * since it cannot represent rates greater than 65535Hz, so
11927 * override that value with the sample rate from the
11928 * METADATA_BLOCK_STREAMINFO block */
11929 CUR_STREAM (stream)->rate =
11930 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11941 gint len = QT_UINT32 (stsd_entry_data);
11944 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11947 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11949 /* If we have enough data, let's try to get the 'damr' atom. See
11950 * the 3GPP container spec (26.244) for more details. */
11951 if ((len - 0x34) > 8 &&
11952 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11953 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11954 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11957 gst_caps_set_simple (entry->caps,
11958 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11959 gst_buffer_unref (buf);
11965 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11966 gint len = QT_UINT32 (stsd_entry_data);
11969 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11971 if (sound_version == 1) {
11972 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11973 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11974 guint8 codec_data[2];
11976 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11978 gint sample_rate_index =
11979 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11981 /* build AAC codec data */
11982 codec_data[0] = profile << 3;
11983 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11984 codec_data[1] = (sample_rate_index & 0x01) << 7;
11985 codec_data[1] |= (channels & 0xF) << 3;
11987 buf = gst_buffer_new_and_alloc (2);
11988 gst_buffer_fill (buf, 0, codec_data, 2);
11989 gst_caps_set_simple (entry->caps,
11990 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11991 gst_buffer_unref (buf);
11997 /* Fully handled elsewhere */
12000 GST_INFO_OBJECT (qtdemux,
12001 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12005 GST_INFO_OBJECT (qtdemux,
12006 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12007 GST_FOURCC_ARGS (fourcc), entry->caps);
12009 } else if (stream->subtype == FOURCC_strm) {
12010 if (fourcc == FOURCC_rtsp) {
12011 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12013 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12014 GST_FOURCC_ARGS (fourcc));
12015 goto unknown_stream;
12017 entry->sampled = TRUE;
12018 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12019 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12020 || stream->subtype == FOURCC_clcp) {
12022 entry->sampled = TRUE;
12023 entry->sparse = TRUE;
12026 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12029 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12030 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12035 /* hunt for sort-of codec data */
12039 GNode *mp4s = NULL;
12040 GNode *esds = NULL;
12042 /* look for palette in a stsd->mp4s->esds sub-atom */
12043 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12045 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12046 if (esds == NULL) {
12048 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12052 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12053 stream->stream_tags);
12057 GST_INFO_OBJECT (qtdemux,
12058 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12061 GST_INFO_OBJECT (qtdemux,
12062 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12063 GST_FOURCC_ARGS (fourcc), entry->caps);
12065 /* everything in 1 sample */
12066 entry->sampled = TRUE;
12069 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12072 if (entry->caps == NULL)
12073 goto unknown_stream;
12076 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12077 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12083 /* promote to sampled format */
12084 if (entry->fourcc == FOURCC_samr) {
12085 /* force mono 8000 Hz for AMR */
12086 entry->sampled = TRUE;
12087 entry->n_channels = 1;
12088 entry->rate = 8000;
12089 } else if (entry->fourcc == FOURCC_sawb) {
12090 /* force mono 16000 Hz for AMR-WB */
12091 entry->sampled = TRUE;
12092 entry->n_channels = 1;
12093 entry->rate = 16000;
12094 } else if (entry->fourcc == FOURCC_mp4a) {
12095 entry->sampled = TRUE;
12099 stsd_entry_data += len;
12100 remaining_stsd_len -= len;
12104 /* collect sample information */
12105 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12106 goto samples_failed;
12108 if (qtdemux->fragmented) {
12111 /* need all moov samples as basis; probably not many if any at all */
12112 /* prevent moof parsing taking of at this time */
12113 offset = qtdemux->moof_offset;
12114 qtdemux->moof_offset = 0;
12115 if (stream->n_samples &&
12116 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12117 qtdemux->moof_offset = offset;
12118 goto samples_failed;
12120 qtdemux->moof_offset = 0;
12121 /* movie duration more reliable in this case (e.g. mehd) */
12122 if (qtdemux->segment.duration &&
12123 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12125 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12128 /* configure segments */
12129 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12130 goto segments_failed;
12132 /* add some language tag, if useful */
12133 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12134 strcmp (stream->lang_id, "und")) {
12135 const gchar *lang_code;
12137 /* convert ISO 639-2 code to ISO 639-1 */
12138 lang_code = gst_tag_get_language_code (stream->lang_id);
12139 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12140 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12143 /* Check for UDTA tags */
12144 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12145 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12148 /* Insert and sort new stream in track-id order.
12149 * This will help in comparing old/new streams during stream update check */
12150 qtdemux->active_streams =
12151 g_list_insert_sorted (qtdemux->active_streams, stream,
12152 (GCompareFunc) qtdemux_track_id_compare_func);
12153 qtdemux->n_streams++;
12154 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
12161 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12162 (_("This file is corrupt and cannot be played.")), (NULL));
12164 gst_qtdemux_stream_free (stream);
12169 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12170 gst_qtdemux_stream_free (stream);
12176 /* we posted an error already */
12177 /* free stbl sub-atoms */
12178 gst_qtdemux_stbl_free (stream);
12179 gst_qtdemux_stream_free (stream);
12184 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12190 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12191 GST_FOURCC_ARGS (stream->subtype));
12192 gst_qtdemux_stream_free (stream);
12197 /* If we can estimate the overall bitrate, and don't have information about the
12198 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12199 * the overall bitrate minus the sum of the bitrates of all other streams. This
12200 * should be useful for the common case where we have one audio and one video
12201 * stream and can estimate the bitrate of one, but not the other. */
12203 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12205 QtDemuxStream *stream = NULL;
12206 gint64 size, sys_bitrate, sum_bitrate = 0;
12207 GstClockTime duration;
12211 if (qtdemux->fragmented)
12214 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12216 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12218 GST_DEBUG_OBJECT (qtdemux,
12219 "Size in bytes of the stream not known - bailing");
12223 /* Subtract the header size */
12224 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12225 size, qtdemux->header_size);
12227 if (size < qtdemux->header_size)
12230 size = size - qtdemux->header_size;
12232 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12233 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12237 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12238 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
12239 switch (str->subtype) {
12242 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12243 CUR_STREAM (str)->caps);
12244 /* retrieve bitrate, prefer avg then max */
12246 if (str->stream_tags) {
12247 if (gst_tag_list_get_uint (str->stream_tags,
12248 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12249 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12250 if (gst_tag_list_get_uint (str->stream_tags,
12251 GST_TAG_NOMINAL_BITRATE, &bitrate))
12252 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12253 if (gst_tag_list_get_uint (str->stream_tags,
12254 GST_TAG_BITRATE, &bitrate))
12255 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12258 sum_bitrate += bitrate;
12261 GST_DEBUG_OBJECT (qtdemux,
12262 ">1 stream with unknown bitrate - bailing");
12269 /* For other subtypes, we assume no significant impact on bitrate */
12275 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12279 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12281 if (sys_bitrate < sum_bitrate) {
12282 /* This can happen, since sum_bitrate might be derived from maximum
12283 * bitrates and not average bitrates */
12284 GST_DEBUG_OBJECT (qtdemux,
12285 "System bitrate less than sum bitrate - bailing");
12289 bitrate = sys_bitrate - sum_bitrate;
12290 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12291 ", Stream bitrate = %u", sys_bitrate, bitrate);
12293 if (!stream->stream_tags)
12294 stream->stream_tags = gst_tag_list_new_empty ();
12296 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12298 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12299 GST_TAG_BITRATE, bitrate, NULL);
12302 static GstFlowReturn
12303 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12305 GstFlowReturn ret = GST_FLOW_OK;
12306 GList *iter, *next;
12308 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12310 for (iter = qtdemux->active_streams; ret == GST_FLOW_OK && iter; iter = next) {
12311 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12312 guint32 sample_num = 0;
12316 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12317 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12319 if (qtdemux->fragmented) {
12320 /* need all moov samples first */
12321 GST_OBJECT_LOCK (qtdemux);
12322 while (stream->n_samples == 0)
12323 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12325 GST_OBJECT_UNLOCK (qtdemux);
12327 /* discard any stray moof */
12328 qtdemux->moof_offset = 0;
12331 /* prepare braking */
12332 if (ret != GST_FLOW_ERROR)
12335 /* in pull mode, we should have parsed some sample info by now;
12336 * and quite some code will not handle no samples.
12337 * in push mode, we'll just have to deal with it */
12338 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12339 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12340 gst_qtdemux_remove_stream (qtdemux, stream);
12342 } else if (stream->track_id == qtdemux->chapters_track_id &&
12343 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12344 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12345 so that it doesn't look like a subtitle track */
12346 gst_qtdemux_remove_stream (qtdemux, stream);
12350 /* parse the initial sample for use in setting the frame rate cap */
12351 while (sample_num == 0 && sample_num < stream->n_samples) {
12352 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12362 _stream_in_list (GList * list, QtDemuxStream * stream)
12366 for (iter = list; iter; iter = g_list_next (iter)) {
12367 QtDemuxStream *tmp = QTDEMUX_STREAM (iter->data);
12368 if (!g_strcmp0 (tmp->stream_id, stream->stream_id))
12376 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12380 if (!qtdemux->active_streams)
12383 /* streams in list are sorted in track-id order */
12384 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12385 new = g_list_next (new), old = g_list_next (old)) {
12387 /* Different stream-id, updated */
12388 if (g_strcmp0 (QTDEMUX_STREAM (new->data)->stream_id,
12389 QTDEMUX_STREAM (old->data)->stream_id))
12393 /* Different length, updated */
12394 if (new != NULL || old != NULL)
12401 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12402 QtDemuxStream * oldstream, QtDemuxStream * newstream)
12404 /* Connect old stream's srcpad to new stream */
12405 newstream->pad = oldstream->pad;
12406 oldstream->pad = NULL;
12408 /* unset new_stream to prevent stream-start event */
12409 newstream->new_stream = FALSE;
12411 return gst_qtdemux_configure_stream (qtdemux, newstream);
12415 qtdemux_update_streams (GstQTDemux * qtdemux)
12417 GList *iter, *next;
12419 /* At below, figure out which stream in active_streams has identical stream-id
12420 * with that of in old_streams. If there is matching stream-id,
12421 * corresponding newstream will not be exposed again,
12422 * but demux will reuse srcpad of matched old stream
12424 * active_streams : newly created streams from the latest moov
12425 * old_streams : existing streams (belong to previous moov)
12428 /* Count n_streams again */
12429 qtdemux->n_streams = 0;
12431 for (iter = qtdemux->active_streams; iter; iter = next) {
12433 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12437 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12438 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12440 qtdemux->n_streams++;
12442 if (qtdemux->streams_aware
12443 && (tmp = _stream_in_list (qtdemux->old_streams, stream)) != NULL
12444 && QTDEMUX_STREAM (tmp->data)->pad) {
12445 QtDemuxStream *oldstream = QTDEMUX_STREAM (tmp->data);
12447 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12449 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12452 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, oldstream);
12453 gst_qtdemux_stream_free (oldstream);
12457 /* now we have all info and can expose */
12458 list = stream->stream_tags;
12459 stream->stream_tags = NULL;
12460 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12468 /* Must be called with expose lock */
12469 static GstFlowReturn
12470 qtdemux_expose_streams (GstQTDemux * qtdemux)
12472 GList *iter, *next;
12474 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12476 if (!qtdemux_is_streams_update (qtdemux)) {
12479 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12480 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12481 new = g_list_next (new), old = g_list_next (old)) {
12482 if (!qtdemux_reuse_and_configure_stream (qtdemux,
12483 QTDEMUX_STREAM (old->data), QTDEMUX_STREAM (new->data)))
12484 return GST_FLOW_ERROR;
12487 g_list_free_full (qtdemux->old_streams,
12488 (GDestroyNotify) gst_qtdemux_stream_free);
12489 qtdemux->old_streams = NULL;
12491 return GST_FLOW_OK;
12494 if (qtdemux->streams_aware) {
12495 if (!qtdemux_update_streams (qtdemux))
12496 return GST_FLOW_ERROR;
12498 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12499 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12502 /* now we have all info and can expose */
12503 list = stream->stream_tags;
12504 stream->stream_tags = NULL;
12505 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12506 return GST_FLOW_ERROR;
12511 gst_qtdemux_guess_bitrate (qtdemux);
12513 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12515 /* If we have still old_streams, it's no more used stream */
12516 for (iter = qtdemux->old_streams; iter; iter = next) {
12517 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12518 next = g_list_next (iter);
12523 event = gst_event_new_eos ();
12524 if (qtdemux->segment_seqnum)
12525 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12527 gst_pad_push_event (stream->pad, event);
12530 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, stream);
12531 gst_qtdemux_stream_free (stream);
12534 /* check if we should post a redirect in case there is a single trak
12535 * and it is a redirecting trak */
12536 if (qtdemux->n_streams == 1 &&
12537 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri != NULL) {
12540 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12541 "an external content");
12542 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12543 gst_structure_new ("redirect",
12544 "new-location", G_TYPE_STRING,
12545 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri, NULL));
12546 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12547 qtdemux->posted_redirect = TRUE;
12550 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12551 qtdemux_do_allocation (qtdemux, QTDEMUX_STREAM (iter->data));
12554 qtdemux->need_segment = TRUE;
12556 qtdemux->exposed = TRUE;
12557 return GST_FLOW_OK;
12560 /* check if major or compatible brand is 3GP */
12561 static inline gboolean
12562 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12565 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12567 } else if (qtdemux->comp_brands != NULL) {
12571 gboolean res = FALSE;
12573 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12576 while (size >= 4) {
12577 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12582 gst_buffer_unmap (qtdemux->comp_brands, &map);
12589 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12590 static inline gboolean
12591 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12593 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12594 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12595 || fourcc == FOURCC_albm;
12599 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12600 const char *tag, const char *dummy, GNode * node)
12602 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12606 gdouble longitude, latitude, altitude;
12609 len = QT_UINT32 (node->data);
12616 /* TODO: language code skipped */
12618 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12621 /* do not alarm in trivial case, but bail out otherwise */
12622 if (*(data + offset) != 0) {
12623 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12627 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12628 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12629 offset += strlen (name);
12633 if (len < offset + 2 + 4 + 4 + 4)
12636 /* +1 +1 = skip null-terminator and location role byte */
12638 /* table in spec says unsigned, semantics say negative has meaning ... */
12639 longitude = QT_SFP32 (data + offset);
12642 latitude = QT_SFP32 (data + offset);
12645 altitude = QT_SFP32 (data + offset);
12647 /* one invalid means all are invalid */
12648 if (longitude >= -180.0 && longitude <= 180.0 &&
12649 latitude >= -90.0 && latitude <= 90.0) {
12650 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12651 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12652 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12653 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12656 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12663 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12670 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12671 const char *tag, const char *dummy, GNode * node)
12677 len = QT_UINT32 (node->data);
12681 y = QT_UINT16 ((guint8 *) node->data + 12);
12683 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12686 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12688 date = g_date_new_dmy (1, 1, y);
12689 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12690 g_date_free (date);
12694 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12695 const char *tag, const char *dummy, GNode * node)
12698 char *tag_str = NULL;
12703 len = QT_UINT32 (node->data);
12708 entity = (guint8 *) node->data + offset;
12709 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12710 GST_DEBUG_OBJECT (qtdemux,
12711 "classification info: %c%c%c%c invalid classification entity",
12712 entity[0], entity[1], entity[2], entity[3]);
12717 table = QT_UINT16 ((guint8 *) node->data + offset);
12719 /* Language code skipped */
12723 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12724 * XXXX: classification entity, fixed length 4 chars.
12725 * Y[YYYY]: classification table, max 5 chars.
12727 tag_str = g_strdup_printf ("----://%u/%s",
12728 table, (char *) node->data + offset);
12730 /* memcpy To be sure we're preserving byte order */
12731 memcpy (tag_str, entity, 4);
12732 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12734 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12743 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12749 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12750 const char *tag, const char *dummy, GNode * node)
12752 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12758 gboolean ret = TRUE;
12759 const gchar *charset = NULL;
12761 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12763 len = QT_UINT32 (data->data);
12764 type = QT_UINT32 ((guint8 *) data->data + 8);
12765 if (type == 0x00000001 && len > 16) {
12766 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12769 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12770 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12773 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12777 len = QT_UINT32 (node->data);
12778 type = QT_UINT32 ((guint8 *) node->data + 4);
12779 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12783 /* Type starts with the (C) symbol, so the next data is a list
12784 * of (string size(16), language code(16), string) */
12786 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12787 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12789 /* the string + fourcc + size + 2 16bit fields,
12790 * means that there are more tags in this atom */
12791 if (len > str_len + 8 + 4) {
12792 /* TODO how to represent the same tag in different languages? */
12793 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12794 "text alternatives, reading only first one");
12798 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12799 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12801 if (lang_code < 0x800) { /* MAC encoded string */
12804 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12805 QT_FOURCC ((guint8 *) node->data + 4))) {
12806 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12808 /* we go for 3GP style encoding if major brands claims so,
12809 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12810 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12811 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12812 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12814 /* 16-bit Language code is ignored here as well */
12815 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12822 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12823 ret = FALSE; /* may have to fallback */
12826 GError *err = NULL;
12828 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12829 charset, NULL, NULL, &err);
12831 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12832 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12834 g_error_free (err);
12837 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12838 len - offset, env_vars);
12841 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12842 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12846 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12853 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12854 const char *tag, const char *dummy, GNode * node)
12856 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12860 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12861 const char *tag, const char *dummy, GNode * node)
12863 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12865 char *s, *t, *k = NULL;
12870 /* first try normal string tag if major brand not 3GP */
12871 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12872 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12873 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12874 * let's try it 3gpp way after minor safety check */
12876 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12882 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12886 len = QT_UINT32 (data);
12890 count = QT_UINT8 (data + 14);
12892 for (; count; count--) {
12895 if (offset + 1 > len)
12897 slen = QT_UINT8 (data + offset);
12899 if (offset + slen > len)
12901 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12904 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12906 t = g_strjoin (",", k, s, NULL);
12914 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12921 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12922 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12931 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12937 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12938 const char *tag1, const char *tag2, GNode * node)
12945 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12947 len = QT_UINT32 (data->data);
12948 type = QT_UINT32 ((guint8 *) data->data + 8);
12949 if (type == 0x00000000 && len >= 22) {
12950 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12951 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12953 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12954 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12957 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12958 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12965 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12966 const char *tag1, const char *dummy, GNode * node)
12973 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12975 len = QT_UINT32 (data->data);
12976 type = QT_UINT32 ((guint8 *) data->data + 8);
12977 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12978 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12979 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12980 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12982 /* do not add bpm=0 */
12983 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12984 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12992 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12993 const char *tag1, const char *dummy, GNode * node)
13000 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13002 len = QT_UINT32 (data->data);
13003 type = QT_UINT32 ((guint8 *) data->data + 8);
13004 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13005 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13006 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13007 num = QT_UINT32 ((guint8 *) data->data + 16);
13009 /* do not add num=0 */
13010 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13011 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13018 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13019 const char *tag1, const char *dummy, GNode * node)
13026 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13028 len = QT_UINT32 (data->data);
13029 type = QT_UINT32 ((guint8 *) data->data + 8);
13030 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13031 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13032 GstTagImageType image_type;
13034 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13035 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13037 image_type = GST_TAG_IMAGE_TYPE_NONE;
13040 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13041 len - 16, image_type))) {
13042 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13043 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13044 gst_sample_unref (sample);
13051 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
13052 const char *tag, const char *dummy, GNode * node)
13055 GstDateTime *datetime = NULL;
13060 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13062 len = QT_UINT32 (data->data);
13063 type = QT_UINT32 ((guint8 *) data->data + 8);
13064 if (type == 0x00000001 && len > 16) {
13065 guint y, m = 1, d = 1;
13068 s = g_strndup ((char *) data->data + 16, len - 16);
13069 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13070 datetime = gst_date_time_new_from_iso8601_string (s);
13071 if (datetime != NULL) {
13072 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13074 gst_date_time_unref (datetime);
13077 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13078 if (ret >= 1 && y > 1500 && y < 3000) {
13081 date = g_date_new_dmy (d, m, y);
13082 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13083 g_date_free (date);
13085 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13093 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13094 const char *tag, const char *dummy, GNode * node)
13098 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13100 /* re-route to normal string tag if major brand says so
13101 * or no data atom and compatible brand suggests so */
13102 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13103 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13104 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13109 guint len, type, n;
13111 len = QT_UINT32 (data->data);
13112 type = QT_UINT32 ((guint8 *) data->data + 8);
13113 if (type == 0x00000000 && len >= 18) {
13114 n = QT_UINT16 ((guint8 *) data->data + 16);
13116 const gchar *genre;
13118 genre = gst_tag_id3_genre_get (n - 1);
13119 if (genre != NULL) {
13120 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13121 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13129 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13130 const gchar * tag, guint8 * data, guint32 datasize)
13135 /* make a copy to have \0 at the end */
13136 datacopy = g_strndup ((gchar *) data, datasize);
13138 /* convert the str to double */
13139 if (sscanf (datacopy, "%lf", &value) == 1) {
13140 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13141 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13143 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13151 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13152 const char *tag, const char *tag_bis, GNode * node)
13161 const gchar *meanstr;
13162 const gchar *namestr;
13164 /* checking the whole ---- atom size for consistency */
13165 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13166 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13170 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13172 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13176 meansize = QT_UINT32 (mean->data);
13177 if (meansize <= 12) {
13178 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13181 meanstr = ((gchar *) mean->data) + 12;
13184 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13186 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13190 namesize = QT_UINT32 (name->data);
13191 if (namesize <= 12) {
13192 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13195 namestr = ((gchar *) name->data) + 12;
13203 * uint24 - data type
13207 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13209 GST_WARNING_OBJECT (demux, "No data atom in this tag");
13212 datasize = QT_UINT32 (data->data);
13213 if (datasize <= 16) {
13214 GST_WARNING_OBJECT (demux, "Data atom too small");
13217 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13219 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13220 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13221 static const struct
13223 const gchar name[28];
13224 const gchar tag[28];
13227 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13228 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13229 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13230 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13231 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13232 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13233 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13234 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13238 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13239 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13240 switch (gst_tag_get_type (tags[i].tag)) {
13241 case G_TYPE_DOUBLE:
13242 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13243 ((guint8 *) data->data) + 16, datasize - 16);
13245 case G_TYPE_STRING:
13246 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13255 if (i == G_N_ELEMENTS (tags))
13265 #ifndef GST_DISABLE_GST_DEBUG
13267 gchar *namestr_dbg;
13268 gchar *meanstr_dbg;
13270 meanstr_dbg = g_strndup (meanstr, meansize);
13271 namestr_dbg = g_strndup (namestr, namesize);
13273 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13274 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13276 g_free (namestr_dbg);
13277 g_free (meanstr_dbg);
13284 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13285 const char *tag_bis, GNode * node)
13290 GstTagList *id32_taglist = NULL;
13292 GST_LOG_OBJECT (demux, "parsing ID32");
13295 len = GST_READ_UINT32_BE (data);
13297 /* need at least full box and language tag */
13301 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13302 gst_buffer_fill (buf, 0, data + 14, len - 14);
13304 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13305 if (id32_taglist) {
13306 GST_LOG_OBJECT (demux, "parsing ok");
13307 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13308 gst_tag_list_unref (id32_taglist);
13310 GST_LOG_OBJECT (demux, "parsing failed");
13313 gst_buffer_unref (buf);
13316 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13317 const char *tag, const char *tag_bis, GNode * node);
13320 FOURCC_pcst -> if media is a podcast -> bool
13321 FOURCC_cpil -> if media is part of a compilation -> bool
13322 FOURCC_pgap -> if media is part of a gapless context -> bool
13323 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13326 static const struct
13329 const gchar *gst_tag;
13330 const gchar *gst_tag_bis;
13331 const GstQTDemuxAddTagFunc func;
13334 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13335 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13336 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13337 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13338 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13339 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13340 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13341 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13342 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13343 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13344 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13345 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13346 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13347 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13348 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13349 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13350 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13351 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13352 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13353 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13354 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13355 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13356 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13357 qtdemux_tag_add_num}, {
13358 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13359 qtdemux_tag_add_num}, {
13360 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13361 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13362 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13363 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13364 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13365 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13366 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13367 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13368 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13369 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13370 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13371 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13372 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13373 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13374 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13375 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13376 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13377 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13378 qtdemux_tag_add_classification}, {
13379 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13380 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13381 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13383 /* This is a special case, some tags are stored in this
13384 * 'reverse dns naming', according to:
13385 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13388 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13389 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13390 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13393 struct _GstQtDemuxTagList
13396 GstTagList *taglist;
13398 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13401 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13407 const gchar *style;
13412 GstQTDemux *demux = qtdemuxtaglist->demux;
13413 GstTagList *taglist = qtdemuxtaglist->taglist;
13416 len = QT_UINT32 (data);
13417 buf = gst_buffer_new_and_alloc (len);
13418 gst_buffer_fill (buf, 0, data, len);
13420 /* heuristic to determine style of tag */
13421 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13422 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13424 else if (demux->major_brand == FOURCC_qt__)
13425 style = "quicktime";
13426 /* fall back to assuming iso/3gp tag style */
13430 /* santize the name for the caps. */
13431 for (i = 0; i < 4; i++) {
13432 guint8 d = data[4 + i];
13433 if (g_ascii_isalnum (d))
13434 ndata[i] = g_ascii_tolower (d);
13439 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13440 ndata[0], ndata[1], ndata[2], ndata[3]);
13441 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13443 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13444 sample = gst_sample_new (buf, NULL, NULL, s);
13445 gst_buffer_unref (buf);
13446 g_free (media_type);
13448 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13451 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13452 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13454 gst_sample_unref (sample);
13458 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13465 GstQtDemuxTagList demuxtaglist;
13467 demuxtaglist.demux = qtdemux;
13468 demuxtaglist.taglist = taglist;
13470 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13471 if (meta != NULL) {
13472 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13473 if (ilst == NULL) {
13474 GST_LOG_OBJECT (qtdemux, "no ilst");
13479 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13483 while (i < G_N_ELEMENTS (add_funcs)) {
13484 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13488 len = QT_UINT32 (node->data);
13490 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13491 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13493 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13494 add_funcs[i].gst_tag_bis, node);
13496 g_node_destroy (node);
13502 /* parsed nodes have been removed, pass along remainder as blob */
13503 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13504 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13506 /* parse up XMP_ node if existing */
13507 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13508 if (xmp_ != NULL) {
13510 GstTagList *xmptaglist;
13512 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13513 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13514 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13515 gst_buffer_unref (buf);
13517 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13519 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13525 GstStructure *structure; /* helper for sort function */
13527 guint min_req_bitrate;
13528 guint min_req_qt_version;
13532 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13534 GstQtReference *ref_a = (GstQtReference *) a;
13535 GstQtReference *ref_b = (GstQtReference *) b;
13537 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13538 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13540 /* known bitrates go before unknown; higher bitrates go first */
13541 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13544 /* sort the redirects and post a message for the application.
13547 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13549 GstQtReference *best;
13552 GValue list_val = { 0, };
13555 g_assert (references != NULL);
13557 references = g_list_sort (references, qtdemux_redirects_sort_func);
13559 best = (GstQtReference *) references->data;
13561 g_value_init (&list_val, GST_TYPE_LIST);
13563 for (l = references; l != NULL; l = l->next) {
13564 GstQtReference *ref = (GstQtReference *) l->data;
13565 GValue struct_val = { 0, };
13567 ref->structure = gst_structure_new ("redirect",
13568 "new-location", G_TYPE_STRING, ref->location, NULL);
13570 if (ref->min_req_bitrate > 0) {
13571 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13572 ref->min_req_bitrate, NULL);
13575 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13576 g_value_set_boxed (&struct_val, ref->structure);
13577 gst_value_list_append_value (&list_val, &struct_val);
13578 g_value_unset (&struct_val);
13579 /* don't free anything here yet, since we need best->structure below */
13582 g_assert (best != NULL);
13583 s = gst_structure_copy (best->structure);
13585 if (g_list_length (references) > 1) {
13586 gst_structure_set_value (s, "locations", &list_val);
13589 g_value_unset (&list_val);
13591 for (l = references; l != NULL; l = l->next) {
13592 GstQtReference *ref = (GstQtReference *) l->data;
13594 gst_structure_free (ref->structure);
13595 g_free (ref->location);
13598 g_list_free (references);
13600 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13601 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13602 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13603 qtdemux->posted_redirect = TRUE;
13606 /* look for redirect nodes, collect all redirect information and
13610 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13612 GNode *rmra, *rmda, *rdrf;
13614 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13616 GList *redirects = NULL;
13618 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13620 GstQtReference ref = { NULL, NULL, 0, 0 };
13621 GNode *rmdr, *rmvc;
13623 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13624 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13625 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13626 ref.min_req_bitrate);
13629 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13630 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13631 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13633 #ifndef GST_DISABLE_GST_DEBUG
13634 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13636 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13638 GST_LOG_OBJECT (qtdemux,
13639 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13640 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13641 bitmask, check_type);
13642 if (package == FOURCC_qtim && check_type == 0) {
13643 ref.min_req_qt_version = version;
13647 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13653 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13654 if (ref_len > 20) {
13655 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13656 ref_data = (guint8 *) rdrf->data + 20;
13657 if (ref_type == FOURCC_alis) {
13658 guint record_len, record_version, fn_len;
13660 if (ref_len > 70) {
13661 /* MacOSX alias record, google for alias-layout.txt */
13662 record_len = QT_UINT16 (ref_data + 4);
13663 record_version = QT_UINT16 (ref_data + 4 + 2);
13664 fn_len = QT_UINT8 (ref_data + 50);
13665 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13666 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13669 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13672 } else if (ref_type == FOURCC_url_) {
13673 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13675 GST_DEBUG_OBJECT (qtdemux,
13676 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13677 GST_FOURCC_ARGS (ref_type));
13679 if (ref.location != NULL) {
13680 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13682 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13684 GST_WARNING_OBJECT (qtdemux,
13685 "Failed to extract redirect location from rdrf atom");
13688 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13692 /* look for others */
13693 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13696 if (redirects != NULL) {
13697 qtdemux_process_redirects (qtdemux, redirects);
13703 static GstTagList *
13704 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13708 if (tags == NULL) {
13709 tags = gst_tag_list_new_empty ();
13710 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13713 if (qtdemux->major_brand == FOURCC_mjp2)
13714 fmt = "Motion JPEG 2000";
13715 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13717 else if (qtdemux->major_brand == FOURCC_qt__)
13719 else if (qtdemux->fragmented)
13722 fmt = "ISO MP4/M4A";
13724 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13725 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13727 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13733 /* we have read the complete moov node now.
13734 * This function parses all of the relevant info, creates the traks and
13735 * prepares all data structures for playback
13738 qtdemux_parse_tree (GstQTDemux * qtdemux)
13745 guint64 creation_time;
13746 GstDateTime *datetime = NULL;
13749 /* make sure we have a usable taglist */
13750 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13752 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13753 if (mvhd == NULL) {
13754 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13755 return qtdemux_parse_redirects (qtdemux);
13758 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13759 if (version == 1) {
13760 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13761 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13762 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13763 } else if (version == 0) {
13764 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13765 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13766 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13768 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13772 /* Moving qt creation time (secs since 1904) to unix time */
13773 if (creation_time != 0) {
13774 /* Try to use epoch first as it should be faster and more commonly found */
13775 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13778 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13779 /* some data cleansing sanity */
13780 g_get_current_time (&now);
13781 if (now.tv_sec + 24 * 3600 < creation_time) {
13782 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13784 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13787 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13788 GDateTime *dt, *dt_local;
13790 dt = g_date_time_add_seconds (base_dt, creation_time);
13791 dt_local = g_date_time_to_local (dt);
13792 datetime = gst_date_time_new_from_g_date_time (dt_local);
13794 g_date_time_unref (base_dt);
13795 g_date_time_unref (dt);
13799 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13800 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13802 gst_date_time_unref (datetime);
13805 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13806 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13808 /* check for fragmented file and get some (default) data */
13809 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13812 GstByteReader mehd_data;
13814 /* let track parsing or anyone know weird stuff might happen ... */
13815 qtdemux->fragmented = TRUE;
13817 /* compensate for total duration */
13818 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13820 qtdemux_parse_mehd (qtdemux, &mehd_data);
13823 /* Update the movie segment duration, unless it was directly given to us
13824 * by upstream. Otherwise let it as is, as we don't want to mangle the
13825 * duration provided by upstream that may come e.g. from a MPD file. */
13826 if (!qtdemux->upstream_format_is_time) {
13827 GstClockTime duration;
13828 /* set duration in the segment info */
13829 gst_qtdemux_get_duration (qtdemux, &duration);
13830 qtdemux->segment.duration = duration;
13831 /* also do not exceed duration; stop is set that way post seek anyway,
13832 * and segment activation falls back to duration,
13833 * whereas loop only checks stop, so let's align this here as well */
13834 qtdemux->segment.stop = duration;
13837 /* parse all traks */
13838 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13840 qtdemux_parse_trak (qtdemux, trak);
13841 /* iterate all siblings */
13842 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13845 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13848 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13850 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13852 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13855 /* maybe also some tags in meta box */
13856 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13858 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13859 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13861 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13864 /* parse any protection system info */
13865 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13867 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13868 qtdemux_parse_pssh (qtdemux, pssh);
13869 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13872 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13877 /* taken from ffmpeg */
13879 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13891 len = (len << 7) | (c & 0x7f);
13900 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13901 gsize codec_data_size)
13903 GList *list = NULL;
13904 guint8 *p = codec_data;
13905 gint i, offset, num_packets;
13906 guint *length, last;
13908 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13910 if (codec_data == NULL || codec_data_size == 0)
13913 /* start of the stream and vorbis audio or theora video, need to
13914 * send the codec_priv data as first three packets */
13915 num_packets = p[0] + 1;
13916 GST_DEBUG_OBJECT (qtdemux,
13917 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13918 (guint) num_packets, codec_data_size);
13920 /* Let's put some limits, Don't think there even is a xiph codec
13921 * with more than 3-4 headers */
13922 if (G_UNLIKELY (num_packets > 16)) {
13923 GST_WARNING_OBJECT (qtdemux,
13924 "Unlikely number of xiph headers, most likely not valid");
13928 length = g_alloca (num_packets * sizeof (guint));
13932 /* first packets, read length values */
13933 for (i = 0; i < num_packets - 1; i++) {
13935 while (offset < codec_data_size) {
13936 length[i] += p[offset];
13937 if (p[offset++] != 0xff)
13942 if (offset + last > codec_data_size)
13945 /* last packet is the remaining size */
13946 length[i] = codec_data_size - offset - last;
13948 for (i = 0; i < num_packets; i++) {
13951 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13953 if (offset + length[i] > codec_data_size)
13956 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
13957 list = g_list_append (list, hdr);
13959 offset += length[i];
13968 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13974 /* this can change the codec originally present in @list */
13976 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13977 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13979 int len = QT_UINT32 (esds->data);
13980 guint8 *ptr = esds->data;
13981 guint8 *end = ptr + len;
13983 guint8 *data_ptr = NULL;
13985 guint8 object_type_id = 0;
13986 guint8 stream_type = 0;
13987 const char *codec_name = NULL;
13988 GstCaps *caps = NULL;
13990 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13992 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13994 while (ptr + 1 < end) {
13995 tag = QT_UINT8 (ptr);
13996 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13998 len = read_descr_size (ptr, end, &ptr);
13999 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14001 /* Check the stated amount of data is available for reading */
14002 if (len < 0 || ptr + len > end)
14006 case ES_DESCRIPTOR_TAG:
14007 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14008 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14011 case DECODER_CONFIG_DESC_TAG:{
14012 guint max_bitrate, avg_bitrate;
14014 object_type_id = QT_UINT8 (ptr);
14015 stream_type = QT_UINT8 (ptr + 1) >> 2;
14016 max_bitrate = QT_UINT32 (ptr + 5);
14017 avg_bitrate = QT_UINT32 (ptr + 9);
14018 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14019 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14020 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14021 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14022 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14023 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14024 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14025 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14027 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14028 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14029 avg_bitrate, NULL);
14034 case DECODER_SPECIFIC_INFO_TAG:
14035 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14036 if (object_type_id == 0xe0 && len == 0x40) {
14042 GST_DEBUG_OBJECT (qtdemux,
14043 "Have VOBSUB palette. Creating palette event");
14044 /* move to decConfigDescr data and read palette */
14046 for (i = 0; i < 16; i++) {
14047 clut[i] = QT_UINT32 (data);
14051 s = gst_structure_new ("application/x-gst-dvd", "event",
14052 G_TYPE_STRING, "dvd-spu-clut-change",
14053 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14054 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14055 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14056 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14057 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14058 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14059 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14060 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14063 /* store event and trigger custom processing */
14064 stream->pending_event =
14065 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14067 /* Generic codec_data handler puts it on the caps */
14074 case SL_CONFIG_DESC_TAG:
14075 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14079 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14081 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14087 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14088 * in use, and should also be used to override some other parameters for some
14090 switch (object_type_id) {
14091 case 0x20: /* MPEG-4 */
14092 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14093 * profile_and_level_indication */
14094 if (data_ptr != NULL && data_len >= 5 &&
14095 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14096 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14097 data_ptr + 4, data_len - 4);
14099 break; /* Nothing special needed here */
14100 case 0x21: /* H.264 */
14101 codec_name = "H.264 / AVC";
14102 caps = gst_caps_new_simple ("video/x-h264",
14103 "stream-format", G_TYPE_STRING, "avc",
14104 "alignment", G_TYPE_STRING, "au", NULL);
14106 case 0x40: /* AAC (any) */
14107 case 0x66: /* AAC Main */
14108 case 0x67: /* AAC LC */
14109 case 0x68: /* AAC SSR */
14110 /* Override channels and rate based on the codec_data, as it's often
14112 /* Only do so for basic setup without HE-AAC extension */
14113 if (data_ptr && data_len == 2) {
14114 guint channels, rate;
14116 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14118 entry->n_channels = channels;
14120 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14122 entry->rate = rate;
14125 /* Set level and profile if possible */
14126 if (data_ptr != NULL && data_len >= 2) {
14127 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14128 data_ptr, data_len);
14130 const gchar *profile_str = NULL;
14133 guint8 *codec_data;
14134 gint rate_idx, profile;
14136 /* No codec_data, let's invent something.
14137 * FIXME: This is wrong for SBR! */
14139 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14141 buffer = gst_buffer_new_and_alloc (2);
14142 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14143 codec_data = map.data;
14146 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14149 switch (object_type_id) {
14151 profile_str = "main";
14155 profile_str = "lc";
14159 profile_str = "ssr";
14167 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14169 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14171 gst_buffer_unmap (buffer, &map);
14172 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14173 GST_TYPE_BUFFER, buffer, NULL);
14174 gst_buffer_unref (buffer);
14177 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14178 G_TYPE_STRING, profile_str, NULL);
14182 case 0x60: /* MPEG-2, various profiles */
14188 codec_name = "MPEG-2 video";
14189 caps = gst_caps_new_simple ("video/mpeg",
14190 "mpegversion", G_TYPE_INT, 2,
14191 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14193 case 0x69: /* MPEG-2 BC audio */
14194 case 0x6B: /* MPEG-1 audio */
14195 caps = gst_caps_new_simple ("audio/mpeg",
14196 "mpegversion", G_TYPE_INT, 1, NULL);
14197 codec_name = "MPEG-1 audio";
14199 case 0x6A: /* MPEG-1 */
14200 codec_name = "MPEG-1 video";
14201 caps = gst_caps_new_simple ("video/mpeg",
14202 "mpegversion", G_TYPE_INT, 1,
14203 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14205 case 0x6C: /* MJPEG */
14207 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14209 codec_name = "Motion-JPEG";
14211 case 0x6D: /* PNG */
14213 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14215 codec_name = "PNG still images";
14217 case 0x6E: /* JPEG2000 */
14218 codec_name = "JPEG-2000";
14219 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14221 case 0xA4: /* Dirac */
14222 codec_name = "Dirac";
14223 caps = gst_caps_new_empty_simple ("video/x-dirac");
14225 case 0xA5: /* AC3 */
14226 codec_name = "AC-3 audio";
14227 caps = gst_caps_new_simple ("audio/x-ac3",
14228 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14230 case 0xA9: /* AC3 */
14231 codec_name = "DTS audio";
14232 caps = gst_caps_new_simple ("audio/x-dts",
14233 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14236 if (stream_type == 0x05 && data_ptr) {
14238 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14241 GValue arr_val = G_VALUE_INIT;
14242 GValue buf_val = G_VALUE_INIT;
14245 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14246 codec_name = "Vorbis";
14247 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14248 g_value_init (&arr_val, GST_TYPE_ARRAY);
14249 g_value_init (&buf_val, GST_TYPE_BUFFER);
14250 for (tmp = headers; tmp; tmp = tmp->next) {
14251 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14252 gst_value_array_append_value (&arr_val, &buf_val);
14254 s = gst_caps_get_structure (caps, 0);
14255 gst_structure_take_value (s, "streamheader", &arr_val);
14256 g_value_unset (&buf_val);
14257 g_list_free (headers);
14264 case 0xE1: /* QCELP */
14265 /* QCELP, the codec_data is a riff tag (little endian) with
14266 * 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). */
14267 caps = gst_caps_new_empty_simple ("audio/qcelp");
14268 codec_name = "QCELP";
14274 /* If we have a replacement caps, then change our caps for this stream */
14276 gst_caps_unref (entry->caps);
14277 entry->caps = caps;
14280 if (codec_name && list)
14281 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14282 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14284 /* Add the codec_data attribute to caps, if we have it */
14288 buffer = gst_buffer_new_and_alloc (data_len);
14289 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14291 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14292 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14294 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14296 gst_buffer_unref (buffer);
14301 static inline GstCaps *
14302 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14306 char *s, fourstr[5];
14308 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14309 for (i = 0; i < 4; i++) {
14310 if (!g_ascii_isalnum (fourstr[i]))
14313 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14314 caps = gst_caps_new_empty_simple (s);
14319 #define _codec(name) \
14321 if (codec_name) { \
14322 *codec_name = g_strdup (name); \
14327 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14328 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14329 const guint8 * stsd_entry_data, gchar ** codec_name)
14331 GstCaps *caps = NULL;
14332 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14336 _codec ("PNG still images");
14337 caps = gst_caps_new_empty_simple ("image/png");
14340 _codec ("JPEG still images");
14342 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14345 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14346 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14347 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14348 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14349 _codec ("Motion-JPEG");
14351 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14354 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14355 _codec ("Motion-JPEG format B");
14356 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14359 _codec ("JPEG-2000");
14360 /* override to what it should be according to spec, avoid palette_data */
14361 entry->bits_per_sample = 24;
14362 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14365 _codec ("Sorensen video v.3");
14366 caps = gst_caps_new_simple ("video/x-svq",
14367 "svqversion", G_TYPE_INT, 3, NULL);
14369 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14370 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14371 _codec ("Sorensen video v.1");
14372 caps = gst_caps_new_simple ("video/x-svq",
14373 "svqversion", G_TYPE_INT, 1, NULL);
14375 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14376 caps = gst_caps_new_empty_simple ("video/x-raw");
14377 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14378 _codec ("Windows Raw RGB");
14379 stream->alignment = 32;
14385 bps = QT_UINT16 (stsd_entry_data + 82);
14388 format = GST_VIDEO_FORMAT_RGB15;
14391 format = GST_VIDEO_FORMAT_RGB16;
14394 format = GST_VIDEO_FORMAT_RGB;
14397 format = GST_VIDEO_FORMAT_ARGB;
14405 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14406 format = GST_VIDEO_FORMAT_I420;
14408 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14409 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14410 format = GST_VIDEO_FORMAT_I420;
14413 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14414 format = GST_VIDEO_FORMAT_UYVY;
14416 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14417 format = GST_VIDEO_FORMAT_v308;
14419 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14420 format = GST_VIDEO_FORMAT_v216;
14423 format = GST_VIDEO_FORMAT_v210;
14425 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14426 format = GST_VIDEO_FORMAT_r210;
14428 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14429 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14430 format = GST_VIDEO_FORMAT_v410;
14433 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14434 * but different order than AYUV
14435 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14436 format = GST_VIDEO_FORMAT_v408;
14439 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14440 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14441 _codec ("MPEG-1 video");
14442 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14443 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14445 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14446 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14447 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14448 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14449 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14450 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14451 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14452 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14453 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14454 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14455 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14456 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14457 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14458 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14459 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14460 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14461 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14462 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14463 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14464 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14465 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14466 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14467 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14468 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14469 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14470 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14471 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14472 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14473 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14474 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14475 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14476 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14477 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14478 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14479 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14480 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14481 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14482 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14483 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14484 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14485 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14486 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14487 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14488 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14489 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14490 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14491 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14492 _codec ("MPEG-2 video");
14493 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14494 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14496 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14497 _codec ("GIF still images");
14498 caps = gst_caps_new_empty_simple ("image/gif");
14501 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14503 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14505 /* ffmpeg uses the height/width props, don't know why */
14506 caps = gst_caps_new_simple ("video/x-h263",
14507 "variant", G_TYPE_STRING, "itu", NULL);
14511 _codec ("MPEG-4 video");
14512 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14513 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14515 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14516 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14517 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14518 caps = gst_caps_new_simple ("video/x-msmpeg",
14519 "msmpegversion", G_TYPE_INT, 43, NULL);
14521 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14523 caps = gst_caps_new_simple ("video/x-divx",
14524 "divxversion", G_TYPE_INT, 3, NULL);
14526 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14527 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14529 caps = gst_caps_new_simple ("video/x-divx",
14530 "divxversion", G_TYPE_INT, 4, NULL);
14532 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14534 caps = gst_caps_new_simple ("video/x-divx",
14535 "divxversion", G_TYPE_INT, 5, NULL);
14538 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14540 caps = gst_caps_new_simple ("video/x-ffv",
14541 "ffvversion", G_TYPE_INT, 1, NULL);
14544 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14545 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14550 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14551 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14552 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14556 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14557 _codec ("Cinepak");
14558 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14560 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14561 _codec ("Apple QuickDraw");
14562 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14564 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14565 _codec ("Apple video");
14566 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14570 _codec ("H.264 / AVC");
14571 caps = gst_caps_new_simple ("video/x-h264",
14572 "stream-format", G_TYPE_STRING, "avc",
14573 "alignment", G_TYPE_STRING, "au", NULL);
14576 _codec ("H.264 / AVC");
14577 caps = gst_caps_new_simple ("video/x-h264",
14578 "stream-format", G_TYPE_STRING, "avc3",
14579 "alignment", G_TYPE_STRING, "au", NULL);
14583 _codec ("H.265 / HEVC");
14584 caps = gst_caps_new_simple ("video/x-h265",
14585 "stream-format", G_TYPE_STRING, "hvc1",
14586 "alignment", G_TYPE_STRING, "au", NULL);
14589 _codec ("H.265 / HEVC");
14590 caps = gst_caps_new_simple ("video/x-h265",
14591 "stream-format", G_TYPE_STRING, "hev1",
14592 "alignment", G_TYPE_STRING, "au", NULL);
14595 _codec ("Run-length encoding");
14596 caps = gst_caps_new_simple ("video/x-rle",
14597 "layout", G_TYPE_STRING, "quicktime", NULL);
14600 _codec ("Run-length encoding");
14601 caps = gst_caps_new_simple ("video/x-rle",
14602 "layout", G_TYPE_STRING, "microsoft", NULL);
14604 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14605 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14606 _codec ("Indeo Video 3");
14607 caps = gst_caps_new_simple ("video/x-indeo",
14608 "indeoversion", G_TYPE_INT, 3, NULL);
14610 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14611 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14612 _codec ("Intel Video 4");
14613 caps = gst_caps_new_simple ("video/x-indeo",
14614 "indeoversion", G_TYPE_INT, 4, NULL);
14618 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14619 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14620 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14621 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14622 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14623 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14624 _codec ("DV Video");
14625 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14626 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14628 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14629 case FOURCC_dv5p: /* DVCPRO50 PAL */
14630 _codec ("DVCPro50 Video");
14631 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14632 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14634 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14635 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14636 _codec ("DVCProHD Video");
14637 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14638 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14640 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14641 _codec ("Apple Graphics (SMC)");
14642 caps = gst_caps_new_empty_simple ("video/x-smc");
14644 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14646 caps = gst_caps_new_empty_simple ("video/x-vp3");
14648 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14649 _codec ("VP6 Flash");
14650 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14654 caps = gst_caps_new_empty_simple ("video/x-theora");
14655 /* theora uses one byte of padding in the data stream because it does not
14656 * allow 0 sized packets while theora does */
14657 entry->padding = 1;
14661 caps = gst_caps_new_empty_simple ("video/x-dirac");
14663 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14664 _codec ("TIFF still images");
14665 caps = gst_caps_new_empty_simple ("image/tiff");
14667 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14668 _codec ("Apple Intermediate Codec");
14669 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14671 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14672 _codec ("AVID DNxHD");
14673 caps = gst_caps_from_string ("video/x-dnxhd");
14677 _codec ("On2 VP8");
14678 caps = gst_caps_from_string ("video/x-vp8");
14681 _codec ("Google VP9");
14682 caps = gst_caps_from_string ("video/x-vp9");
14685 _codec ("Apple ProRes LT");
14687 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14691 _codec ("Apple ProRes HQ");
14693 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14697 _codec ("Apple ProRes");
14699 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14703 _codec ("Apple ProRes Proxy");
14705 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14709 _codec ("Apple ProRes 4444");
14711 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14715 _codec ("Apple ProRes 4444 XQ");
14717 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14721 _codec ("GoPro CineForm");
14722 caps = gst_caps_from_string ("video/x-cineform");
14727 caps = gst_caps_new_simple ("video/x-wmv",
14728 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14732 caps = gst_caps_new_empty_simple ("video/x-av1");
14734 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14737 caps = _get_unknown_codec_name ("video", fourcc);
14742 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14745 gst_video_info_init (&info);
14746 gst_video_info_set_format (&info, format, entry->width, entry->height);
14748 caps = gst_video_info_to_caps (&info);
14749 *codec_name = gst_pb_utils_get_codec_description (caps);
14751 /* enable clipping for raw video streams */
14752 stream->need_clip = TRUE;
14753 stream->alignment = 32;
14760 round_up_pow2 (guint n)
14772 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14773 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14774 int len, gchar ** codec_name)
14777 const GstStructure *s;
14780 GstAudioFormat format = 0;
14783 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14785 depth = entry->bytes_per_packet * 8;
14788 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14790 /* 8-bit audio is unsigned */
14792 format = GST_AUDIO_FORMAT_U8;
14793 /* otherwise it's signed and big-endian just like 'twos' */
14795 endian = G_BIG_ENDIAN;
14802 endian = G_LITTLE_ENDIAN;
14805 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14807 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14811 caps = gst_caps_new_simple ("audio/x-raw",
14812 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14813 "layout", G_TYPE_STRING, "interleaved", NULL);
14814 stream->alignment = GST_ROUND_UP_8 (depth);
14815 stream->alignment = round_up_pow2 (stream->alignment);
14818 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14819 _codec ("Raw 64-bit floating-point audio");
14820 caps = gst_caps_new_simple ("audio/x-raw",
14821 "format", G_TYPE_STRING, "F64BE",
14822 "layout", G_TYPE_STRING, "interleaved", NULL);
14823 stream->alignment = 8;
14825 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14826 _codec ("Raw 32-bit floating-point audio");
14827 caps = gst_caps_new_simple ("audio/x-raw",
14828 "format", G_TYPE_STRING, "F32BE",
14829 "layout", G_TYPE_STRING, "interleaved", NULL);
14830 stream->alignment = 4;
14833 _codec ("Raw 24-bit PCM audio");
14834 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14836 caps = gst_caps_new_simple ("audio/x-raw",
14837 "format", G_TYPE_STRING, "S24BE",
14838 "layout", G_TYPE_STRING, "interleaved", NULL);
14839 stream->alignment = 4;
14841 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14842 _codec ("Raw 32-bit PCM audio");
14843 caps = gst_caps_new_simple ("audio/x-raw",
14844 "format", G_TYPE_STRING, "S32BE",
14845 "layout", G_TYPE_STRING, "interleaved", NULL);
14846 stream->alignment = 4;
14848 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14849 _codec ("Raw 16-bit PCM audio");
14850 caps = gst_caps_new_simple ("audio/x-raw",
14851 "format", G_TYPE_STRING, "S16LE",
14852 "layout", G_TYPE_STRING, "interleaved", NULL);
14853 stream->alignment = 2;
14856 _codec ("Mu-law audio");
14857 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14860 _codec ("A-law audio");
14861 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14865 _codec ("Microsoft ADPCM");
14866 /* Microsoft ADPCM-ACM code 2 */
14867 caps = gst_caps_new_simple ("audio/x-adpcm",
14868 "layout", G_TYPE_STRING, "microsoft", NULL);
14872 _codec ("DVI/IMA ADPCM");
14873 caps = gst_caps_new_simple ("audio/x-adpcm",
14874 "layout", G_TYPE_STRING, "dvi", NULL);
14878 _codec ("DVI/Intel IMA ADPCM");
14879 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14880 caps = gst_caps_new_simple ("audio/x-adpcm",
14881 "layout", G_TYPE_STRING, "quicktime", NULL);
14885 /* MPEG layer 3, CBR only (pre QT4.1) */
14887 _codec ("MPEG-1 layer 3");
14888 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14889 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14890 "mpegversion", G_TYPE_INT, 1, NULL);
14892 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14893 _codec ("MPEG-1 layer 2");
14895 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14896 "mpegversion", G_TYPE_INT, 1, NULL);
14899 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14900 _codec ("EAC-3 audio");
14901 caps = gst_caps_new_simple ("audio/x-eac3",
14902 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14903 entry->sampled = TRUE;
14905 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14907 _codec ("AC-3 audio");
14908 caps = gst_caps_new_simple ("audio/x-ac3",
14909 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14910 entry->sampled = TRUE;
14912 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14913 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14914 _codec ("DTS audio");
14915 caps = gst_caps_new_simple ("audio/x-dts",
14916 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14917 entry->sampled = TRUE;
14919 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14920 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14921 _codec ("DTS-HD audio");
14922 caps = gst_caps_new_simple ("audio/x-dts",
14923 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14924 entry->sampled = TRUE;
14928 caps = gst_caps_new_simple ("audio/x-mace",
14929 "maceversion", G_TYPE_INT, 3, NULL);
14933 caps = gst_caps_new_simple ("audio/x-mace",
14934 "maceversion", G_TYPE_INT, 6, NULL);
14936 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14938 caps = gst_caps_new_empty_simple ("application/ogg");
14940 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14941 _codec ("DV audio");
14942 caps = gst_caps_new_empty_simple ("audio/x-dv");
14945 _codec ("MPEG-4 AAC audio");
14946 caps = gst_caps_new_simple ("audio/mpeg",
14947 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14948 "stream-format", G_TYPE_STRING, "raw", NULL);
14950 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14951 _codec ("QDesign Music");
14952 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14955 _codec ("QDesign Music v.2");
14956 /* FIXME: QDesign music version 2 (no constant) */
14957 if (FALSE && data) {
14958 caps = gst_caps_new_simple ("audio/x-qdm2",
14959 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14960 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14961 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14963 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14967 _codec ("GSM audio");
14968 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14971 _codec ("AMR audio");
14972 caps = gst_caps_new_empty_simple ("audio/AMR");
14975 _codec ("AMR-WB audio");
14976 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14979 _codec ("Quicktime IMA ADPCM");
14980 caps = gst_caps_new_simple ("audio/x-adpcm",
14981 "layout", G_TYPE_STRING, "quicktime", NULL);
14984 _codec ("Apple lossless audio");
14985 caps = gst_caps_new_empty_simple ("audio/x-alac");
14988 _codec ("Free Lossless Audio Codec");
14989 caps = gst_caps_new_simple ("audio/x-flac",
14990 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14992 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14993 _codec ("QualComm PureVoice");
14994 caps = gst_caps_from_string ("audio/qcelp");
14999 caps = gst_caps_new_empty_simple ("audio/x-wma");
15003 caps = gst_caps_new_empty_simple ("audio/x-opus");
15010 GstAudioFormat format;
15013 FLAG_IS_FLOAT = 0x1,
15014 FLAG_IS_BIG_ENDIAN = 0x2,
15015 FLAG_IS_SIGNED = 0x4,
15016 FLAG_IS_PACKED = 0x8,
15017 FLAG_IS_ALIGNED_HIGH = 0x10,
15018 FLAG_IS_NON_INTERLEAVED = 0x20
15020 _codec ("Raw LPCM audio");
15022 if (data && len >= 36) {
15023 depth = QT_UINT32 (data + 24);
15024 flags = QT_UINT32 (data + 28);
15025 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15027 if ((flags & FLAG_IS_FLOAT) == 0) {
15032 if ((flags & FLAG_IS_ALIGNED_HIGH))
15035 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15036 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15037 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15038 caps = gst_caps_new_simple ("audio/x-raw",
15039 "format", G_TYPE_STRING,
15041 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15042 "UNKNOWN", "layout", G_TYPE_STRING,
15043 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15044 "interleaved", NULL);
15045 stream->alignment = GST_ROUND_UP_8 (depth);
15046 stream->alignment = round_up_pow2 (stream->alignment);
15051 if (flags & FLAG_IS_BIG_ENDIAN)
15052 format = GST_AUDIO_FORMAT_F64BE;
15054 format = GST_AUDIO_FORMAT_F64LE;
15056 if (flags & FLAG_IS_BIG_ENDIAN)
15057 format = GST_AUDIO_FORMAT_F32BE;
15059 format = GST_AUDIO_FORMAT_F32LE;
15061 caps = gst_caps_new_simple ("audio/x-raw",
15062 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15063 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15064 "non-interleaved" : "interleaved", NULL);
15065 stream->alignment = width / 8;
15069 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15073 caps = _get_unknown_codec_name ("audio", fourcc);
15079 GstCaps *templ_caps =
15080 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15081 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15082 gst_caps_unref (caps);
15083 gst_caps_unref (templ_caps);
15084 caps = intersection;
15087 /* enable clipping for raw audio streams */
15088 s = gst_caps_get_structure (caps, 0);
15089 name = gst_structure_get_name (s);
15090 if (g_str_has_prefix (name, "audio/x-raw")) {
15091 stream->need_clip = TRUE;
15092 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15093 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15099 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15100 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15101 const guint8 * stsd_entry_data, gchar ** codec_name)
15105 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15109 _codec ("DVD subtitle");
15110 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15111 stream->need_process = TRUE;
15114 _codec ("Quicktime timed text");
15117 _codec ("3GPP timed text");
15119 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15121 /* actual text piece needs to be extracted */
15122 stream->need_process = TRUE;
15125 _codec ("XML subtitles");
15126 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15129 _codec ("CEA 608 Closed Caption");
15131 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15132 G_TYPE_STRING, "cc_data", NULL);
15133 stream->need_process = TRUE;
15136 _codec ("CEA 708 Closed Caption");
15138 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15139 G_TYPE_STRING, "cdp", NULL);
15140 stream->need_process = TRUE;
15145 caps = _get_unknown_codec_name ("text", fourcc);
15153 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15154 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15155 const guint8 * stsd_entry_data, gchar ** codec_name)
15161 _codec ("MPEG 1 video");
15162 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15163 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15173 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15174 const gchar * system_id)
15178 if (!qtdemux->protection_system_ids)
15179 qtdemux->protection_system_ids =
15180 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15181 /* Check whether we already have an entry for this system ID. */
15182 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15183 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15184 if (g_ascii_strcasecmp (system_id, id) == 0) {
15188 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15189 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,