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 GstStaticPadTemplate gst_qtdemux_sink_template =
488 GST_STATIC_PAD_TEMPLATE ("sink",
491 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
495 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
496 GST_STATIC_PAD_TEMPLATE ("video_%u",
499 GST_STATIC_CAPS_ANY);
501 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
502 GST_STATIC_PAD_TEMPLATE ("audio_%u",
505 GST_STATIC_CAPS_ANY);
507 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
508 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
511 GST_STATIC_CAPS_ANY);
513 #define gst_qtdemux_parent_class parent_class
514 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
516 static void gst_qtdemux_dispose (GObject * object);
519 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
520 GstClockTime media_time);
522 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
523 QtDemuxStream * str, gint64 media_offset);
526 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
527 static GstIndex *gst_qtdemux_get_index (GstElement * element);
529 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
530 GstStateChange transition);
531 static void gst_qtdemux_set_context (GstElement * element,
532 GstContext * context);
533 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
534 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
535 GstObject * parent, GstPadMode mode, gboolean active);
537 static void gst_qtdemux_loop (GstPad * pad);
538 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
540 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
542 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
543 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
544 QtDemuxStream * stream);
545 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
546 QtDemuxStream * stream);
547 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
549 static GstClockTime gst_qtdemux_streams_get_first_sample_ts (GstQTDemux *
551 static GstClockTime gst_qtdemux_streams_have_samples (GstQTDemux * demux);
553 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
554 const guint8 * buffer, guint length);
555 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
556 const guint8 * buffer, guint length);
557 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
558 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
561 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
562 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
564 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
565 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
566 const guint8 * stsd_entry_data, gchar ** codec_name);
567 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
568 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
569 const guint8 * data, int len, gchar ** codec_name);
570 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
571 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
572 gchar ** codec_name);
573 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
574 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
575 const guint8 * stsd_entry_data, gchar ** codec_name);
577 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
578 QtDemuxStream * stream, guint32 n);
579 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
580 static void gst_qtdemux_stream_free (QtDemuxStream * stream);
581 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
582 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux,
583 QtDemuxStream * stream);
584 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
585 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
586 QtDemuxStream * stream);
587 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
588 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
589 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
590 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
591 GstClockTime * _start, GstClockTime * _stop);
592 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
593 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
595 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
596 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
598 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
600 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
601 QtDemuxStream * stream, guint sample_index);
602 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
604 static void qtdemux_gst_structure_free (GstStructure * gststructure);
605 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
608 gst_qtdemux_class_init (GstQTDemuxClass * klass)
610 GObjectClass *gobject_class;
611 GstElementClass *gstelement_class;
613 gobject_class = (GObjectClass *) klass;
614 gstelement_class = (GstElementClass *) klass;
616 parent_class = g_type_class_peek_parent (klass);
618 gobject_class->dispose = gst_qtdemux_dispose;
620 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
622 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
623 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
625 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
627 gst_tag_register_musicbrainz_tags ();
629 gst_element_class_add_static_pad_template (gstelement_class,
630 &gst_qtdemux_sink_template);
631 gst_element_class_add_static_pad_template (gstelement_class,
632 &gst_qtdemux_videosrc_template);
633 gst_element_class_add_static_pad_template (gstelement_class,
634 &gst_qtdemux_audiosrc_template);
635 gst_element_class_add_static_pad_template (gstelement_class,
636 &gst_qtdemux_subsrc_template);
637 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
639 "Demultiplex a QuickTime file into audio and video streams",
640 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
642 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
647 gst_qtdemux_init (GstQTDemux * qtdemux)
650 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
651 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
652 gst_pad_set_activatemode_function (qtdemux->sinkpad,
653 qtdemux_sink_activate_mode);
654 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
655 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
656 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
658 qtdemux->adapter = gst_adapter_new ();
659 g_queue_init (&qtdemux->protection_event_queue);
660 qtdemux->flowcombiner = gst_flow_combiner_new ();
661 g_mutex_init (&qtdemux->expose_lock);
663 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
665 gst_qtdemux_reset (qtdemux, TRUE);
669 gst_qtdemux_dispose (GObject * object)
671 GstQTDemux *qtdemux = GST_QTDEMUX (object);
673 if (qtdemux->adapter) {
674 g_object_unref (G_OBJECT (qtdemux->adapter));
675 qtdemux->adapter = NULL;
677 gst_tag_list_unref (qtdemux->tag_list);
678 gst_flow_combiner_free (qtdemux->flowcombiner);
679 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
681 g_queue_clear (&qtdemux->protection_event_queue);
683 g_free (qtdemux->cenc_aux_info_sizes);
684 qtdemux->cenc_aux_info_sizes = NULL;
685 g_mutex_clear (&qtdemux->expose_lock);
687 G_OBJECT_CLASS (parent_class)->dispose (object);
691 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
693 if (qtdemux->posted_redirect) {
694 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
695 (_("This file contains no playable streams.")),
696 ("no known streams found, a redirect message has been posted"));
698 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
699 (_("This file contains no playable streams.")),
700 ("no known streams found"));
705 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
707 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
708 mem, size, 0, size, mem, free_func);
712 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
719 if (G_UNLIKELY (size == 0)) {
721 GstBuffer *tmp = NULL;
723 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
724 if (ret != GST_FLOW_OK)
727 gst_buffer_map (tmp, &map, GST_MAP_READ);
728 size = QT_UINT32 (map.data);
729 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
731 gst_buffer_unmap (tmp, &map);
732 gst_buffer_unref (tmp);
735 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
736 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
737 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
738 /* we're pulling header but already got most interesting bits,
739 * so never mind the rest (e.g. tags) (that much) */
740 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
744 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
745 (_("This file is invalid and cannot be played.")),
746 ("atom has bogus size %" G_GUINT64_FORMAT, size));
747 return GST_FLOW_ERROR;
751 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
753 if (G_UNLIKELY (flow != GST_FLOW_OK))
756 bsize = gst_buffer_get_size (*buf);
757 /* Catch short reads - we don't want any partial atoms */
758 if (G_UNLIKELY (bsize < size)) {
759 GST_WARNING_OBJECT (qtdemux,
760 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
761 gst_buffer_unref (*buf);
771 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
772 GstFormat src_format, gint64 src_value, GstFormat dest_format,
776 QtDemuxStream *stream = gst_pad_get_element_private (pad);
779 if (stream->subtype != FOURCC_vide) {
784 switch (src_format) {
785 case GST_FORMAT_TIME:
786 switch (dest_format) {
787 case GST_FORMAT_BYTES:{
788 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
794 *dest_value = stream->samples[index].offset;
796 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
797 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
798 GST_TIME_ARGS (src_value), *dest_value);
806 case GST_FORMAT_BYTES:
807 switch (dest_format) {
808 case GST_FORMAT_TIME:{
810 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
819 QTSTREAMTIME_TO_GSTTIME (stream,
820 stream->samples[index].timestamp);
821 GST_DEBUG_OBJECT (qtdemux,
822 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
823 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
842 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
844 gboolean res = FALSE;
846 *duration = GST_CLOCK_TIME_NONE;
848 if (qtdemux->duration != 0 &&
849 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
850 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
853 *duration = GST_CLOCK_TIME_NONE;
860 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
863 gboolean res = FALSE;
864 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
866 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
868 switch (GST_QUERY_TYPE (query)) {
869 case GST_QUERY_POSITION:{
872 gst_query_parse_position (query, &fmt, NULL);
873 if (fmt == GST_FORMAT_TIME
874 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
875 gst_query_set_position (query, GST_FORMAT_TIME,
876 qtdemux->segment.position);
881 case GST_QUERY_DURATION:{
884 gst_query_parse_duration (query, &fmt, NULL);
885 if (fmt == GST_FORMAT_TIME) {
886 /* First try to query upstream */
887 res = gst_pad_query_default (pad, parent, query);
889 GstClockTime duration;
890 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
891 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
898 case GST_QUERY_CONVERT:{
899 GstFormat src_fmt, dest_fmt;
900 gint64 src_value, dest_value = 0;
902 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
904 res = gst_qtdemux_src_convert (qtdemux, pad,
905 src_fmt, src_value, dest_fmt, &dest_value);
907 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
911 case GST_QUERY_FORMATS:
912 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
915 case GST_QUERY_SEEKING:{
919 /* try upstream first */
920 res = gst_pad_query_default (pad, parent, query);
923 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
924 if (fmt == GST_FORMAT_TIME) {
925 GstClockTime duration;
927 gst_qtdemux_get_duration (qtdemux, &duration);
929 if (!qtdemux->pullbased) {
932 /* we might be able with help from upstream */
934 q = gst_query_new_seeking (GST_FORMAT_BYTES);
935 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
936 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
937 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
941 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
947 case GST_QUERY_SEGMENT:
952 format = qtdemux->segment.format;
955 gst_segment_to_stream_time (&qtdemux->segment, format,
956 qtdemux->segment.start);
957 if ((stop = qtdemux->segment.stop) == -1)
958 stop = qtdemux->segment.duration;
960 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
962 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
967 res = gst_pad_query_default (pad, parent, query);
975 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
977 if (G_LIKELY (stream->pad)) {
978 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
979 GST_DEBUG_PAD_NAME (stream->pad));
981 if (!gst_tag_list_is_empty (stream->stream_tags)) {
982 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
983 stream->stream_tags);
984 gst_pad_push_event (stream->pad,
985 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
988 if (G_UNLIKELY (stream->send_global_tags)) {
989 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
991 gst_pad_push_event (stream->pad,
992 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
993 stream->send_global_tags = FALSE;
998 /* push event on all source pads; takes ownership of the event */
1000 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1002 gboolean has_valid_stream = FALSE;
1003 GstEventType etype = GST_EVENT_TYPE (event);
1006 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1007 GST_EVENT_TYPE_NAME (event));
1009 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1011 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1012 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1014 if ((pad = stream->pad)) {
1015 has_valid_stream = TRUE;
1017 if (etype == GST_EVENT_EOS) {
1018 /* let's not send twice */
1019 if (stream->sent_eos)
1021 stream->sent_eos = TRUE;
1024 gst_pad_push_event (pad, gst_event_ref (event));
1028 gst_event_unref (event);
1030 /* if it is EOS and there are no pads, post an error */
1031 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1032 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1036 /* push a pending newsegment event, if any from the streaming thread */
1038 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1040 if (G_UNLIKELY (qtdemux->need_segment)) {
1041 GstEvent *newsegment;
1043 if (!qtdemux->upstream_format_is_time) {
1044 GstClockTime min_ts;
1046 if (!gst_qtdemux_streams_have_samples (qtdemux)) {
1047 /* No samples yet, can't decide on segment.start */
1048 GST_DEBUG_OBJECT (qtdemux, "No samples yet, postponing segment event");
1052 min_ts = gst_qtdemux_streams_get_first_sample_ts (qtdemux);
1054 /* have_samples() above should guarantee we have a valid time */
1055 g_assert (GST_CLOCK_TIME_IS_VALID (min_ts));
1057 qtdemux->segment.start = min_ts;
1060 newsegment = gst_event_new_segment (&qtdemux->segment);
1061 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
1062 gst_event_set_seqnum (newsegment, qtdemux->segment_seqnum);
1063 qtdemux->need_segment = FALSE;
1064 gst_qtdemux_push_event (qtdemux, newsegment);
1074 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1076 if ((gint64) s1->timestamp > *media_time)
1078 if ((gint64) s1->timestamp == *media_time)
1084 /* find the index of the sample that includes the data for @media_time using a
1085 * binary search. Only to be called in optimized cases of linear search below.
1087 * Returns the index of the sample with the corresponding *DTS*.
1090 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1093 QtDemuxSample *result;
1096 /* convert media_time to mov format */
1098 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1100 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1101 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1102 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1104 if (G_LIKELY (result))
1105 index = result - str->samples;
1114 /* find the index of the sample that includes the data for @media_offset using a
1117 * Returns the index of the sample.
1120 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1121 QtDemuxStream * str, gint64 media_offset)
1123 QtDemuxSample *result = str->samples;
1126 if (result == NULL || str->n_samples == 0)
1129 if (media_offset == result->offset)
1133 while (index < str->n_samples - 1) {
1134 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1137 if (media_offset < result->offset)
1148 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1153 /* find the index of the sample that includes the data for @media_time using a
1154 * linear search, and keeping in mind that not all samples may have been parsed
1155 * yet. If possible, it will delegate to binary search.
1157 * Returns the index of the sample.
1160 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1161 GstClockTime media_time)
1165 QtDemuxSample *sample;
1167 /* convert media_time to mov format */
1169 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1171 sample = str->samples;
1172 if (mov_time == sample->timestamp + sample->pts_offset)
1175 /* use faster search if requested time in already parsed range */
1176 sample = str->samples + str->stbl_index;
1177 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1178 index = gst_qtdemux_find_index (qtdemux, str, media_time);
1179 sample = str->samples + index;
1181 while (index < str->n_samples - 1) {
1182 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1185 sample = str->samples + index + 1;
1186 if (mov_time < sample->timestamp) {
1187 sample = str->samples + index;
1195 /* sample->timestamp is now <= media_time, need to find the corresponding
1196 * PTS now by looking backwards */
1197 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1199 sample = str->samples + index;
1207 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1212 /* find the index of the keyframe needed to decode the sample at @index
1213 * of stream @str, or of a subsequent keyframe (depending on @next)
1215 * Returns the index of the keyframe.
1218 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1219 guint32 index, gboolean next)
1221 guint32 new_index = index;
1223 if (index >= str->n_samples) {
1224 new_index = str->n_samples;
1228 /* all keyframes, return index */
1229 if (str->all_keyframe) {
1234 /* else search until we have a keyframe */
1235 while (new_index < str->n_samples) {
1236 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1239 if (str->samples[new_index].keyframe)
1251 if (new_index == str->n_samples) {
1252 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1257 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1258 "gave %u", next ? "after" : "before", index, new_index);
1265 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1270 /* find the segment for @time_position for @stream
1272 * Returns the index of the segment containing @time_position.
1273 * Returns the last segment and sets the @eos variable to TRUE
1274 * if the time is beyond the end. @eos may be NULL
1277 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1278 GstClockTime time_position)
1283 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1284 GST_TIME_ARGS (time_position));
1287 for (i = 0; i < stream->n_segments; i++) {
1288 QtDemuxSegment *segment = &stream->segments[i];
1290 GST_LOG_OBJECT (stream->pad,
1291 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1292 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1294 /* For the last segment we include stop_time in the last segment */
1295 if (i < stream->n_segments - 1) {
1296 if (segment->time <= time_position && time_position < segment->stop_time) {
1297 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1302 /* Last segment always matches */
1310 /* move the stream @str to the sample position @index.
1312 * Updates @str->sample_index and marks discontinuity if needed.
1315 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1318 /* no change needed */
1319 if (index == str->sample_index)
1322 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1325 /* position changed, we have a discont */
1326 str->sample_index = index;
1327 str->offset_in_sample = 0;
1328 /* Each time we move in the stream we store the position where we are
1330 str->from_sample = index;
1331 str->discont = TRUE;
1335 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1336 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1339 gint64 min_byte_offset = -1;
1342 min_offset = desired_time;
1344 /* for each stream, find the index of the sample in the segment
1345 * and move back to the previous keyframe. */
1346 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1348 guint32 index, kindex;
1350 GstClockTime media_start;
1351 GstClockTime media_time;
1352 GstClockTime seg_time;
1353 QtDemuxSegment *seg;
1354 gboolean empty_segment = FALSE;
1356 str = QTDEMUX_STREAM (iter->data);
1358 if (CUR_STREAM (str)->sparse && !use_sparse)
1361 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1362 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1364 /* get segment and time in the segment */
1365 seg = &str->segments[seg_idx];
1366 seg_time = (desired_time - seg->time) * seg->rate;
1368 while (QTSEGMENT_IS_EMPTY (seg)) {
1370 empty_segment = TRUE;
1371 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1374 if (seg_idx == str->n_segments)
1376 seg = &str->segments[seg_idx];
1379 if (seg_idx == str->n_segments) {
1380 /* FIXME track shouldn't have the last segment as empty, but if it
1381 * happens we better handle it */
1385 /* get the media time in the segment */
1386 media_start = seg->media_start + seg_time;
1388 /* get the index of the sample with media time */
1389 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1390 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1391 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1392 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1395 /* shift to next frame if we are looking for next keyframe */
1396 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1397 && index < str->stbl_index)
1400 if (!empty_segment) {
1401 /* find previous keyframe */
1402 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1404 /* we will settle for one before if none found after */
1405 if (next && kindex == -1)
1406 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1408 /* if the keyframe is at a different position, we need to update the
1409 * requested seek time */
1410 if (index != kindex) {
1413 /* get timestamp of keyframe */
1414 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1415 GST_DEBUG_OBJECT (qtdemux,
1416 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1417 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1418 str->samples[kindex].offset);
1420 /* keyframes in the segment get a chance to change the
1421 * desired_offset. keyframes out of the segment are
1423 if (media_time >= seg->media_start) {
1424 GstClockTime seg_time;
1426 /* this keyframe is inside the segment, convert back to
1428 seg_time = (media_time - seg->media_start) + seg->time;
1429 if ((!next && (seg_time < min_offset)) ||
1430 (next && (seg_time > min_offset)))
1431 min_offset = seg_time;
1436 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1437 min_byte_offset = str->samples[index].offset;
1441 *key_time = min_offset;
1443 *key_offset = min_byte_offset;
1447 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1448 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1452 g_return_val_if_fail (format != NULL, FALSE);
1453 g_return_val_if_fail (cur != NULL, FALSE);
1454 g_return_val_if_fail (stop != NULL, FALSE);
1456 if (*format == GST_FORMAT_TIME)
1460 if (cur_type != GST_SEEK_TYPE_NONE)
1461 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1462 if (res && stop_type != GST_SEEK_TYPE_NONE)
1463 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1466 *format = GST_FORMAT_TIME;
1471 /* perform seek in push based mode:
1472 find BYTE position to move to based on time and delegate to upstream
1475 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1480 GstSeekType cur_type, stop_type;
1481 gint64 cur, stop, key_cur;
1484 gint64 original_stop;
1487 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1489 gst_event_parse_seek (event, &rate, &format, &flags,
1490 &cur_type, &cur, &stop_type, &stop);
1491 seqnum = gst_event_get_seqnum (event);
1493 /* only forward streaming and seeking is possible */
1495 goto unsupported_seek;
1497 /* convert to TIME if needed and possible */
1498 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1502 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1503 * the original stop position to use when upstream pushes the new segment
1505 original_stop = stop;
1508 /* find reasonable corresponding BYTE position,
1509 * also try to mind about keyframes, since we can not go back a bit for them
1511 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1512 * mostly just work, but let's not yet boldly go there ... */
1513 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1518 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1519 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1522 GST_OBJECT_LOCK (qtdemux);
1523 qtdemux->seek_offset = byte_cur;
1524 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1525 qtdemux->push_seek_start = cur;
1527 qtdemux->push_seek_start = key_cur;
1530 if (stop_type == GST_SEEK_TYPE_NONE) {
1531 qtdemux->push_seek_stop = qtdemux->segment.stop;
1533 qtdemux->push_seek_stop = original_stop;
1535 GST_OBJECT_UNLOCK (qtdemux);
1537 /* BYTE seek event */
1538 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1540 gst_event_set_seqnum (event, seqnum);
1541 res = gst_pad_push_event (qtdemux->sinkpad, event);
1548 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1554 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1559 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1564 /* perform the seek.
1566 * We set all segment_indexes in the streams to unknown and
1567 * adjust the time_position to the desired position. this is enough
1568 * to trigger a segment switch in the streaming thread to start
1569 * streaming from the desired position.
1571 * Keyframe seeking is a little more complicated when dealing with
1572 * segments. Ideally we want to move to the previous keyframe in
1573 * the segment but there might not be a keyframe in the segment. In
1574 * fact, none of the segments could contain a keyframe. We take a
1575 * practical approach: seek to the previous keyframe in the segment,
1576 * if there is none, seek to the beginning of the segment.
1578 * Called with STREAM_LOCK
1581 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1582 guint32 seqnum, GstSeekFlags flags)
1584 gint64 desired_offset;
1587 desired_offset = segment->position;
1589 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1590 GST_TIME_ARGS (desired_offset));
1592 /* may not have enough fragmented info to do this adjustment,
1593 * and we can't scan (and probably should not) at this time with
1594 * possibly flushing upstream */
1595 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1597 gboolean next, before, after;
1599 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1600 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1601 next = after && !before;
1602 if (segment->rate < 0)
1605 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1607 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1608 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1609 desired_offset = min_offset;
1612 /* and set all streams to the final position */
1613 gst_flow_combiner_reset (qtdemux->flowcombiner);
1614 qtdemux->segment_seqnum = seqnum;
1615 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1616 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1618 stream->time_position = desired_offset;
1619 stream->accumulated_base = 0;
1620 stream->sample_index = -1;
1621 stream->offset_in_sample = 0;
1622 stream->segment_index = -1;
1623 stream->sent_eos = FALSE;
1625 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1626 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1628 segment->position = desired_offset;
1629 segment->time = desired_offset;
1630 if (segment->rate >= 0) {
1631 segment->start = desired_offset;
1633 /* we stop at the end */
1634 if (segment->stop == -1)
1635 segment->stop = segment->duration;
1637 segment->stop = desired_offset;
1640 if (qtdemux->fragmented)
1641 qtdemux->fragmented_seek_pending = TRUE;
1646 /* do a seek in pull based mode */
1648 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1653 GstSeekType cur_type, stop_type;
1657 GstSegment seeksegment;
1658 guint32 seqnum = GST_SEQNUM_INVALID;
1659 GstEvent *flush_event;
1663 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1665 gst_event_parse_seek (event, &rate, &format, &flags,
1666 &cur_type, &cur, &stop_type, &stop);
1667 seqnum = gst_event_get_seqnum (event);
1669 /* we have to have a format as the segment format. Try to convert
1671 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1675 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1677 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1681 flush = flags & GST_SEEK_FLAG_FLUSH;
1683 /* stop streaming, either by flushing or by pausing the task */
1685 flush_event = gst_event_new_flush_start ();
1686 if (seqnum != GST_SEQNUM_INVALID)
1687 gst_event_set_seqnum (flush_event, seqnum);
1688 /* unlock upstream pull_range */
1689 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1690 /* make sure out loop function exits */
1691 gst_qtdemux_push_event (qtdemux, flush_event);
1693 /* non flushing seek, pause the task */
1694 gst_pad_pause_task (qtdemux->sinkpad);
1697 /* wait for streaming to finish */
1698 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1700 /* copy segment, we need this because we still need the old
1701 * segment when we close the current segment. */
1702 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1705 /* configure the segment with the seek variables */
1706 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1707 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1708 cur_type, cur, stop_type, stop, &update)) {
1710 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1712 /* now do the seek */
1713 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1716 /* now do the seek */
1717 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1720 /* prepare for streaming again */
1722 flush_event = gst_event_new_flush_stop (TRUE);
1723 if (seqnum != GST_SEQNUM_INVALID)
1724 gst_event_set_seqnum (flush_event, seqnum);
1726 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1727 gst_qtdemux_push_event (qtdemux, flush_event);
1730 /* commit the new segment */
1731 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1733 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1734 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1735 qtdemux->segment.format, qtdemux->segment.position);
1736 if (seqnum != GST_SEQNUM_INVALID)
1737 gst_message_set_seqnum (msg, seqnum);
1738 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1741 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1742 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1743 qtdemux->sinkpad, NULL);
1745 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1752 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1758 qtdemux_ensure_index (GstQTDemux * qtdemux)
1762 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1764 /* Build complete index */
1765 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1766 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1768 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1769 GST_LOG_OBJECT (qtdemux,
1770 "Building complete index of track-id %u for seeking failed!",
1780 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1783 gboolean res = TRUE;
1784 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1786 switch (GST_EVENT_TYPE (event)) {
1787 case GST_EVENT_SEEK:
1789 #ifndef GST_DISABLE_GST_DEBUG
1790 GstClockTime ts = gst_util_get_timestamp ();
1792 guint32 seqnum = gst_event_get_seqnum (event);
1794 if (seqnum == qtdemux->segment_seqnum) {
1795 GST_LOG_OBJECT (pad,
1796 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1797 gst_event_unref (event);
1801 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1802 /* seek should be handled by upstream, we might need to re-download fragments */
1803 GST_DEBUG_OBJECT (qtdemux,
1804 "let upstream handle seek for fragmented playback");
1808 /* Build complete index for seeking;
1809 * if not a fragmented file at least */
1810 if (!qtdemux->fragmented)
1811 if (!qtdemux_ensure_index (qtdemux))
1813 #ifndef GST_DISABLE_GST_DEBUG
1814 ts = gst_util_get_timestamp () - ts;
1815 GST_INFO_OBJECT (qtdemux,
1816 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1819 if (qtdemux->pullbased) {
1820 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1821 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1822 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1824 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1825 && !qtdemux->fragmented) {
1826 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1828 GST_DEBUG_OBJECT (qtdemux,
1829 "ignoring seek in push mode in current state");
1832 gst_event_unref (event);
1836 res = gst_pad_event_default (pad, parent, event);
1846 GST_ERROR_OBJECT (qtdemux, "Index failed");
1847 gst_event_unref (event);
1853 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1855 * If @fw is false, the coding order is explored backwards.
1857 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1858 * sample is found for that track.
1860 * The stream and sample index of the sample with the minimum offset in the direction explored
1861 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1863 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1864 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1865 * @_stream and @_index. */
1867 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1868 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1871 gint64 time, min_time;
1872 QtDemuxStream *stream;
1879 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1882 gboolean set_sample;
1884 str = QTDEMUX_STREAM (iter->data);
1891 i = str->n_samples - 1;
1895 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1896 if (str->samples[i].size == 0)
1899 if (fw && (str->samples[i].offset < byte_pos))
1902 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1905 /* move stream to first available sample */
1907 gst_qtdemux_move_stream (qtdemux, str, i);
1911 /* avoid index from sparse streams since they might be far away */
1912 if (!CUR_STREAM (str)->sparse) {
1913 /* determine min/max time */
1914 time = QTSAMPLE_PTS (str, &str->samples[i]);
1915 if (min_time == -1 || (!fw && time > min_time) ||
1916 (fw && time < min_time)) {
1920 /* determine stream with leading sample, to get its position */
1922 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1923 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1931 /* no sample for this stream, mark eos */
1933 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1944 /* Copied from mpegtsbase code */
1945 /* FIXME: replace this function when we add new util function for stream-id creation */
1947 _get_upstream_id (GstQTDemux * demux)
1949 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1952 /* Try to create one from the upstream URI, else use a randome number */
1956 /* Try to generate one from the URI query and
1957 * if it fails take a random number instead */
1958 query = gst_query_new_uri ();
1959 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1960 gst_query_parse_uri (query, &uri);
1966 /* And then generate an SHA256 sum of the URI */
1967 cs = g_checksum_new (G_CHECKSUM_SHA256);
1968 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1970 upstream_id = g_strdup (g_checksum_get_string (cs));
1971 g_checksum_free (cs);
1973 /* Just get some random number if the URI query fails */
1974 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1975 "implementing a deterministic way of creating a stream-id");
1977 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1978 g_random_int (), g_random_int ());
1981 gst_query_unref (query);
1986 static QtDemuxStream *
1987 _create_stream (GstQTDemux * demux, guint32 track_id)
1989 QtDemuxStream *stream;
1992 stream = g_new0 (QtDemuxStream, 1);
1993 stream->demux = demux;
1994 stream->track_id = track_id;
1995 upstream_id = _get_upstream_id (demux);
1996 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1997 g_free (upstream_id);
1998 /* new streams always need a discont */
1999 stream->discont = TRUE;
2000 /* we enable clipping for raw audio/video streams */
2001 stream->need_clip = FALSE;
2002 stream->need_process = FALSE;
2003 stream->segment_index = -1;
2004 stream->time_position = 0;
2005 stream->sample_index = -1;
2006 stream->offset_in_sample = 0;
2007 stream->new_stream = TRUE;
2008 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2009 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2010 stream->protected = FALSE;
2011 stream->protection_scheme_type = 0;
2012 stream->protection_scheme_version = 0;
2013 stream->protection_scheme_info = NULL;
2014 stream->n_samples_moof = 0;
2015 stream->duration_moof = 0;
2016 stream->duration_last_moof = 0;
2017 stream->alignment = 1;
2018 stream->stream_tags = gst_tag_list_new_empty ();
2019 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2020 g_queue_init (&stream->protection_scheme_event_queue);
2025 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2027 GstStructure *structure;
2028 const gchar *variant;
2029 const GstCaps *mediacaps = NULL;
2031 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2033 structure = gst_caps_get_structure (caps, 0);
2034 variant = gst_structure_get_string (structure, "variant");
2036 if (variant && strcmp (variant, "mss-fragmented") == 0) {
2037 QtDemuxStream *stream;
2038 const GValue *value;
2040 demux->fragmented = TRUE;
2041 demux->mss_mode = TRUE;
2043 if (demux->n_streams > 1) {
2044 /* can't do this, we can only renegotiate for another mss format */
2048 value = gst_structure_get_value (structure, "media-caps");
2051 const GValue *timescale_v;
2053 /* TODO update when stream changes during playback */
2055 if (demux->n_streams == 0) {
2056 stream = _create_stream (demux, 1);
2057 demux->active_streams = g_list_append (demux->active_streams, stream);
2058 demux->n_streams = 1;
2059 /* mss has no stsd/stsd entry, use id 0 as default */
2060 stream->stsd_entries_length = 1;
2061 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2062 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2064 stream = QTDEMUX_FIRST_STREAM (demux);
2067 timescale_v = gst_structure_get_value (structure, "timescale");
2069 stream->timescale = g_value_get_uint64 (timescale_v);
2071 /* default mss timescale */
2072 stream->timescale = 10000000;
2074 demux->timescale = stream->timescale;
2076 mediacaps = gst_value_get_caps (value);
2077 if (!CUR_STREAM (stream)->caps
2078 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2079 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2081 stream->new_caps = TRUE;
2083 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2084 structure = gst_caps_get_structure (mediacaps, 0);
2085 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2086 stream->subtype = FOURCC_vide;
2088 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2089 gst_structure_get_int (structure, "height",
2090 &CUR_STREAM (stream)->height);
2091 gst_structure_get_fraction (structure, "framerate",
2092 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2093 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2095 stream->subtype = FOURCC_soun;
2096 gst_structure_get_int (structure, "channels",
2097 &CUR_STREAM (stream)->n_channels);
2098 gst_structure_get_int (structure, "rate", &rate);
2099 CUR_STREAM (stream)->rate = rate;
2102 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2104 demux->mss_mode = FALSE;
2111 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2115 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2116 gst_pad_stop_task (qtdemux->sinkpad);
2118 if (hard || qtdemux->upstream_format_is_time) {
2119 qtdemux->state = QTDEMUX_STATE_INITIAL;
2120 qtdemux->neededbytes = 16;
2121 qtdemux->todrop = 0;
2122 qtdemux->pullbased = FALSE;
2123 qtdemux->posted_redirect = FALSE;
2124 qtdemux->first_mdat = -1;
2125 qtdemux->header_size = 0;
2126 qtdemux->mdatoffset = -1;
2127 qtdemux->restoredata_offset = -1;
2128 if (qtdemux->mdatbuffer)
2129 gst_buffer_unref (qtdemux->mdatbuffer);
2130 if (qtdemux->restoredata_buffer)
2131 gst_buffer_unref (qtdemux->restoredata_buffer);
2132 qtdemux->mdatbuffer = NULL;
2133 qtdemux->restoredata_buffer = NULL;
2134 qtdemux->mdatleft = 0;
2135 qtdemux->mdatsize = 0;
2136 if (qtdemux->comp_brands)
2137 gst_buffer_unref (qtdemux->comp_brands);
2138 qtdemux->comp_brands = NULL;
2139 qtdemux->last_moov_offset = -1;
2140 if (qtdemux->moov_node_compressed) {
2141 g_node_destroy (qtdemux->moov_node_compressed);
2142 if (qtdemux->moov_node)
2143 g_free (qtdemux->moov_node->data);
2145 qtdemux->moov_node_compressed = NULL;
2146 if (qtdemux->moov_node)
2147 g_node_destroy (qtdemux->moov_node);
2148 qtdemux->moov_node = NULL;
2149 if (qtdemux->tag_list)
2150 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2151 qtdemux->tag_list = gst_tag_list_new_empty ();
2152 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2154 if (qtdemux->element_index)
2155 gst_object_unref (qtdemux->element_index);
2156 qtdemux->element_index = NULL;
2158 qtdemux->major_brand = 0;
2159 qtdemux->upstream_format_is_time = FALSE;
2160 qtdemux->upstream_seekable = FALSE;
2161 qtdemux->upstream_size = 0;
2163 qtdemux->fragment_start = -1;
2164 qtdemux->fragment_start_offset = -1;
2165 qtdemux->duration = 0;
2166 qtdemux->moof_offset = 0;
2167 qtdemux->chapters_track_id = 0;
2168 qtdemux->have_group_id = FALSE;
2169 qtdemux->group_id = G_MAXUINT;
2171 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2173 g_queue_clear (&qtdemux->protection_event_queue);
2175 qtdemux->offset = 0;
2176 gst_adapter_clear (qtdemux->adapter);
2177 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2178 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2179 qtdemux->need_segment = TRUE;
2182 g_list_free_full (qtdemux->active_streams,
2183 (GDestroyNotify) gst_qtdemux_stream_free);
2184 g_list_free_full (qtdemux->old_streams,
2185 (GDestroyNotify) gst_qtdemux_stream_free);
2186 qtdemux->active_streams = NULL;
2187 qtdemux->old_streams = NULL;
2188 qtdemux->n_streams = 0;
2189 qtdemux->n_video_streams = 0;
2190 qtdemux->n_audio_streams = 0;
2191 qtdemux->n_sub_streams = 0;
2192 qtdemux->exposed = FALSE;
2193 qtdemux->fragmented = FALSE;
2194 qtdemux->mss_mode = FALSE;
2195 gst_caps_replace (&qtdemux->media_caps, NULL);
2196 qtdemux->timescale = 0;
2197 qtdemux->got_moov = FALSE;
2198 qtdemux->cenc_aux_info_offset = 0;
2199 qtdemux->cenc_aux_info_sizes = NULL;
2200 qtdemux->cenc_aux_sample_count = 0;
2201 if (qtdemux->protection_system_ids) {
2202 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2203 qtdemux->protection_system_ids = NULL;
2205 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2206 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2207 GST_BIN_FLAG_STREAMS_AWARE);
2209 if (qtdemux->preferred_protection_system_id) {
2210 g_free (qtdemux->preferred_protection_system_id);
2211 qtdemux->preferred_protection_system_id = NULL;
2213 } else if (qtdemux->mss_mode) {
2214 gst_flow_combiner_reset (qtdemux->flowcombiner);
2215 g_list_foreach (qtdemux->active_streams,
2216 (GFunc) gst_qtdemux_stream_clear, NULL);
2218 gst_flow_combiner_reset (qtdemux->flowcombiner);
2219 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2220 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2221 stream->sent_eos = FALSE;
2222 stream->time_position = 0;
2223 stream->accumulated_base = 0;
2229 /* Maps the @segment to the qt edts internal segments and pushes
2230 * the correspnding segment event.
2232 * If it ends up being at a empty segment, a gap will be pushed and the next
2233 * edts segment will be activated in sequence.
2235 * To be used in push-mode only */
2237 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2242 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2243 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2245 stream->time_position = segment->start;
2247 /* in push mode we should be guaranteed that we will have empty segments
2248 * at the beginning and then one segment after, other scenarios are not
2249 * supported and are discarded when parsing the edts */
2250 for (i = 0; i < stream->n_segments; i++) {
2251 if (stream->segments[i].stop_time > segment->start) {
2252 /* push the empty segment and move to the next one */
2253 gst_qtdemux_activate_segment (qtdemux, stream, i,
2254 stream->time_position);
2255 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2256 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2257 stream->time_position);
2259 /* accumulate previous segments */
2260 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2261 stream->accumulated_base +=
2262 (stream->segment.stop -
2263 stream->segment.start) / ABS (stream->segment.rate);
2267 g_assert (i == stream->n_segments - 1);
2274 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2277 GstQTDemux *demux = GST_QTDEMUX (parent);
2278 gboolean res = TRUE;
2280 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2282 switch (GST_EVENT_TYPE (event)) {
2283 case GST_EVENT_SEGMENT:
2286 QtDemuxStream *stream;
2290 /* some debug output */
2291 gst_event_copy_segment (event, &segment);
2292 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2295 if (segment.format == GST_FORMAT_TIME) {
2296 demux->upstream_format_is_time = TRUE;
2298 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2299 "not in time format");
2301 /* chain will send initial newsegment after pads have been added */
2302 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2303 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2308 /* check if this matches a time seek we received previously
2309 * FIXME for backwards compatibility reasons we use the
2310 * seek_offset here to compare. In the future we might want to
2311 * change this to use the seqnum as it uniquely should identify
2312 * the segment that corresponds to the seek. */
2313 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2314 ", received segment offset %" G_GINT64_FORMAT,
2315 demux->seek_offset, segment.start);
2316 if (segment.format == GST_FORMAT_BYTES
2317 && demux->seek_offset == segment.start) {
2318 GST_OBJECT_LOCK (demux);
2319 offset = segment.start;
2321 segment.format = GST_FORMAT_TIME;
2322 segment.start = demux->push_seek_start;
2323 segment.stop = demux->push_seek_stop;
2324 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2325 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2326 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2327 GST_OBJECT_UNLOCK (demux);
2330 /* we only expect a BYTE segment, e.g. following a seek */
2331 if (segment.format == GST_FORMAT_BYTES) {
2332 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2333 offset = segment.start;
2335 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2336 NULL, (gint64 *) & segment.start);
2337 if ((gint64) segment.start < 0)
2340 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2341 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2342 NULL, (gint64 *) & segment.stop);
2343 /* keyframe seeking should already arrange for start >= stop,
2344 * but make sure in other rare cases */
2345 segment.stop = MAX (segment.stop, segment.start);
2347 } else if (segment.format == GST_FORMAT_TIME) {
2348 /* push all data on the adapter before starting this
2350 gst_qtdemux_process_adapter (demux, TRUE);
2352 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2356 /* We shouldn't modify upstream driven TIME FORMAT segment */
2357 if (!demux->upstream_format_is_time) {
2358 /* accept upstream's notion of segment and distribute along */
2359 segment.format = GST_FORMAT_TIME;
2360 segment.position = segment.time = segment.start;
2361 segment.duration = demux->segment.duration;
2362 segment.base = gst_segment_to_running_time (&demux->segment,
2363 GST_FORMAT_TIME, demux->segment.position);
2366 gst_segment_copy_into (&segment, &demux->segment);
2367 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2369 /* map segment to internal qt segments and push on each stream */
2370 if (demux->n_streams) {
2371 if (demux->fragmented) {
2372 GstEvent *segment_event = gst_event_new_segment (&segment);
2374 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2375 gst_qtdemux_push_event (demux, segment_event);
2377 gst_qtdemux_map_and_push_segments (demux, &segment);
2379 /* keep need-segment as is in case this is the segment before
2380 * fragmented data, we might not have pads yet to push it */
2382 demux->need_segment = FALSE;
2385 /* clear leftover in current segment, if any */
2386 gst_adapter_clear (demux->adapter);
2388 /* set up streaming thread */
2389 demux->offset = offset;
2390 if (demux->upstream_format_is_time) {
2391 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2392 "set values to restart reading from a new atom");
2393 demux->neededbytes = 16;
2396 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2399 demux->todrop = stream->samples[idx].offset - offset;
2400 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2402 /* set up for EOS */
2403 demux->neededbytes = -1;
2408 gst_event_unref (event);
2412 case GST_EVENT_FLUSH_START:
2414 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2415 gst_event_unref (event);
2418 QTDEMUX_EXPOSE_LOCK (demux);
2419 res = gst_pad_event_default (demux->sinkpad, parent, event);
2420 QTDEMUX_EXPOSE_UNLOCK (demux);
2423 case GST_EVENT_FLUSH_STOP:
2427 dur = demux->segment.duration;
2428 gst_qtdemux_reset (demux, FALSE);
2429 demux->segment.duration = dur;
2431 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2432 gst_event_unref (event);
2438 /* If we are in push mode, and get an EOS before we've seen any streams,
2439 * then error out - we have nowhere to send the EOS */
2440 if (!demux->pullbased) {
2442 gboolean has_valid_stream = FALSE;
2443 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
2444 if (QTDEMUX_STREAM (iter->data)->pad != NULL) {
2445 has_valid_stream = TRUE;
2449 if (!has_valid_stream)
2450 gst_qtdemux_post_no_playable_stream_error (demux);
2452 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2453 (guint) gst_adapter_available (demux->adapter));
2454 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2460 case GST_EVENT_CAPS:{
2461 GstCaps *caps = NULL;
2463 gst_event_parse_caps (event, &caps);
2464 gst_qtdemux_setcaps (demux, caps);
2466 gst_event_unref (event);
2469 case GST_EVENT_PROTECTION:
2471 const gchar *system_id = NULL;
2473 gst_event_parse_protection (event, &system_id, NULL, NULL);
2474 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2476 gst_qtdemux_append_protection_system_id (demux, system_id);
2477 /* save the event for later, for source pads that have not been created */
2478 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2479 /* send it to all pads that already exist */
2480 gst_qtdemux_push_event (demux, event);
2484 case GST_EVENT_STREAM_START:
2487 gst_event_unref (event);
2489 /* Drain all the buffers */
2490 gst_qtdemux_process_adapter (demux, TRUE);
2491 gst_qtdemux_reset (demux, FALSE);
2492 /* We expect new moov box after new stream-start event */
2493 demux->old_streams =
2494 g_list_concat (demux->old_streams, demux->active_streams);
2495 demux->active_streams = NULL;
2503 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2511 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2513 GstQTDemux *demux = GST_QTDEMUX (element);
2515 GST_OBJECT_LOCK (demux);
2516 if (demux->element_index)
2517 gst_object_unref (demux->element_index);
2519 demux->element_index = gst_object_ref (index);
2521 demux->element_index = NULL;
2523 GST_OBJECT_UNLOCK (demux);
2524 /* object lock might be taken again */
2526 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2527 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2528 demux->element_index, demux->index_id);
2532 gst_qtdemux_get_index (GstElement * element)
2534 GstIndex *result = NULL;
2535 GstQTDemux *demux = GST_QTDEMUX (element);
2537 GST_OBJECT_LOCK (demux);
2538 if (demux->element_index)
2539 result = gst_object_ref (demux->element_index);
2540 GST_OBJECT_UNLOCK (demux);
2542 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2549 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2551 g_free ((gpointer) stream->stco.data);
2552 stream->stco.data = NULL;
2553 g_free ((gpointer) stream->stsz.data);
2554 stream->stsz.data = NULL;
2555 g_free ((gpointer) stream->stsc.data);
2556 stream->stsc.data = NULL;
2557 g_free ((gpointer) stream->stts.data);
2558 stream->stts.data = NULL;
2559 g_free ((gpointer) stream->stss.data);
2560 stream->stss.data = NULL;
2561 g_free ((gpointer) stream->stps.data);
2562 stream->stps.data = NULL;
2563 g_free ((gpointer) stream->ctts.data);
2564 stream->ctts.data = NULL;
2568 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2570 g_free (stream->segments);
2571 stream->segments = NULL;
2572 stream->segment_index = -1;
2573 stream->accumulated_base = 0;
2577 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2579 g_free (stream->samples);
2580 stream->samples = NULL;
2581 gst_qtdemux_stbl_free (stream);
2584 g_free (stream->ra_entries);
2585 stream->ra_entries = NULL;
2586 stream->n_ra_entries = 0;
2588 stream->sample_index = -1;
2589 stream->stbl_index = -1;
2590 stream->n_samples = 0;
2591 stream->time_position = 0;
2593 stream->n_samples_moof = 0;
2594 stream->duration_moof = 0;
2595 stream->duration_last_moof = 0;
2599 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2602 if (stream->allocator)
2603 gst_object_unref (stream->allocator);
2604 while (stream->buffers) {
2605 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2606 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2608 for (i = 0; i < stream->stsd_entries_length; i++) {
2609 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2610 if (entry->rgb8_palette) {
2611 gst_memory_unref (entry->rgb8_palette);
2612 entry->rgb8_palette = NULL;
2614 entry->sparse = FALSE;
2617 if (stream->stream_tags)
2618 gst_tag_list_unref (stream->stream_tags);
2620 stream->stream_tags = gst_tag_list_new_empty ();
2621 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2622 g_free (stream->redirect_uri);
2623 stream->redirect_uri = NULL;
2624 stream->sent_eos = FALSE;
2625 stream->protected = FALSE;
2626 if (stream->protection_scheme_info) {
2627 if (stream->protection_scheme_type == FOURCC_cenc) {
2628 QtDemuxCencSampleSetInfo *info =
2629 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2630 if (info->default_properties)
2631 gst_structure_free (info->default_properties);
2632 if (info->crypto_info)
2633 g_ptr_array_free (info->crypto_info, TRUE);
2635 g_free (stream->protection_scheme_info);
2636 stream->protection_scheme_info = NULL;
2638 stream->protection_scheme_type = 0;
2639 stream->protection_scheme_version = 0;
2640 g_queue_foreach (&stream->protection_scheme_event_queue,
2641 (GFunc) gst_event_unref, NULL);
2642 g_queue_clear (&stream->protection_scheme_event_queue);
2643 gst_qtdemux_stream_flush_segments_data (stream);
2644 gst_qtdemux_stream_flush_samples_data (stream);
2648 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2651 gst_qtdemux_stream_clear (stream);
2652 for (i = 0; i < stream->stsd_entries_length; i++) {
2653 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2655 gst_caps_unref (entry->caps);
2659 g_free (stream->stsd_entries);
2660 stream->stsd_entries = NULL;
2661 stream->stsd_entries_length = 0;
2666 gst_qtdemux_stream_free (QtDemuxStream * stream)
2668 gst_qtdemux_stream_reset (stream);
2669 gst_tag_list_unref (stream->stream_tags);
2671 GstQTDemux *demux = stream->demux;
2672 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2673 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2675 g_free (stream->stream_id);
2680 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
2682 qtdemux->active_streams = g_list_remove (qtdemux->active_streams, stream);
2683 gst_qtdemux_stream_free (stream);
2684 qtdemux->n_streams--;
2687 static GstStateChangeReturn
2688 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2690 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2691 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2693 switch (transition) {
2694 case GST_STATE_CHANGE_READY_TO_PAUSED:
2695 gst_qtdemux_reset (qtdemux, TRUE);
2701 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2703 switch (transition) {
2704 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2705 gst_qtdemux_reset (qtdemux, TRUE);
2716 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2718 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2720 g_return_if_fail (GST_IS_CONTEXT (context));
2722 if (gst_context_has_context_type (context,
2723 "drm-preferred-decryption-system-id")) {
2724 const GstStructure *s;
2726 s = gst_context_get_structure (context);
2727 g_free (qtdemux->preferred_protection_system_id);
2728 qtdemux->preferred_protection_system_id =
2729 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2730 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2731 qtdemux->preferred_protection_system_id);
2734 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2738 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2740 /* counts as header data */
2741 qtdemux->header_size += length;
2743 /* only consider at least a sufficiently complete ftyp atom */
2747 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2748 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2749 GST_FOURCC_ARGS (qtdemux->major_brand));
2750 if (qtdemux->comp_brands)
2751 gst_buffer_unref (qtdemux->comp_brands);
2752 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2753 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2758 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2759 GstTagList * xmptaglist)
2761 /* Strip out bogus fields */
2763 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2764 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2765 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2767 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2770 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2772 /* prioritize native tags using _KEEP mode */
2773 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2774 gst_tag_list_unref (xmptaglist);
2779 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2787 QtDemuxStream *stream;
2788 GstStructure *structure;
2789 QtDemuxCencSampleSetInfo *ss_info = NULL;
2790 const gchar *system_id;
2791 gboolean uses_sub_sample_encryption = FALSE;
2792 guint32 sample_count;
2794 stream = QTDEMUX_FIRST_STREAM (qtdemux);
2798 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2799 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2800 GST_WARNING_OBJECT (qtdemux,
2801 "Attempting PIFF box parsing on an unencrypted stream.");
2805 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2806 G_TYPE_STRING, &system_id, NULL);
2807 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2809 stream->protected = TRUE;
2810 stream->protection_scheme_type = FOURCC_cenc;
2812 if (!stream->protection_scheme_info)
2813 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2815 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2817 if (ss_info->default_properties)
2818 gst_structure_free (ss_info->default_properties);
2820 ss_info->default_properties =
2821 gst_structure_new ("application/x-cenc",
2822 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2824 if (ss_info->crypto_info) {
2825 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2826 g_ptr_array_free (ss_info->crypto_info, TRUE);
2827 ss_info->crypto_info = NULL;
2831 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2833 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2834 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2838 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2839 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2843 if ((flags & 0x000001)) {
2844 guint32 algorithm_id = 0;
2847 gboolean is_encrypted = TRUE;
2849 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2850 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2855 if (algorithm_id == 0) {
2856 is_encrypted = FALSE;
2857 } else if (algorithm_id == 1) {
2858 /* FIXME: maybe store this in properties? */
2859 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2860 } else if (algorithm_id == 2) {
2861 /* FIXME: maybe store this in properties? */
2862 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2865 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2868 if (!gst_byte_reader_get_data (&br, 16, &kid))
2871 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2872 gst_buffer_fill (kid_buf, 0, kid, 16);
2873 if (ss_info->default_properties)
2874 gst_structure_free (ss_info->default_properties);
2875 ss_info->default_properties =
2876 gst_structure_new ("application/x-cenc",
2877 "iv_size", G_TYPE_UINT, iv_size,
2878 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2879 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2880 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2881 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2882 gst_buffer_unref (kid_buf);
2883 } else if ((flags & 0x000002)) {
2884 uses_sub_sample_encryption = TRUE;
2887 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2888 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2892 ss_info->crypto_info =
2893 g_ptr_array_new_full (sample_count,
2894 (GDestroyNotify) qtdemux_gst_structure_free);
2896 for (i = 0; i < sample_count; ++i) {
2897 GstStructure *properties;
2901 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2902 if (properties == NULL) {
2903 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2904 qtdemux->cenc_aux_sample_count = i;
2908 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2909 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2910 gst_structure_free (properties);
2911 qtdemux->cenc_aux_sample_count = i;
2914 buf = gst_buffer_new_wrapped (data, iv_size);
2915 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2916 gst_buffer_unref (buf);
2918 if (uses_sub_sample_encryption) {
2919 guint16 n_subsamples;
2921 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2922 || n_subsamples == 0) {
2923 GST_ERROR_OBJECT (qtdemux,
2924 "failed to get subsample count for sample %u", i);
2925 gst_structure_free (properties);
2926 qtdemux->cenc_aux_sample_count = i;
2929 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2930 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2931 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2933 gst_structure_free (properties);
2934 qtdemux->cenc_aux_sample_count = i;
2937 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2938 gst_structure_set (properties,
2939 "subsample_count", G_TYPE_UINT, n_subsamples,
2940 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2941 gst_buffer_unref (buf);
2943 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2946 g_ptr_array_add (ss_info->crypto_info, properties);
2949 qtdemux->cenc_aux_sample_count = sample_count;
2953 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2955 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2956 0x97, 0xA9, 0x42, 0xE8,
2957 0x9C, 0x71, 0x99, 0x94,
2958 0x91, 0xE3, 0xAF, 0xAC
2960 static const guint8 playready_uuid[] = {
2961 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2962 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2965 static const guint8 piff_sample_encryption_uuid[] = {
2966 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2967 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2972 /* counts as header data */
2973 qtdemux->header_size += length;
2975 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2977 if (length <= offset + 16) {
2978 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2982 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2984 GstTagList *taglist;
2986 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2987 length - offset - 16, NULL);
2988 taglist = gst_tag_list_from_xmp_buffer (buf);
2989 gst_buffer_unref (buf);
2991 /* make sure we have a usable taglist */
2992 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2994 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2996 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2998 const gunichar2 *s_utf16;
3001 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3002 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3003 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3004 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3008 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3009 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3011 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3012 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3014 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3015 GST_READ_UINT32_LE (buffer + offset),
3016 GST_READ_UINT32_LE (buffer + offset + 4),
3017 GST_READ_UINT32_LE (buffer + offset + 8),
3018 GST_READ_UINT32_LE (buffer + offset + 12));
3023 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3025 GstSidxParser sidx_parser;
3026 GstIsoffParserResult res;
3029 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3032 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3034 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3035 if (res == GST_ISOFF_QT_PARSER_DONE) {
3036 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3038 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3041 /* caller verifies at least 8 bytes in buf */
3043 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3044 guint64 * plength, guint32 * pfourcc)
3049 length = QT_UINT32 (data);
3050 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3051 fourcc = QT_FOURCC (data + 4);
3052 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3055 length = G_MAXUINT64;
3056 } else if (length == 1 && size >= 16) {
3057 /* this means we have an extended size, which is the 64 bit value of
3058 * the next 8 bytes */
3059 length = QT_UINT64 (data + 8);
3060 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3070 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3072 guint32 version = 0;
3073 GstClockTime duration = 0;
3075 if (!gst_byte_reader_get_uint32_be (br, &version))
3080 if (!gst_byte_reader_get_uint64_be (br, &duration))
3085 if (!gst_byte_reader_get_uint32_be (br, &dur))
3090 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3091 qtdemux->duration = duration;
3097 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3103 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3104 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3106 if (!stream->parsed_trex && qtdemux->moov_node) {
3108 GstByteReader trex_data;
3110 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3112 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3115 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3117 /* skip version/flags */
3118 if (!gst_byte_reader_skip (&trex_data, 4))
3120 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3122 if (id != stream->track_id)
3124 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3126 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3128 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3130 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3133 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3134 "duration %d, size %d, flags 0x%x", stream->track_id,
3137 stream->parsed_trex = TRUE;
3138 stream->def_sample_description_index = sdi;
3139 stream->def_sample_duration = dur;
3140 stream->def_sample_size = size;
3141 stream->def_sample_flags = flags;
3144 /* iterate all siblings */
3145 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3151 *ds_duration = stream->def_sample_duration;
3152 *ds_size = stream->def_sample_size;
3153 *ds_flags = stream->def_sample_flags;
3155 /* even then, above values are better than random ... */
3156 if (G_UNLIKELY (!stream->parsed_trex)) {
3157 GST_WARNING_OBJECT (qtdemux,
3158 "failed to find fragment defaults for stream %d", stream->track_id);
3165 /* This method should be called whenever a more accurate duration might
3166 * have been found. It will update all relevant variables if/where needed
3169 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3173 GstClockTime prevdur;
3176 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3178 if (movdur > qtdemux->duration) {
3179 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3180 GST_DEBUG_OBJECT (qtdemux,
3181 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3182 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3183 qtdemux->duration = movdur;
3184 GST_DEBUG_OBJECT (qtdemux,
3185 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3186 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3187 GST_TIME_ARGS (qtdemux->segment.stop));
3188 if (qtdemux->segment.duration == prevdur) {
3189 /* If the current segment has duration/stop identical to previous duration
3190 * update them also (because they were set at that point in time with
3191 * the wrong duration */
3192 /* We convert the value *from* the timescale version to avoid rounding errors */
3193 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3194 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3195 qtdemux->segment.duration = fixeddur;
3196 qtdemux->segment.stop = fixeddur;
3199 for (iter = qtdemux->active_streams, i = 0; iter;
3200 iter = g_list_next (iter), i++) {
3201 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3203 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3204 if (movdur > stream->duration) {
3205 GST_DEBUG_OBJECT (qtdemux,
3206 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3207 GST_TIME_ARGS (duration));
3208 stream->duration = movdur;
3209 /* internal duration tracking state has been updated above, so */
3210 /* preserve an open-ended dummy segment rather than repeatedly updating
3211 * it and spamming downstream accordingly with segment events */
3212 if (stream->dummy_segment &&
3213 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3214 /* Update all dummy values to new duration */
3215 stream->segments[0].stop_time = duration;
3216 stream->segments[0].duration = duration;
3217 stream->segments[0].media_stop = duration;
3219 /* let downstream know we possibly have a new stop time */
3220 if (stream->segment_index != -1) {
3223 if (qtdemux->segment.rate >= 0) {
3224 pos = stream->segment.start;
3226 pos = stream->segment.stop;
3229 gst_qtdemux_stream_update_segment (qtdemux, stream,
3230 stream->segment_index, pos, NULL, NULL);
3238 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3239 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3240 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3241 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3244 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3246 gint32 data_offset = 0;
3247 guint32 flags = 0, first_flags = 0, samples_count = 0;
3250 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3251 QtDemuxSample *sample;
3252 gboolean ismv = FALSE;
3253 gint64 initial_offset;
3255 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3256 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3257 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3258 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3260 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3261 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3265 /* presence of stss or not can't really tell us much,
3266 * and flags and so on tend to be marginally reliable in these files */
3267 if (stream->subtype == FOURCC_soun) {
3268 GST_DEBUG_OBJECT (qtdemux,
3269 "sound track in fragmented file; marking all keyframes");
3270 stream->all_keyframe = TRUE;
3273 if (!gst_byte_reader_skip (trun, 1) ||
3274 !gst_byte_reader_get_uint24_be (trun, &flags))
3277 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3280 if (flags & TR_DATA_OFFSET) {
3281 /* note this is really signed */
3282 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3284 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3285 /* default base offset = first byte of moof */
3286 if (*base_offset == -1) {
3287 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3288 *base_offset = moof_offset;
3290 *running_offset = *base_offset + data_offset;
3292 /* if no offset at all, that would mean data starts at moof start,
3293 * which is a bit wrong and is ismv crappy way, so compensate
3294 * assuming data is in mdat following moof */
3295 if (*base_offset == -1) {
3296 *base_offset = moof_offset + moof_length + 8;
3297 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3300 if (*running_offset == -1)
3301 *running_offset = *base_offset;
3304 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3306 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3307 data_offset, flags, samples_count);
3309 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3310 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3311 GST_DEBUG_OBJECT (qtdemux,
3312 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3313 flags ^= TR_FIRST_SAMPLE_FLAGS;
3315 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3317 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3321 /* FIXME ? spec says other bits should also be checked to determine
3322 * entry size (and prefix size for that matter) */
3324 dur_offset = size_offset = 0;
3325 if (flags & TR_SAMPLE_DURATION) {
3326 GST_LOG_OBJECT (qtdemux, "entry duration present");
3327 dur_offset = entry_size;
3330 if (flags & TR_SAMPLE_SIZE) {
3331 GST_LOG_OBJECT (qtdemux, "entry size present");
3332 size_offset = entry_size;
3335 if (flags & TR_SAMPLE_FLAGS) {
3336 GST_LOG_OBJECT (qtdemux, "entry flags present");
3337 flags_offset = entry_size;
3340 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3341 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3342 ct_offset = entry_size;
3346 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3348 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3350 if (stream->n_samples + samples_count >=
3351 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3354 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3355 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3356 (stream->n_samples + samples_count) *
3357 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3359 /* create a new array of samples if it's the first sample parsed */
3360 if (stream->n_samples == 0) {
3361 g_assert (stream->samples == NULL);
3362 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3363 /* or try to reallocate it with space enough to insert the new samples */
3365 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3366 stream->n_samples + samples_count);
3367 if (stream->samples == NULL)
3370 if (qtdemux->fragment_start != -1) {
3371 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3372 qtdemux->fragment_start = -1;
3374 if (stream->n_samples == 0) {
3375 if (decode_ts > 0) {
3376 timestamp = decode_ts;
3377 } else if (stream->pending_seek != NULL) {
3378 /* if we don't have a timestamp from a tfdt box, we'll use the one
3379 * from the mfra seek table */
3380 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3381 GST_TIME_ARGS (stream->pending_seek->ts));
3383 /* FIXME: this is not fully correct, the timestamp refers to the random
3384 * access sample refered to in the tfra entry, which may not necessarily
3385 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3386 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3391 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3392 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3393 GST_TIME_ARGS (gst_ts));
3395 /* subsequent fragments extend stream */
3397 stream->samples[stream->n_samples - 1].timestamp +
3398 stream->samples[stream->n_samples - 1].duration;
3400 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3401 * difference (1 sec.) between decode_ts and timestamp, prefer the
3403 if (has_tfdt && !qtdemux->upstream_format_is_time
3404 && ABSDIFF (decode_ts, timestamp) >
3405 MAX (stream->duration_last_moof / 2,
3406 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3407 GST_INFO_OBJECT (qtdemux,
3408 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3409 ") are significantly different (more than %" GST_TIME_FORMAT
3410 "), using decode_ts",
3411 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3412 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3413 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3414 MAX (stream->duration_last_moof / 2,
3415 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3416 timestamp = decode_ts;
3419 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3420 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3421 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3425 initial_offset = *running_offset;
3427 sample = stream->samples + stream->n_samples;
3428 for (i = 0; i < samples_count; i++) {
3429 guint32 dur, size, sflags, ct;
3431 /* first read sample data */
3432 if (flags & TR_SAMPLE_DURATION) {
3433 dur = QT_UINT32 (data + dur_offset);
3435 dur = d_sample_duration;
3437 if (flags & TR_SAMPLE_SIZE) {
3438 size = QT_UINT32 (data + size_offset);
3440 size = d_sample_size;
3442 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3444 sflags = first_flags;
3446 sflags = d_sample_flags;
3448 } else if (flags & TR_SAMPLE_FLAGS) {
3449 sflags = QT_UINT32 (data + flags_offset);
3451 sflags = d_sample_flags;
3453 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3454 ct = QT_UINT32 (data + ct_offset);
3460 /* fill the sample information */
3461 sample->offset = *running_offset;
3462 sample->pts_offset = ct;
3463 sample->size = size;
3464 sample->timestamp = timestamp;
3465 sample->duration = dur;
3466 /* sample-is-difference-sample */
3467 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3468 * now idea how it relates to bitfield other than massive LE/BE confusion */
3469 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3470 *running_offset += size;
3472 stream->duration_moof += dur;
3476 /* Update total duration if needed */
3477 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3479 /* Pre-emptively figure out size of mdat based on trun information.
3480 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3481 * size, else we will still be able to use this when dealing with gap'ed
3483 qtdemux->mdatleft = *running_offset - initial_offset;
3484 qtdemux->mdatoffset = initial_offset;
3485 qtdemux->mdatsize = qtdemux->mdatleft;
3487 stream->n_samples += samples_count;
3488 stream->n_samples_moof += samples_count;
3490 if (stream->pending_seek != NULL)
3491 stream->pending_seek = NULL;
3497 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3502 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3508 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3509 "be larger than %uMB (broken file?)", stream->n_samples,
3510 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3515 /* find stream with @id */
3516 static inline QtDemuxStream *
3517 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3519 QtDemuxStream *stream;
3523 if (G_UNLIKELY (!id)) {
3524 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3528 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3529 stream = QTDEMUX_STREAM (iter->data);
3530 if (stream->track_id == id)
3533 if (qtdemux->mss_mode) {
3534 /* mss should have only 1 stream anyway */
3535 return QTDEMUX_FIRST_STREAM (qtdemux);
3542 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3543 guint32 * fragment_number)
3545 if (!gst_byte_reader_skip (mfhd, 4))
3547 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3552 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3558 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3559 QtDemuxStream ** stream, guint32 * default_sample_duration,
3560 guint32 * default_sample_size, guint32 * default_sample_flags,
3561 gint64 * base_offset)
3564 guint32 track_id = 0;
3566 if (!gst_byte_reader_skip (tfhd, 1) ||
3567 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3570 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3573 *stream = qtdemux_find_stream (qtdemux, track_id);
3574 if (G_UNLIKELY (!*stream))
3575 goto unknown_stream;
3577 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3578 *base_offset = qtdemux->moof_offset;
3580 if (flags & TF_BASE_DATA_OFFSET)
3581 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3584 /* obtain stream defaults */
3585 qtdemux_parse_trex (qtdemux, *stream,
3586 default_sample_duration, default_sample_size, default_sample_flags);
3588 (*stream)->stsd_sample_description_id =
3589 (*stream)->def_sample_description_index - 1;
3591 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3592 guint32 sample_description_index;
3593 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3595 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3598 if (qtdemux->mss_mode) {
3599 /* mss has no stsd entry */
3600 (*stream)->stsd_sample_description_id = 0;
3603 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3604 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3607 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3608 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3611 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3612 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3619 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3624 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3630 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3631 guint64 * decode_time)
3633 guint32 version = 0;
3635 if (!gst_byte_reader_get_uint32_be (br, &version))
3640 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3643 guint32 dec_time = 0;
3644 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3646 *decode_time = dec_time;
3649 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3656 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3661 /* Returns a pointer to a GstStructure containing the properties of
3662 * the stream sample identified by @sample_index. The caller must unref
3663 * the returned object after use. Returns NULL if unsuccessful. */
3664 static GstStructure *
3665 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3666 QtDemuxStream * stream, guint sample_index)
3668 QtDemuxCencSampleSetInfo *info = NULL;
3670 g_return_val_if_fail (stream != NULL, NULL);
3671 g_return_val_if_fail (stream->protected, NULL);
3672 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3674 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3676 /* Currently, cenc properties for groups of samples are not supported, so
3677 * simply return a copy of the default sample properties */
3678 return gst_structure_copy (info->default_properties);
3681 /* Parses the sizes of sample auxiliary information contained within a stream,
3682 * as given in a saiz box. Returns array of sample_count guint8 size values,
3683 * or NULL on failure */
3685 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3686 GstByteReader * br, guint32 * sample_count)
3690 guint8 default_info_size;
3692 g_return_val_if_fail (qtdemux != NULL, NULL);
3693 g_return_val_if_fail (stream != NULL, NULL);
3694 g_return_val_if_fail (br != NULL, NULL);
3695 g_return_val_if_fail (sample_count != NULL, NULL);
3697 if (!gst_byte_reader_get_uint32_be (br, &flags))
3701 /* aux_info_type and aux_info_type_parameter are ignored */
3702 if (!gst_byte_reader_skip (br, 8))
3706 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3708 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3710 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3712 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3715 if (default_info_size == 0) {
3716 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3720 info_sizes = g_new (guint8, *sample_count);
3721 memset (info_sizes, default_info_size, *sample_count);
3727 /* Parses the offset of sample auxiliary information contained within a stream,
3728 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3730 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3731 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3736 guint32 aux_info_type = 0;
3737 guint32 aux_info_type_parameter = 0;
3738 guint32 entry_count;
3741 const guint8 *aux_info_type_data = NULL;
3743 g_return_val_if_fail (qtdemux != NULL, FALSE);
3744 g_return_val_if_fail (stream != NULL, FALSE);
3745 g_return_val_if_fail (br != NULL, FALSE);
3746 g_return_val_if_fail (offset != NULL, FALSE);
3748 if (!gst_byte_reader_get_uint8 (br, &version))
3751 if (!gst_byte_reader_get_uint24_be (br, &flags))
3756 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3758 aux_info_type = QT_FOURCC (aux_info_type_data);
3760 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3762 } else if (stream->protected) {
3763 aux_info_type = stream->protection_scheme_type;
3765 aux_info_type = CUR_STREAM (stream)->fourcc;
3769 *info_type = aux_info_type;
3770 if (info_type_parameter)
3771 *info_type_parameter = aux_info_type_parameter;
3773 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3774 "aux_info_type_parameter: %#06x",
3775 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3777 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3780 if (entry_count != 1) {
3781 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3786 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3788 *offset = (guint64) off_32;
3790 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3795 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3800 qtdemux_gst_structure_free (GstStructure * gststructure)
3803 gst_structure_free (gststructure);
3807 /* Parses auxiliary information relating to samples protected using Common
3808 * Encryption (cenc); the format of this information is defined in
3809 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3811 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3812 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3814 QtDemuxCencSampleSetInfo *ss_info = NULL;
3817 GPtrArray *old_crypto_info = NULL;
3818 guint old_entries = 0;
3820 g_return_val_if_fail (qtdemux != NULL, FALSE);
3821 g_return_val_if_fail (stream != NULL, FALSE);
3822 g_return_val_if_fail (br != NULL, FALSE);
3823 g_return_val_if_fail (stream->protected, FALSE);
3824 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3826 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3828 if (ss_info->crypto_info) {
3829 old_crypto_info = ss_info->crypto_info;
3830 /* Count number of non-null entries remaining at the tail end */
3831 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3832 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3838 ss_info->crypto_info =
3839 g_ptr_array_new_full (sample_count + old_entries,
3840 (GDestroyNotify) qtdemux_gst_structure_free);
3842 /* We preserve old entries because we parse the next moof in advance
3843 * of consuming all samples from the previous moof, and otherwise
3844 * we'd discard the corresponding crypto info for the samples
3845 * from the previous fragment. */
3847 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3849 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3850 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3852 g_ptr_array_index (old_crypto_info, i) = NULL;
3856 if (old_crypto_info) {
3857 /* Everything now belongs to the new array */
3858 g_ptr_array_free (old_crypto_info, TRUE);
3861 for (i = 0; i < sample_count; ++i) {
3862 GstStructure *properties;
3863 guint16 n_subsamples = 0;
3868 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3869 if (properties == NULL) {
3870 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3873 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3874 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3875 gst_structure_free (properties);
3878 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3879 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3880 gst_structure_free (properties);
3883 buf = gst_buffer_new_wrapped (data, iv_size);
3884 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3885 gst_buffer_unref (buf);
3886 size = info_sizes[i];
3887 if (size > iv_size) {
3888 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3889 || !(n_subsamples > 0)) {
3890 gst_structure_free (properties);
3891 GST_ERROR_OBJECT (qtdemux,
3892 "failed to get subsample count for sample %u", i);
3895 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3896 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3897 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3899 gst_structure_free (properties);
3902 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3904 gst_structure_free (properties);
3907 gst_structure_set (properties,
3908 "subsample_count", G_TYPE_UINT, n_subsamples,
3909 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3910 gst_buffer_unref (buf);
3912 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3914 g_ptr_array_add (ss_info->crypto_info, properties);
3919 /* Converts a UUID in raw byte form to a string representation, as defined in
3920 * RFC 4122. The caller takes ownership of the returned string and is
3921 * responsible for freeing it after use. */
3923 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3925 const guint8 *uuid = (const guint8 *) uuid_bytes;
3927 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3928 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3929 uuid[0], uuid[1], uuid[2], uuid[3],
3930 uuid[4], uuid[5], uuid[6], uuid[7],
3931 uuid[8], uuid[9], uuid[10], uuid[11],
3932 uuid[12], uuid[13], uuid[14], uuid[15]);
3935 /* Parses a Protection System Specific Header box (pssh), as defined in the
3936 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3937 * information needed by a specific content protection system in order to
3938 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3941 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3943 gchar *sysid_string;
3944 guint32 pssh_size = QT_UINT32 (node->data);
3945 GstBuffer *pssh = NULL;
3946 GstEvent *event = NULL;
3947 guint32 parent_box_type;
3950 if (G_UNLIKELY (pssh_size < 32U)) {
3951 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3956 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3958 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3960 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3961 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3962 gst_buffer_get_size (pssh));
3964 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3966 /* Push an event containing the pssh box onto the queues of all streams. */
3967 event = gst_event_new_protection (sysid_string, pssh,
3968 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3969 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3970 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3971 GST_TRACE_OBJECT (qtdemux,
3972 "adding protection event for stream %s and system %s",
3973 stream->stream_id, sysid_string);
3974 g_queue_push_tail (&stream->protection_scheme_event_queue,
3975 gst_event_ref (event));
3977 g_free (sysid_string);
3978 gst_event_unref (event);
3979 gst_buffer_unref (pssh);
3984 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3985 guint64 moof_offset, QtDemuxStream * stream)
3987 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3989 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3990 GNode *saiz_node, *saio_node, *pssh_node;
3991 GstByteReader saiz_data, saio_data;
3992 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3993 gint64 base_offset, running_offset;
3996 /* NOTE @stream ignored */
3998 moof_node = g_node_new ((guint8 *) buffer);
3999 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4000 qtdemux_node_dump (qtdemux, moof_node);
4002 /* Get fragment number from mfhd and check it's valid */
4004 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4005 if (mfhd_node == NULL)
4007 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4009 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4011 /* unknown base_offset to start with */
4012 base_offset = running_offset = -1;
4013 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4015 guint64 decode_time = 0;
4017 /* Fragment Header node */
4019 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4023 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4024 &ds_size, &ds_flags, &base_offset))
4027 /* The following code assumes at most a single set of sample auxiliary
4028 * data in the fragment (consisting of a saiz box and a corresponding saio
4029 * box); in theory, however, there could be multiple sets of sample
4030 * auxiliary data in a fragment. */
4032 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4035 guint32 info_type = 0;
4037 guint32 info_type_parameter = 0;
4039 g_free (qtdemux->cenc_aux_info_sizes);
4041 qtdemux->cenc_aux_info_sizes =
4042 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4043 &qtdemux->cenc_aux_sample_count);
4044 if (qtdemux->cenc_aux_info_sizes == NULL) {
4045 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4049 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4052 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4053 g_free (qtdemux->cenc_aux_info_sizes);
4054 qtdemux->cenc_aux_info_sizes = NULL;
4058 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4059 &info_type, &info_type_parameter, &offset))) {
4060 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4061 g_free (qtdemux->cenc_aux_info_sizes);
4062 qtdemux->cenc_aux_info_sizes = NULL;
4065 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4066 offset += (guint64) (base_offset - qtdemux->moof_offset);
4067 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4069 if (offset > length) {
4070 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4071 qtdemux->cenc_aux_info_offset = offset;
4073 gst_byte_reader_init (&br, buffer + offset, length - offset);
4074 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4075 qtdemux->cenc_aux_info_sizes,
4076 qtdemux->cenc_aux_sample_count)) {
4077 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4078 g_free (qtdemux->cenc_aux_info_sizes);
4079 qtdemux->cenc_aux_info_sizes = NULL;
4087 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4090 /* We'll use decode_time to interpolate timestamps
4091 * in case the input timestamps are missing */
4092 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4094 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4095 " (%" GST_TIME_FORMAT ")", decode_time,
4096 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4097 decode_time) : GST_CLOCK_TIME_NONE));
4099 /* Discard the fragment buffer timestamp info to avoid using it.
4100 * Rely on tfdt instead as it is more accurate than the timestamp
4101 * that is fetched from a manifest/playlist and is usually
4103 qtdemux->fragment_start = -1;
4106 if (G_UNLIKELY (!stream)) {
4107 /* we lost track of offset, we'll need to regain it,
4108 * but can delay complaining until later or avoid doing so altogether */
4112 if (G_UNLIKELY (base_offset < -1))
4115 if (qtdemux->upstream_format_is_time)
4116 gst_qtdemux_stream_flush_samples_data (stream);
4118 /* initialise moof sample data */
4119 stream->n_samples_moof = 0;
4120 stream->duration_last_moof = stream->duration_moof;
4121 stream->duration_moof = 0;
4123 /* Track Run node */
4125 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4128 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4129 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4130 &running_offset, decode_time, (tfdt_node != NULL));
4131 /* iterate all siblings */
4132 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4136 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4138 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4139 guint32 box_length = QT_UINT32 (uuid_buffer);
4141 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4144 /* if no new base_offset provided for next traf,
4145 * base is end of current traf */
4146 base_offset = running_offset;
4147 running_offset = -1;
4149 if (stream->n_samples_moof && stream->duration_moof)
4150 stream->new_caps = TRUE;
4153 /* iterate all siblings */
4154 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4157 /* parse any protection system info */
4158 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4160 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4161 qtdemux_parse_pssh (qtdemux, pssh_node);
4162 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4165 g_node_destroy (moof_node);
4170 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4175 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4180 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4185 g_node_destroy (moof_node);
4186 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4187 (_("This file is corrupt and cannot be played.")), (NULL));
4193 /* might be used if some day we actually use mfra & co
4194 * for random access to fragments,
4195 * but that will require quite some modifications and much less relying
4196 * on a sample array */
4200 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4202 QtDemuxStream *stream;
4203 guint32 ver_flags, track_id, len, num_entries, i;
4204 guint value_size, traf_size, trun_size, sample_size;
4205 guint64 time = 0, moof_offset = 0;
4207 GstBuffer *buf = NULL;
4212 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4214 if (!gst_byte_reader_skip (&tfra, 8))
4217 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4220 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4221 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4222 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4225 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4227 stream = qtdemux_find_stream (qtdemux, track_id);
4229 goto unknown_trackid;
4231 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4232 sample_size = (len & 3) + 1;
4233 trun_size = ((len & 12) >> 2) + 1;
4234 traf_size = ((len & 48) >> 4) + 1;
4236 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4237 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4239 if (num_entries == 0)
4242 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4243 value_size + value_size + traf_size + trun_size + sample_size))
4246 g_free (stream->ra_entries);
4247 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4248 stream->n_ra_entries = num_entries;
4250 for (i = 0; i < num_entries; i++) {
4251 qt_atom_parser_get_offset (&tfra, value_size, &time);
4252 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4253 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4254 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4255 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4257 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4259 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4260 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4262 stream->ra_entries[i].ts = time;
4263 stream->ra_entries[i].moof_offset = moof_offset;
4265 /* don't want to go through the entire file and read all moofs at startup */
4267 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4268 if (ret != GST_FLOW_OK)
4270 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4271 moof_offset, stream);
4272 gst_buffer_unref (buf);
4276 check_update_duration (qtdemux, time);
4283 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4288 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4293 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4299 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4301 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4302 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4303 GstBuffer *mfro = NULL, *mfra = NULL;
4305 gboolean ret = FALSE;
4306 GNode *mfra_node, *tfra_node;
4307 guint64 mfra_offset = 0;
4308 guint32 fourcc, mfra_size;
4311 /* query upstream size in bytes */
4312 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4313 goto size_query_failed;
4315 /* mfro box should be at the very end of the file */
4316 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4317 if (flow != GST_FLOW_OK)
4320 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4322 fourcc = QT_FOURCC (mfro_map.data + 4);
4323 if (fourcc != FOURCC_mfro)
4326 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4327 if (mfro_map.size < 16)
4328 goto invalid_mfro_size;
4330 mfra_size = QT_UINT32 (mfro_map.data + 12);
4331 if (mfra_size >= len)
4332 goto invalid_mfra_size;
4334 mfra_offset = len - mfra_size;
4336 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4337 mfra_offset, mfra_size);
4339 /* now get and parse mfra box */
4340 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4341 if (flow != GST_FLOW_OK)
4344 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4346 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4347 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4349 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4352 qtdemux_parse_tfra (qtdemux, tfra_node);
4353 /* iterate all siblings */
4354 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4356 g_node_destroy (mfra_node);
4358 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4364 if (mfro_map.memory != NULL)
4365 gst_buffer_unmap (mfro, &mfro_map);
4366 gst_buffer_unref (mfro);
4369 if (mfra_map.memory != NULL)
4370 gst_buffer_unmap (mfra, &mfra_map);
4371 gst_buffer_unref (mfra);
4378 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4383 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4388 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4393 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4399 add_offset (guint64 offset, guint64 advance)
4401 /* Avoid 64-bit overflow by clamping */
4402 if (offset > G_MAXUINT64 - advance)
4404 return offset + advance;
4407 static GstFlowReturn
4408 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4412 GstBuffer *buf = NULL;
4413 GstFlowReturn ret = GST_FLOW_OK;
4414 guint64 cur_offset = qtdemux->offset;
4417 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4418 if (G_UNLIKELY (ret != GST_FLOW_OK))
4420 gst_buffer_map (buf, &map, GST_MAP_READ);
4421 if (G_LIKELY (map.size >= 8))
4422 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4423 gst_buffer_unmap (buf, &map);
4424 gst_buffer_unref (buf);
4426 /* maybe we already got most we needed, so only consider this eof */
4427 if (G_UNLIKELY (length == 0)) {
4428 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4429 (_("Invalid atom size.")),
4430 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4431 GST_FOURCC_ARGS (fourcc)));
4438 /* record for later parsing when needed */
4439 if (!qtdemux->moof_offset) {
4440 qtdemux->moof_offset = qtdemux->offset;
4442 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4445 qtdemux->offset += length; /* skip moof and keep going */
4447 if (qtdemux->got_moov) {
4448 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4460 GST_LOG_OBJECT (qtdemux,
4461 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4462 GST_FOURCC_ARGS (fourcc), cur_offset);
4463 qtdemux->offset = add_offset (qtdemux->offset, length);
4468 GstBuffer *moov = NULL;
4470 if (qtdemux->got_moov) {
4471 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4472 qtdemux->offset = add_offset (qtdemux->offset, length);
4476 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4477 if (ret != GST_FLOW_OK)
4479 gst_buffer_map (moov, &map, GST_MAP_READ);
4481 if (length != map.size) {
4482 /* Some files have a 'moov' atom at the end of the file which contains
4483 * a terminal 'free' atom where the body of the atom is missing.
4484 * Check for, and permit, this special case.
4486 if (map.size >= 8) {
4487 guint8 *final_data = map.data + (map.size - 8);
4488 guint32 final_length = QT_UINT32 (final_data);
4489 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4491 if (final_fourcc == FOURCC_free
4492 && map.size + final_length - 8 == length) {
4493 /* Ok, we've found that special case. Allocate a new buffer with
4494 * that free atom actually present. */
4495 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4496 gst_buffer_fill (newmoov, 0, map.data, map.size);
4497 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4498 gst_buffer_unmap (moov, &map);
4499 gst_buffer_unref (moov);
4501 gst_buffer_map (moov, &map, GST_MAP_READ);
4506 if (length != map.size) {
4507 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4508 (_("This file is incomplete and cannot be played.")),
4509 ("We got less than expected (received %" G_GSIZE_FORMAT
4510 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4511 (guint) length, cur_offset));
4512 gst_buffer_unmap (moov, &map);
4513 gst_buffer_unref (moov);
4514 ret = GST_FLOW_ERROR;
4517 qtdemux->offset += length;
4519 qtdemux_parse_moov (qtdemux, map.data, length);
4520 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4522 qtdemux_parse_tree (qtdemux);
4523 if (qtdemux->moov_node_compressed) {
4524 g_node_destroy (qtdemux->moov_node_compressed);
4525 g_free (qtdemux->moov_node->data);
4527 qtdemux->moov_node_compressed = NULL;
4528 g_node_destroy (qtdemux->moov_node);
4529 qtdemux->moov_node = NULL;
4530 gst_buffer_unmap (moov, &map);
4531 gst_buffer_unref (moov);
4532 qtdemux->got_moov = TRUE;
4533 if (!qtdemux->fragmented && !qtdemux->upstream_format_is_time) {
4534 /* in this case, parsing the edts entries will give us segments
4536 qtdemux->need_segment = FALSE;
4543 GstBuffer *ftyp = NULL;
4545 /* extract major brand; might come in handy for ISO vs QT issues */
4546 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4547 if (ret != GST_FLOW_OK)
4549 qtdemux->offset += length;
4550 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4551 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4552 gst_buffer_unmap (ftyp, &map);
4553 gst_buffer_unref (ftyp);
4558 GstBuffer *uuid = NULL;
4560 /* uuid are extension atoms */
4561 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4562 if (ret != GST_FLOW_OK)
4564 qtdemux->offset += length;
4565 gst_buffer_map (uuid, &map, GST_MAP_READ);
4566 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4567 gst_buffer_unmap (uuid, &map);
4568 gst_buffer_unref (uuid);
4573 GstBuffer *sidx = NULL;
4574 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4575 if (ret != GST_FLOW_OK)
4577 qtdemux->offset += length;
4578 gst_buffer_map (sidx, &map, GST_MAP_READ);
4579 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4580 gst_buffer_unmap (sidx, &map);
4581 gst_buffer_unref (sidx);
4586 GstBuffer *unknown = NULL;
4588 GST_LOG_OBJECT (qtdemux,
4589 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4590 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4592 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4593 if (ret != GST_FLOW_OK)
4595 gst_buffer_map (unknown, &map, GST_MAP_READ);
4596 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4597 gst_buffer_unmap (unknown, &map);
4598 gst_buffer_unref (unknown);
4599 qtdemux->offset += length;
4605 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4606 /* digested all data, show what we have */
4607 qtdemux_prepare_streams (qtdemux);
4608 QTDEMUX_EXPOSE_LOCK (qtdemux);
4609 ret = qtdemux_expose_streams (qtdemux);
4610 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4612 qtdemux->state = QTDEMUX_STATE_MOVIE;
4613 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4620 /* Seeks to the previous keyframe of the indexed stream and
4621 * aligns other streams with respect to the keyframe timestamp
4622 * of indexed stream. Only called in case of Reverse Playback
4624 static GstFlowReturn
4625 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4627 guint32 seg_idx = 0, k_index = 0;
4628 guint32 ref_seg_idx, ref_k_index;
4629 GstClockTime k_pos = 0, last_stop = 0;
4630 QtDemuxSegment *seg = NULL;
4631 QtDemuxStream *ref_str = NULL;
4632 guint64 seg_media_start_mov; /* segment media start time in mov format */
4636 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4637 * and finally align all the other streams on that timestamp with their
4638 * respective keyframes */
4639 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4640 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4642 /* No candidate yet, take the first stream */
4648 /* So that stream has a segment, we prefer video streams */
4649 if (str->subtype == FOURCC_vide) {
4655 if (G_UNLIKELY (!ref_str)) {
4656 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4660 if (G_UNLIKELY (!ref_str->from_sample)) {
4661 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4665 /* So that stream has been playing from from_sample to to_sample. We will
4666 * get the timestamp of the previous sample and search for a keyframe before
4667 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4668 if (ref_str->subtype == FOURCC_vide) {
4669 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4670 ref_str->from_sample - 1, FALSE);
4672 if (ref_str->from_sample >= 10)
4673 k_index = ref_str->from_sample - 10;
4679 ref_str->samples[k_index].timestamp +
4680 ref_str->samples[k_index].pts_offset;
4682 /* get current segment for that stream */
4683 seg = &ref_str->segments[ref_str->segment_index];
4684 /* Use segment start in original timescale for comparisons */
4685 seg_media_start_mov = seg->trak_media_start;
4687 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4688 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4689 k_index, target_ts, seg_media_start_mov,
4690 GST_TIME_ARGS (seg->media_start));
4692 /* Crawl back through segments to find the one containing this I frame */
4693 while (target_ts < seg_media_start_mov) {
4694 GST_DEBUG_OBJECT (qtdemux,
4695 "keyframe position (sample %u) is out of segment %u " " target %"
4696 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4697 ref_str->segment_index, target_ts, seg_media_start_mov);
4699 if (G_UNLIKELY (!ref_str->segment_index)) {
4700 /* Reached first segment, let's consider it's EOS */
4703 ref_str->segment_index--;
4704 seg = &ref_str->segments[ref_str->segment_index];
4705 /* Use segment start in original timescale for comparisons */
4706 seg_media_start_mov = seg->trak_media_start;
4708 /* Calculate time position of the keyframe and where we should stop */
4710 QTSTREAMTIME_TO_GSTTIME (ref_str,
4711 target_ts - seg->trak_media_start) + seg->time;
4713 QTSTREAMTIME_TO_GSTTIME (ref_str,
4714 ref_str->samples[ref_str->from_sample].timestamp -
4715 seg->trak_media_start) + seg->time;
4717 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4718 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4719 k_index, GST_TIME_ARGS (k_pos));
4721 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4722 qtdemux->segment.position = last_stop;
4723 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4724 GST_TIME_ARGS (last_stop));
4726 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4727 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4731 ref_seg_idx = ref_str->segment_index;
4732 ref_k_index = k_index;
4734 /* Align them all on this */
4735 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4737 GstClockTime seg_time = 0;
4738 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4740 /* aligning reference stream again might lead to backing up to yet another
4741 * keyframe (due to timestamp rounding issues),
4742 * potentially putting more load on downstream; so let's try to avoid */
4743 if (str == ref_str) {
4744 seg_idx = ref_seg_idx;
4745 seg = &str->segments[seg_idx];
4746 k_index = ref_k_index;
4747 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4748 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4750 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4751 GST_DEBUG_OBJECT (qtdemux,
4752 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4753 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4755 /* get segment and time in the segment */
4756 seg = &str->segments[seg_idx];
4757 seg_time = k_pos - seg->time;
4759 /* get the media time in the segment.
4760 * No adjustment for empty "filler" segments */
4761 if (seg->media_start != GST_CLOCK_TIME_NONE)
4762 seg_time += seg->media_start;
4764 /* get the index of the sample with media time */
4765 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4766 GST_DEBUG_OBJECT (qtdemux,
4767 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4768 GST_TIME_ARGS (seg_time), index);
4770 /* find previous keyframe */
4771 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4774 /* Remember until where we want to go */
4775 str->to_sample = str->from_sample - 1;
4776 /* Define our time position */
4778 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4779 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4780 if (seg->media_start != GST_CLOCK_TIME_NONE)
4781 str->time_position -= seg->media_start;
4783 /* Now seek back in time */
4784 gst_qtdemux_move_stream (qtdemux, str, k_index);
4785 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4786 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4787 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4793 return GST_FLOW_EOS;
4797 * Gets the current qt segment start, stop and position for the
4798 * given time offset. This is used in update_segment()
4801 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4802 QtDemuxStream * stream, GstClockTime offset,
4803 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4805 GstClockTime seg_time;
4806 GstClockTime start, stop, time;
4807 QtDemuxSegment *segment;
4809 segment = &stream->segments[stream->segment_index];
4811 /* get time in this segment */
4812 seg_time = (offset - segment->time) * segment->rate;
4814 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4815 GST_TIME_ARGS (seg_time));
4817 if (G_UNLIKELY (seg_time > segment->duration)) {
4818 GST_LOG_OBJECT (stream->pad,
4819 "seg_time > segment->duration %" GST_TIME_FORMAT,
4820 GST_TIME_ARGS (segment->duration));
4821 seg_time = segment->duration;
4824 /* qtdemux->segment.stop is in outside-time-realm, whereas
4825 * segment->media_stop is in track-time-realm.
4827 * In order to compare the two, we need to bring segment.stop
4828 * into the track-time-realm
4830 * FIXME - does this comment still hold? Don't see any conversion here */
4832 stop = qtdemux->segment.stop;
4833 if (stop == GST_CLOCK_TIME_NONE)
4834 stop = qtdemux->segment.duration;
4835 if (stop == GST_CLOCK_TIME_NONE)
4836 stop = segment->media_stop;
4839 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4841 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4842 start = segment->time + seg_time;
4844 stop = start - seg_time + segment->duration;
4845 } else if (qtdemux->segment.rate >= 0) {
4846 start = MIN (segment->media_start + seg_time, stop);
4849 if (segment->media_start >= qtdemux->segment.start) {
4850 time = segment->time;
4852 time = segment->time + (qtdemux->segment.start - segment->media_start);
4855 start = MAX (segment->media_start, qtdemux->segment.start);
4856 stop = MIN (segment->media_start + seg_time, stop);
4865 * Updates the qt segment used for the stream and pushes a new segment event
4866 * downstream on this stream's pad.
4869 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4870 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4871 GstClockTime * _stop)
4873 QtDemuxSegment *segment;
4874 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4875 GstClockTime min_ts;
4879 /* update the current segment */
4880 stream->segment_index = seg_idx;
4882 /* get the segment */
4883 segment = &stream->segments[seg_idx];
4885 if (G_UNLIKELY (offset < segment->time)) {
4886 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4887 GST_TIME_ARGS (segment->time));
4891 /* segment lies beyond total indicated duration */
4892 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4893 segment->time > qtdemux->segment.duration)) {
4894 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4895 " < segment->time %" GST_TIME_FORMAT,
4896 GST_TIME_ARGS (qtdemux->segment.duration),
4897 GST_TIME_ARGS (segment->time));
4901 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4902 &start, &stop, &time);
4904 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4905 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4906 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4908 /* combine global rate with that of the segment */
4909 rate = segment->rate * qtdemux->segment.rate;
4911 /* Copy flags from main segment */
4912 stream->segment.flags = qtdemux->segment.flags;
4914 /* need to offset with the start time of the first sample */
4915 min_ts = gst_qtdemux_streams_get_first_sample_ts (qtdemux);
4917 /* update the segment values used for clipping */
4918 stream->segment.offset = qtdemux->segment.offset;
4919 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4920 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4921 stream->segment.rate = rate;
4922 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4923 stream->cslg_shift) + min_ts;
4924 if (GST_CLOCK_TIME_IS_VALID (stop)) {
4925 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4926 stream->cslg_shift) + min_ts;
4928 stream->segment.time = time + min_ts;
4929 stream->segment.position = stream->segment.start + min_ts;
4931 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4934 /* now prepare and send the segment */
4936 event = gst_event_new_segment (&stream->segment);
4937 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4938 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4940 gst_pad_push_event (stream->pad, event);
4941 /* assume we can send more data now */
4942 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4943 /* clear to send tags on this pad now */
4944 gst_qtdemux_push_tags (qtdemux, stream);
4955 /* activate the given segment number @seg_idx of @stream at time @offset.
4956 * @offset is an absolute global position over all the segments.
4958 * This will push out a NEWSEGMENT event with the right values and
4959 * position the stream index to the first decodable sample before
4963 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4964 guint32 seg_idx, GstClockTime offset)
4966 QtDemuxSegment *segment;
4967 guint32 index, kf_index;
4968 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4970 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4971 seg_idx, GST_TIME_ARGS (offset));
4973 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4977 segment = &stream->segments[stream->segment_index];
4979 /* in the fragmented case, we pick a fragment that starts before our
4980 * desired position and rely on downstream to wait for a keyframe
4981 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4982 * tfra entries tells us which trun/sample the key unit is in, but we don't
4983 * make use of this additional information at the moment) */
4984 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4985 stream->to_sample = G_MAXUINT32;
4988 /* well, it will be taken care of below */
4989 qtdemux->fragmented_seek_pending = FALSE;
4990 /* FIXME ideally the do_fragmented_seek can be done right here,
4991 * rather than at loop level
4992 * (which might even allow handling edit lists in a fragmented file) */
4995 /* We don't need to look for a sample in push-based */
4996 if (!qtdemux->pullbased)
4999 /* and move to the keyframe before the indicated media time of the
5001 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5002 if (qtdemux->segment.rate >= 0) {
5003 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5004 stream->to_sample = G_MAXUINT32;
5005 GST_DEBUG_OBJECT (stream->pad,
5006 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5007 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5008 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5010 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5011 stream->to_sample = index;
5012 GST_DEBUG_OBJECT (stream->pad,
5013 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5014 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5015 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5018 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5019 "this is an empty segment");
5023 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5024 * encountered an error and printed a message so we return appropriately */
5028 /* we're at the right spot */
5029 if (index == stream->sample_index) {
5030 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5034 /* find keyframe of the target index */
5035 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5038 /* indent does stupid stuff with stream->samples[].timestamp */
5040 /* if we move forwards, we don't have to go back to the previous
5041 * keyframe since we already sent that. We can also just jump to
5042 * the keyframe right before the target index if there is one. */
5043 if (index > stream->sample_index) {
5044 /* moving forwards check if we move past a keyframe */
5045 if (kf_index > stream->sample_index) {
5046 GST_DEBUG_OBJECT (stream->pad,
5047 "moving forwards 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);
5052 GST_DEBUG_OBJECT (stream->pad,
5053 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5054 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5055 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5058 GST_DEBUG_OBJECT (stream->pad,
5059 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5060 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5061 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5062 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5070 /* prepare to get the current sample of @stream, getting essential values.
5072 * This function will also prepare and send the segment when needed.
5074 * Return FALSE if the stream is EOS.
5079 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5080 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5081 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5082 gboolean * keyframe)
5084 QtDemuxSample *sample;
5085 GstClockTime time_position;
5088 g_return_val_if_fail (stream != NULL, FALSE);
5090 time_position = stream->time_position;
5091 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5094 seg_idx = stream->segment_index;
5095 if (G_UNLIKELY (seg_idx == -1)) {
5096 /* find segment corresponding to time_position if we are looking
5098 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5101 /* different segment, activate it, sample_index will be set. */
5102 if (G_UNLIKELY (stream->segment_index != seg_idx))
5103 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5105 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5107 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5109 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5110 " prepare empty sample");
5113 *pts = *dts = time_position;
5114 *duration = seg->duration - (time_position - seg->time);
5121 if (stream->sample_index == -1)
5122 stream->sample_index = 0;
5124 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5125 stream->sample_index, stream->n_samples);
5127 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5128 if (!qtdemux->fragmented)
5131 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5135 GST_OBJECT_LOCK (qtdemux);
5136 flow = qtdemux_add_fragmented_samples (qtdemux);
5137 GST_OBJECT_UNLOCK (qtdemux);
5139 if (flow != GST_FLOW_OK)
5142 while (stream->sample_index >= stream->n_samples);
5145 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5146 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5147 stream->sample_index);
5151 /* now get the info for the sample we're at */
5152 sample = &stream->samples[stream->sample_index];
5154 *dts = QTSAMPLE_DTS (stream, sample);
5155 *pts = QTSAMPLE_PTS (stream, sample);
5156 *offset = sample->offset;
5157 *size = sample->size;
5158 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5159 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5166 stream->time_position = GST_CLOCK_TIME_NONE;
5171 /* move to the next sample in @stream.
5173 * Moves to the next segment when needed.
5176 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5178 QtDemuxSample *sample;
5179 QtDemuxSegment *segment;
5181 /* get current segment */
5182 segment = &stream->segments[stream->segment_index];
5184 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5185 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5189 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5190 /* Mark the stream as EOS */
5191 GST_DEBUG_OBJECT (qtdemux,
5192 "reached max allowed sample %u, mark EOS", stream->to_sample);
5193 stream->time_position = GST_CLOCK_TIME_NONE;
5197 /* move to next sample */
5198 stream->sample_index++;
5199 stream->offset_in_sample = 0;
5201 /* reached the last sample, we need the next segment */
5202 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5205 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5206 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5207 stream->sample_index);
5211 /* get next sample */
5212 sample = &stream->samples[stream->sample_index];
5214 /* see if we are past the segment */
5215 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5218 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5219 /* inside the segment, update time_position, looks very familiar to
5220 * GStreamer segments, doesn't it? */
5221 stream->time_position =
5222 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5224 /* not yet in segment, time does not yet increment. This means
5225 * that we are still prerolling keyframes to the decoder so it can
5226 * decode the first sample of the segment. */
5227 stream->time_position = segment->time;
5231 /* move to the next segment */
5234 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5236 if (stream->segment_index == stream->n_segments - 1) {
5237 /* are we at the end of the last segment, we're EOS */
5238 stream->time_position = GST_CLOCK_TIME_NONE;
5240 /* else we're only at the end of the current segment */
5241 stream->time_position = segment->stop_time;
5243 /* make sure we select a new segment */
5245 /* accumulate previous segments */
5246 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5247 stream->accumulated_base +=
5248 (stream->segment.stop -
5249 stream->segment.start) / ABS (stream->segment.rate);
5251 stream->segment_index = -1;
5256 gst_qtdemux_sync_streams (GstQTDemux * demux)
5260 if (demux->n_streams <= 1)
5263 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
5264 QtDemuxStream *stream;
5265 GstClockTime end_time;
5267 stream = QTDEMUX_STREAM (iter->data);
5272 /* TODO advance time on subtitle streams here, if any some day */
5274 /* some clips/trailers may have unbalanced streams at the end,
5275 * so send EOS on shorter stream to prevent stalling others */
5277 /* do not mess with EOS if SEGMENT seeking */
5278 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5281 if (demux->pullbased) {
5282 /* loop mode is sample time based */
5283 if (!STREAM_IS_EOS (stream))
5286 /* push mode is byte position based */
5287 if (stream->n_samples &&
5288 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5292 if (stream->sent_eos)
5295 /* only act if some gap */
5296 end_time = stream->segments[stream->n_segments - 1].stop_time;
5297 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5298 ", stream end: %" GST_TIME_FORMAT,
5299 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5300 if (GST_CLOCK_TIME_IS_VALID (end_time)
5301 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5304 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5305 GST_PAD_NAME (stream->pad));
5306 stream->sent_eos = TRUE;
5307 event = gst_event_new_eos ();
5308 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5309 gst_event_set_seqnum (event, demux->segment_seqnum);
5310 gst_pad_push_event (stream->pad, event);
5315 /* EOS and NOT_LINKED need to be combined. This means that we return:
5317 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5318 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5320 static GstFlowReturn
5321 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5324 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5327 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5330 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5332 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5336 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5337 * completely clipped
5339 * Should be used only with raw buffers */
5341 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5344 guint64 start, stop, cstart, cstop, diff;
5345 GstClockTime pts, duration;
5347 gint num_rate, denom_rate;
5352 osize = size = gst_buffer_get_size (buf);
5355 /* depending on the type, setup the clip parameters */
5356 if (stream->subtype == FOURCC_soun) {
5357 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5358 num_rate = GST_SECOND;
5359 denom_rate = (gint) CUR_STREAM (stream)->rate;
5361 } else if (stream->subtype == FOURCC_vide) {
5363 num_rate = CUR_STREAM (stream)->fps_n;
5364 denom_rate = CUR_STREAM (stream)->fps_d;
5369 if (frame_size <= 0)
5370 goto bad_frame_size;
5372 /* we can only clip if we have a valid pts */
5373 pts = GST_BUFFER_PTS (buf);
5374 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5377 duration = GST_BUFFER_DURATION (buf);
5379 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5381 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5385 stop = start + duration;
5387 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5388 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5391 /* see if some clipping happened */
5392 diff = cstart - start;
5398 /* bring clipped time to samples and to bytes */
5399 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5402 GST_DEBUG_OBJECT (qtdemux,
5403 "clipping start to %" GST_TIME_FORMAT " %"
5404 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5410 diff = stop - cstop;
5415 /* bring clipped time to samples and then to bytes */
5416 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5418 GST_DEBUG_OBJECT (qtdemux,
5419 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5420 " bytes", GST_TIME_ARGS (cstop), diff);
5425 if (offset != 0 || size != osize)
5426 gst_buffer_resize (buf, offset, size);
5428 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5429 GST_BUFFER_PTS (buf) = pts;
5430 GST_BUFFER_DURATION (buf) = duration;
5434 /* dropped buffer */
5437 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5442 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5447 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5452 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5453 gst_buffer_unref (buf);
5459 gst_qtdemux_align_buffer (GstQTDemux * demux,
5460 GstBuffer * buffer, gsize alignment)
5464 gst_buffer_map (buffer, &map, GST_MAP_READ);
5466 if (map.size < sizeof (guintptr)) {
5467 gst_buffer_unmap (buffer, &map);
5471 if (((guintptr) map.data) & (alignment - 1)) {
5472 GstBuffer *new_buffer;
5473 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5475 new_buffer = gst_buffer_new_allocate (NULL,
5476 gst_buffer_get_size (buffer), ¶ms);
5478 /* Copy data "by hand", so ensure alignment is kept: */
5479 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5481 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5482 GST_DEBUG_OBJECT (demux,
5483 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5486 gst_buffer_unmap (buffer, &map);
5487 gst_buffer_unref (buffer);
5492 gst_buffer_unmap (buffer, &map);
5497 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5503 /* We are converting from pairs to triplets */
5504 *res = ccpair_size / 2 * 3;
5505 storage = g_malloc (*res);
5506 for (i = 0; i * 2 < ccpair_size; i += 1) {
5508 storage[i * 3] = 0xfc;
5510 storage[i * 3] = 0xfd;
5511 storage[i * 3 + 1] = ccpair[i * 2];
5512 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5519 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5523 guint32 atom_length, fourcc;
5524 QtDemuxStreamStsdEntry *stsd_entry;
5526 GST_MEMDUMP ("caption atom", data, size);
5528 /* There might be multiple atoms */
5533 atom_length = QT_UINT32 (data);
5534 fourcc = QT_FOURCC (data + 4);
5535 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5538 GST_DEBUG_OBJECT (stream->pad, "here");
5540 /* Check if we have somethig compatible */
5541 stsd_entry = CUR_STREAM (stream);
5542 switch (stsd_entry->fourcc) {
5544 guint8 *cdat = NULL, *cdt2 = NULL;
5545 gsize cdat_size = 0, cdt2_size = 0;
5546 /* Should be cdat or cdt2 */
5547 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5548 GST_WARNING_OBJECT (stream->pad,
5549 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5550 GST_FOURCC_ARGS (fourcc));
5554 /* Convert to cc_data triplet */
5555 if (fourcc == FOURCC_cdat)
5556 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5558 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5559 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5562 /* Check for another atom ? */
5563 if (size > atom_length + 8) {
5564 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5565 if (size >= atom_length + new_atom_length) {
5566 fourcc = QT_FOURCC (data + atom_length + 4);
5567 if (fourcc == FOURCC_cdat) {
5570 convert_to_ccdata (data + atom_length + 8,
5571 new_atom_length - 8, 1, &cdat_size);
5573 GST_WARNING_OBJECT (stream->pad,
5574 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5578 convert_to_ccdata (data + atom_length + 8,
5579 new_atom_length - 8, 2, &cdt2_size);
5581 GST_WARNING_OBJECT (stream->pad,
5582 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5587 *cclen = cdat_size + cdt2_size;
5588 res = g_malloc (*cclen);
5590 memcpy (res, cdat, cdat_size);
5592 memcpy (res + cdat_size, cdt2, cdt2_size);
5598 if (fourcc != FOURCC_ccdp) {
5599 GST_WARNING_OBJECT (stream->pad,
5600 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5601 GST_FOURCC_ARGS (fourcc));
5604 *cclen = atom_length - 8;
5605 res = g_memdup (data + 8, *cclen);
5608 /* Keep this here in case other closed caption formats are added */
5609 g_assert_not_reached ();
5613 GST_MEMDUMP ("Output", res, *cclen);
5618 GST_WARNING ("[cdat] atom is too small or invalid");
5622 /* the input buffer metadata must be writable,
5623 * but time/duration etc not yet set and need not be preserved */
5625 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5632 /* not many cases for now */
5633 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5634 /* send a one time dvd clut event */
5635 if (stream->pending_event && stream->pad)
5636 gst_pad_push_event (stream->pad, stream->pending_event);
5637 stream->pending_event = NULL;
5640 if (G_UNLIKELY (stream->subtype != FOURCC_text
5641 && stream->subtype != FOURCC_sbtl &&
5642 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5646 gst_buffer_map (buf, &map, GST_MAP_READ);
5648 /* empty buffer is sent to terminate previous subtitle */
5649 if (map.size <= 2) {
5650 gst_buffer_unmap (buf, &map);
5651 gst_buffer_unref (buf);
5654 if (stream->subtype == FOURCC_subp) {
5655 /* That's all the processing needed for subpictures */
5656 gst_buffer_unmap (buf, &map);
5660 if (stream->subtype == FOURCC_clcp) {
5663 /* For closed caption, we need to extract the information from the
5664 * [cdat],[cdt2] or [ccdp] atom */
5665 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5666 gst_buffer_unmap (buf, &map);
5667 gst_buffer_unref (buf);
5669 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5671 /* Conversion failed or there's nothing */
5677 nsize = GST_READ_UINT16_BE (map.data);
5678 nsize = MIN (nsize, map.size - 2);
5680 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5683 /* takes care of UTF-8 validation or UTF-16 recognition,
5684 * no other encoding expected */
5685 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5686 gst_buffer_unmap (buf, &map);
5688 gst_buffer_unref (buf);
5689 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5691 /* this should not really happen unless the subtitle is corrupted */
5692 gst_buffer_unref (buf);
5696 /* FIXME ? convert optional subsequent style info to markup */
5701 /* Sets a buffer's attributes properly and pushes it downstream.
5702 * Also checks for additional actions and custom processing that may
5703 * need to be done first.
5705 static GstFlowReturn
5706 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5707 QtDemuxStream * stream, GstBuffer * buf,
5708 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5709 gboolean keyframe, GstClockTime position, guint64 byte_position)
5711 GstFlowReturn ret = GST_FLOW_OK;
5713 /* offset the timestamps according to the edit list */
5715 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5719 gst_buffer_map (buf, &map, GST_MAP_READ);
5720 url = g_strndup ((gchar *) map.data, map.size);
5721 gst_buffer_unmap (buf, &map);
5722 if (url != NULL && strlen (url) != 0) {
5723 /* we have RTSP redirect now */
5724 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5725 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5726 gst_structure_new ("redirect",
5727 "new-location", G_TYPE_STRING, url, NULL)));
5728 qtdemux->posted_redirect = TRUE;
5730 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5736 /* position reporting */
5737 if (qtdemux->segment.rate >= 0) {
5738 qtdemux->segment.position = position;
5739 gst_qtdemux_sync_streams (qtdemux);
5742 if (G_UNLIKELY (!stream->pad)) {
5743 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5744 gst_buffer_unref (buf);
5748 /* send out pending buffers */
5749 while (stream->buffers) {
5750 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5752 if (G_UNLIKELY (stream->discont)) {
5753 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5754 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5755 stream->discont = FALSE;
5757 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5760 if (stream->alignment > 1)
5761 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5762 gst_pad_push (stream->pad, buffer);
5764 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5767 /* we're going to modify the metadata */
5768 buf = gst_buffer_make_writable (buf);
5770 if (G_UNLIKELY (stream->need_process))
5771 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5777 GST_BUFFER_DTS (buf) = dts;
5778 GST_BUFFER_PTS (buf) = pts;
5779 GST_BUFFER_DURATION (buf) = duration;
5780 GST_BUFFER_OFFSET (buf) = -1;
5781 GST_BUFFER_OFFSET_END (buf) = -1;
5783 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5784 gst_buffer_append_memory (buf,
5785 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5787 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5788 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5791 if (G_UNLIKELY (qtdemux->element_index)) {
5792 GstClockTime stream_time;
5795 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5797 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5798 GST_LOG_OBJECT (qtdemux,
5799 "adding association %" GST_TIME_FORMAT "-> %"
5800 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5801 gst_index_add_association (qtdemux->element_index,
5803 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5804 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5805 GST_FORMAT_BYTES, byte_position, NULL);
5810 if (stream->need_clip)
5811 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5813 if (G_UNLIKELY (buf == NULL))
5816 if (G_UNLIKELY (stream->discont)) {
5817 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5818 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5819 stream->discont = FALSE;
5821 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5825 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5826 stream->on_keyframe = FALSE;
5828 stream->on_keyframe = TRUE;
5832 GST_LOG_OBJECT (qtdemux,
5833 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5834 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5835 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5836 GST_PAD_NAME (stream->pad));
5838 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5839 GstStructure *crypto_info;
5840 QtDemuxCencSampleSetInfo *info =
5841 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5845 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5846 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5847 GST_PTR_FORMAT, event);
5848 gst_pad_push_event (stream->pad, event);
5851 if (info->crypto_info == NULL) {
5852 GST_DEBUG_OBJECT (qtdemux,
5853 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5855 /* The end of the crypto_info array matches our n_samples position,
5856 * so count backward from there */
5857 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5858 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5859 /* steal structure from array */
5860 crypto_info = g_ptr_array_index (info->crypto_info, index);
5861 g_ptr_array_index (info->crypto_info, index) = NULL;
5862 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5863 info->crypto_info->len);
5864 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5865 GST_ERROR_OBJECT (qtdemux,
5866 "failed to attach cenc metadata to buffer");
5868 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5869 index, stream->sample_index);
5874 if (stream->alignment > 1)
5875 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5877 ret = gst_pad_push (stream->pad, buf);
5879 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5880 /* mark position in stream, we'll need this to know when to send GAP event */
5881 stream->segment.position = pts + duration;
5888 static const QtDemuxRandomAccessEntry *
5889 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5890 GstClockTime pos, gboolean after)
5892 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5893 guint n_entries = stream->n_ra_entries;
5896 /* we assume the table is sorted */
5897 for (i = 0; i < n_entries; ++i) {
5898 if (entries[i].ts > pos)
5902 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5903 * probably okay to assume that the index lists the very first fragment */
5910 return &entries[i - 1];
5914 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5916 const QtDemuxRandomAccessEntry *best_entry = NULL;
5919 GST_OBJECT_LOCK (qtdemux);
5921 g_assert (qtdemux->n_streams > 0);
5923 /* first see if we can determine where to go to using mfra,
5924 * before we start clearing things */
5925 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5926 const QtDemuxRandomAccessEntry *entry;
5927 QtDemuxStream *stream;
5928 gboolean is_audio_or_video;
5930 stream = QTDEMUX_STREAM (iter->data);
5932 if (stream->ra_entries == NULL)
5935 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5936 is_audio_or_video = TRUE;
5938 is_audio_or_video = FALSE;
5941 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5942 stream->time_position, !is_audio_or_video);
5944 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5945 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5947 stream->pending_seek = entry;
5949 /* decide position to jump to just based on audio/video tracks, not subs */
5950 if (!is_audio_or_video)
5953 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5957 /* no luck, will handle seek otherwise */
5958 if (best_entry == NULL) {
5959 GST_OBJECT_UNLOCK (qtdemux);
5963 /* ok, now we can prepare for processing as of located moof */
5964 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5965 QtDemuxStream *stream;
5967 stream = QTDEMUX_STREAM (iter->data);
5969 g_free (stream->samples);
5970 stream->samples = NULL;
5971 stream->n_samples = 0;
5972 stream->stbl_index = -1; /* no samples have yet been parsed */
5973 stream->sample_index = -1;
5975 if (stream->protection_scheme_info) {
5976 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5977 if (stream->protection_scheme_type == FOURCC_cenc) {
5978 QtDemuxCencSampleSetInfo *info =
5979 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5980 if (info->crypto_info) {
5981 g_ptr_array_free (info->crypto_info, TRUE);
5982 info->crypto_info = NULL;
5988 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5989 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5990 GST_TIME_ARGS (QTDEMUX_FIRST_STREAM (qtdemux)->time_position),
5991 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5993 qtdemux->moof_offset = best_entry->moof_offset;
5995 qtdemux_add_fragmented_samples (qtdemux);
5997 GST_OBJECT_UNLOCK (qtdemux);
6001 static GstFlowReturn
6002 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6004 GstFlowReturn ret = GST_FLOW_OK;
6005 GstBuffer *buf = NULL;
6006 QtDemuxStream *stream, *target_stream = NULL;
6007 GstClockTime min_time;
6009 GstClockTime dts = GST_CLOCK_TIME_NONE;
6010 GstClockTime pts = GST_CLOCK_TIME_NONE;
6011 GstClockTime duration = 0;
6012 gboolean keyframe = FALSE;
6013 guint sample_size = 0;
6018 gst_qtdemux_push_pending_newsegment (qtdemux);
6020 if (qtdemux->fragmented_seek_pending) {
6021 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6022 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6023 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6024 qtdemux->fragmented_seek_pending = FALSE;
6026 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6030 /* Figure out the next stream sample to output, min_time is expressed in
6031 * global time and runs over the edit list segments. */
6032 min_time = G_MAXUINT64;
6033 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6034 GstClockTime position;
6036 stream = QTDEMUX_STREAM (iter->data);
6037 position = stream->time_position;
6039 /* position of -1 is EOS */
6040 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6041 min_time = position;
6042 target_stream = stream;
6046 if (G_UNLIKELY (target_stream == NULL)) {
6047 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6051 /* check for segment end */
6052 if (G_UNLIKELY (qtdemux->segment.stop != -1
6053 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6054 || (qtdemux->segment.rate < 0
6055 && qtdemux->segment.start > min_time))
6056 && target_stream->on_keyframe)) {
6057 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6058 target_stream->time_position = GST_CLOCK_TIME_NONE;
6062 /* gap events for subtitle streams */
6063 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6064 stream = QTDEMUX_STREAM (iter->data);
6065 if (stream->pad && (stream->subtype == FOURCC_subp
6066 || stream->subtype == FOURCC_text
6067 || stream->subtype == FOURCC_sbtl)) {
6068 /* send one second gap events until the stream catches up */
6069 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6070 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6071 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6072 stream->segment.position + GST_SECOND < min_time) {
6074 gst_event_new_gap (stream->segment.position, GST_SECOND);
6075 gst_pad_push_event (stream->pad, gap);
6076 stream->segment.position += GST_SECOND;
6081 stream = target_stream;
6082 /* fetch info for the current sample of this stream */
6083 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6084 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6087 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6088 if (stream->new_caps) {
6089 gst_qtdemux_configure_stream (qtdemux, stream);
6090 qtdemux_do_allocation (qtdemux, stream);
6093 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6094 if (G_UNLIKELY (qtdemux->
6095 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6096 if (stream->subtype == FOURCC_vide && !keyframe) {
6097 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6103 GST_DEBUG_OBJECT (qtdemux,
6104 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6105 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6106 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6107 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6108 GST_TIME_ARGS (duration));
6110 if (G_UNLIKELY (empty)) {
6111 /* empty segment, push a gap if there's a second or more
6112 * difference and move to the next one */
6113 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6114 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6115 stream->segment.position = pts + duration;
6119 /* hmm, empty sample, skip and move to next sample */
6120 if (G_UNLIKELY (sample_size <= 0))
6123 /* last pushed sample was out of boundary, goto next sample */
6124 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6127 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6130 GST_DEBUG_OBJECT (qtdemux,
6131 "size %d larger than stream max_buffer_size %d, trimming",
6132 sample_size, stream->max_buffer_size);
6134 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6137 if (qtdemux->cenc_aux_info_offset > 0) {
6140 GstBuffer *aux_info = NULL;
6142 /* pull the data stored before the sample */
6144 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6145 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6146 if (G_UNLIKELY (ret != GST_FLOW_OK))
6148 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6149 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6150 gst_byte_reader_init (&br, map.data + 8, map.size);
6151 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6152 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6153 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6154 gst_buffer_unmap (aux_info, &map);
6155 gst_buffer_unref (aux_info);
6156 ret = GST_FLOW_ERROR;
6159 gst_buffer_unmap (aux_info, &map);
6160 gst_buffer_unref (aux_info);
6163 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6166 if (stream->use_allocator) {
6167 /* if we have a per-stream allocator, use it */
6168 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6171 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6173 if (G_UNLIKELY (ret != GST_FLOW_OK))
6176 if (size != sample_size) {
6177 pts += gst_util_uint64_scale_int (GST_SECOND,
6178 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6181 gst_util_uint64_scale_int (GST_SECOND,
6182 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6185 gst_util_uint64_scale_int (GST_SECOND,
6186 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6189 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6190 dts, pts, duration, keyframe, min_time, offset);
6192 if (size != sample_size) {
6193 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6194 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6196 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6198 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6199 if (time_position >= segment->media_start) {
6200 /* inside the segment, update time_position, looks very familiar to
6201 * GStreamer segments, doesn't it? */
6202 stream->time_position = (time_position - segment->media_start) +
6205 /* not yet in segment, time does not yet increment. This means
6206 * that we are still prerolling keyframes to the decoder so it can
6207 * decode the first sample of the segment. */
6208 stream->time_position = segment->time;
6213 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6214 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6215 * we have no more data for the pad to push */
6216 if (ret == GST_FLOW_EOS)
6219 stream->offset_in_sample += size;
6220 if (stream->offset_in_sample >= sample_size) {
6221 gst_qtdemux_advance_sample (qtdemux, stream);
6226 gst_qtdemux_advance_sample (qtdemux, stream);
6234 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6240 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6241 /* EOS will be raised if all are EOS */
6248 gst_qtdemux_loop (GstPad * pad)
6250 GstQTDemux *qtdemux;
6254 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6256 cur_offset = qtdemux->offset;
6257 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6258 cur_offset, qt_demux_state_string (qtdemux->state));
6260 switch (qtdemux->state) {
6261 case QTDEMUX_STATE_INITIAL:
6262 case QTDEMUX_STATE_HEADER:
6263 ret = gst_qtdemux_loop_state_header (qtdemux);
6265 case QTDEMUX_STATE_MOVIE:
6266 ret = gst_qtdemux_loop_state_movie (qtdemux);
6267 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6268 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6276 /* if something went wrong, pause */
6277 if (ret != GST_FLOW_OK)
6281 gst_object_unref (qtdemux);
6287 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6288 (NULL), ("streaming stopped, invalid state"));
6289 gst_pad_pause_task (pad);
6290 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6295 const gchar *reason = gst_flow_get_name (ret);
6297 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6299 gst_pad_pause_task (pad);
6301 /* fatal errors need special actions */
6303 if (ret == GST_FLOW_EOS) {
6304 if (qtdemux->n_streams == 0) {
6305 /* we have no streams, post an error */
6306 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6308 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6311 if ((stop = qtdemux->segment.stop) == -1)
6312 stop = qtdemux->segment.duration;
6314 if (qtdemux->segment.rate >= 0) {
6315 GstMessage *message;
6318 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6319 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6320 GST_FORMAT_TIME, stop);
6321 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6322 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6323 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6324 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6326 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6327 gst_qtdemux_push_event (qtdemux, event);
6329 GstMessage *message;
6332 /* For Reverse Playback */
6333 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6334 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6335 GST_FORMAT_TIME, qtdemux->segment.start);
6336 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6337 qtdemux->segment.start);
6338 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6339 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6340 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6342 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6343 gst_qtdemux_push_event (qtdemux, event);
6348 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6349 event = gst_event_new_eos ();
6350 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6351 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6352 gst_qtdemux_push_event (qtdemux, event);
6354 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6355 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6356 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6365 * Returns if there are samples to be played.
6368 has_next_entry (GstQTDemux * demux)
6370 QtDemuxStream *stream;
6373 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6375 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6376 stream = QTDEMUX_STREAM (iter->data);
6378 if (stream->sample_index == -1) {
6379 stream->sample_index = 0;
6380 stream->offset_in_sample = 0;
6383 if (stream->sample_index >= stream->n_samples) {
6384 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6387 GST_DEBUG_OBJECT (demux, "Found a sample");
6391 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6398 * Returns the size of the first entry at the current offset.
6399 * If -1, there are none (which means EOS or empty file).
6402 next_entry_size (GstQTDemux * demux)
6404 QtDemuxStream *stream, *target_stream = NULL;
6405 guint64 smalloffs = (guint64) - 1;
6406 QtDemuxSample *sample;
6409 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6412 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6413 stream = QTDEMUX_STREAM (iter->data);
6415 if (stream->sample_index == -1) {
6416 stream->sample_index = 0;
6417 stream->offset_in_sample = 0;
6420 if (stream->sample_index >= stream->n_samples) {
6421 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6425 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6426 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6427 stream->sample_index);
6431 sample = &stream->samples[stream->sample_index];
6433 GST_LOG_OBJECT (demux,
6434 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6435 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6436 stream->sample_index, sample->offset, sample->size);
6438 if (((smalloffs == -1)
6439 || (sample->offset < smalloffs)) && (sample->size)) {
6440 smalloffs = sample->offset;
6441 target_stream = stream;
6448 GST_LOG_OBJECT (demux,
6449 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6450 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6452 stream = target_stream;
6453 sample = &stream->samples[stream->sample_index];
6455 if (sample->offset >= demux->offset) {
6456 demux->todrop = sample->offset - demux->offset;
6457 return sample->size + demux->todrop;
6460 GST_DEBUG_OBJECT (demux,
6461 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6466 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6468 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6470 gst_element_post_message (GST_ELEMENT_CAST (demux),
6471 gst_message_new_element (GST_OBJECT_CAST (demux),
6472 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6476 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6481 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6484 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6485 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6486 GST_SEEK_TYPE_NONE, -1);
6488 /* store seqnum to drop flush events, they don't need to reach downstream */
6489 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6490 res = gst_pad_push_event (demux->sinkpad, event);
6491 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6496 /* check for seekable upstream, above and beyond a mere query */
6498 gst_qtdemux_check_seekability (GstQTDemux * demux)
6501 gboolean seekable = FALSE;
6502 gint64 start = -1, stop = -1;
6504 if (demux->upstream_size)
6507 if (demux->upstream_format_is_time)
6510 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6511 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6512 GST_DEBUG_OBJECT (demux, "seeking query failed");
6516 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6518 /* try harder to query upstream size if we didn't get it the first time */
6519 if (seekable && stop == -1) {
6520 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6521 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6524 /* if upstream doesn't know the size, it's likely that it's not seekable in
6525 * practice even if it technically may be seekable */
6526 if (seekable && (start != 0 || stop <= start)) {
6527 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6532 gst_query_unref (query);
6534 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6535 G_GUINT64_FORMAT ")", seekable, start, stop);
6536 demux->upstream_seekable = seekable;
6537 demux->upstream_size = seekable ? stop : -1;
6541 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6543 g_return_if_fail (bytes <= demux->todrop);
6545 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6546 gst_adapter_flush (demux->adapter, bytes);
6547 demux->neededbytes -= bytes;
6548 demux->offset += bytes;
6549 demux->todrop -= bytes;
6553 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6555 if (G_UNLIKELY (demux->need_segment)) {
6559 gst_qtdemux_push_pending_newsegment (demux);
6560 /* clear to send tags on all streams */
6561 for (iter = demux->active_streams, i = 0; iter;
6562 iter = g_list_next (iter), i++) {
6563 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6564 gst_qtdemux_push_tags (demux, stream);
6565 if (CUR_STREAM (stream)->sparse) {
6566 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6567 gst_pad_push_event (stream->pad,
6568 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6574 /* Used for push mode only. */
6576 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6577 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6579 GstClockTime ts, dur;
6583 stream->segments[segment_index].duration - (pos -
6584 stream->segments[segment_index].time);
6585 stream->time_position += dur;
6587 /* Only gaps with a duration of at least one second are propagated.
6588 * Same workaround as in pull mode.
6589 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6590 if (dur >= GST_SECOND) {
6592 gap = gst_event_new_gap (ts, dur);
6594 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6595 "segment: %" GST_PTR_FORMAT, gap);
6596 gst_pad_push_event (stream->pad, gap);
6601 gst_qtdemux_streams_get_first_sample_ts (GstQTDemux * demux)
6603 GstClockTime res = GST_CLOCK_TIME_NONE;
6606 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6607 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6608 if (stream->n_samples) {
6609 res = MIN (QTSAMPLE_PTS (stream, &stream->samples[0]), res);
6610 res = MIN (QTSAMPLE_DTS (stream, &stream->samples[0]), res);
6617 gst_qtdemux_streams_have_samples (GstQTDemux * demux)
6621 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6622 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6623 if (stream->n_samples)
6629 static GstFlowReturn
6630 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6634 demux = GST_QTDEMUX (parent);
6636 GST_DEBUG_OBJECT (demux,
6637 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6638 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6639 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6640 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6641 gst_buffer_get_size (inbuf), demux->offset);
6643 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6644 gboolean is_gap_input = FALSE;
6647 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6649 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6650 QTDEMUX_STREAM (iter->data)->discont = TRUE;
6653 /* Check if we can land back on our feet in the case where upstream is
6654 * handling the seeking/pushing of samples with gaps in between (like
6655 * in the case of trick-mode DASH for example) */
6656 if (demux->upstream_format_is_time
6657 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6658 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6660 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6661 GST_LOG_OBJECT (demux,
6662 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6663 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6665 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6666 stream, GST_BUFFER_OFFSET (inbuf));
6668 QtDemuxSample *sample = &stream->samples[res];
6669 GST_LOG_OBJECT (demux,
6670 "Checking if sample %d from track-id %u is valid (offset:%"
6671 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6672 stream->track_id, sample->offset, sample->size);
6673 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6674 GST_LOG_OBJECT (demux,
6675 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6677 is_gap_input = TRUE;
6678 /* We can go back to standard playback mode */
6679 demux->state = QTDEMUX_STATE_MOVIE;
6680 /* Remember which sample this stream is at */
6681 stream->sample_index = res;
6682 /* Finally update all push-based values to the expected values */
6683 demux->neededbytes = stream->samples[res].size;
6684 demux->offset = GST_BUFFER_OFFSET (inbuf);
6686 demux->mdatsize - demux->offset + demux->mdatoffset;
6691 if (!is_gap_input) {
6692 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6693 /* Reset state if it's a real discont */
6694 demux->neededbytes = 16;
6695 demux->state = QTDEMUX_STATE_INITIAL;
6696 demux->offset = GST_BUFFER_OFFSET (inbuf);
6697 gst_adapter_clear (demux->adapter);
6700 /* Reverse fragmented playback, need to flush all we have before
6701 * consuming a new fragment.
6702 * The samples array have the timestamps calculated by accumulating the
6703 * durations but this won't work for reverse playback of fragments as
6704 * the timestamps of a subsequent fragment should be smaller than the
6705 * previously received one. */
6706 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6707 gst_qtdemux_process_adapter (demux, TRUE);
6708 g_list_foreach (demux->active_streams,
6709 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6713 gst_adapter_push (demux->adapter, inbuf);
6715 GST_DEBUG_OBJECT (demux,
6716 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6717 demux->neededbytes, gst_adapter_available (demux->adapter));
6719 return gst_qtdemux_process_adapter (demux, FALSE);
6722 static GstFlowReturn
6723 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6725 GstFlowReturn ret = GST_FLOW_OK;
6727 /* we never really mean to buffer that much */
6728 if (demux->neededbytes == -1) {
6732 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6733 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6735 #ifndef GST_DISABLE_GST_DEBUG
6737 guint64 discont_offset, distance_from_discont;
6739 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6740 distance_from_discont =
6741 gst_adapter_distance_from_discont (demux->adapter);
6743 GST_DEBUG_OBJECT (demux,
6744 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6745 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6746 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6747 demux->offset, discont_offset, distance_from_discont);
6751 switch (demux->state) {
6752 case QTDEMUX_STATE_INITIAL:{
6757 gst_qtdemux_check_seekability (demux);
6759 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6761 /* get fourcc/length, set neededbytes */
6762 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6764 gst_adapter_unmap (demux->adapter);
6766 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6767 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6769 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6770 (_("This file is invalid and cannot be played.")),
6771 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6772 GST_FOURCC_ARGS (fourcc)));
6773 ret = GST_FLOW_ERROR;
6776 if (fourcc == FOURCC_mdat) {
6777 gint next_entry = next_entry_size (demux);
6778 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6779 /* we have the headers, start playback */
6780 demux->state = QTDEMUX_STATE_MOVIE;
6781 demux->neededbytes = next_entry;
6782 demux->mdatleft = size;
6783 demux->mdatsize = demux->mdatleft;
6785 /* no headers yet, try to get them */
6788 guint64 old, target;
6791 old = demux->offset;
6792 target = old + size;
6794 /* try to jump over the atom with a seek */
6795 /* only bother if it seems worth doing so,
6796 * and avoids possible upstream/server problems */
6797 if (demux->upstream_seekable &&
6798 demux->upstream_size > 4 * (1 << 20)) {
6799 res = qtdemux_seek_offset (demux, target);
6801 GST_DEBUG_OBJECT (demux, "skipping seek");
6806 GST_DEBUG_OBJECT (demux, "seek success");
6807 /* remember the offset fo the first mdat so we can seek back to it
6808 * after we have the headers */
6809 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6810 demux->first_mdat = old;
6811 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6814 /* seek worked, continue reading */
6815 demux->offset = target;
6816 demux->neededbytes = 16;
6817 demux->state = QTDEMUX_STATE_INITIAL;
6819 /* seek failed, need to buffer */
6820 demux->offset = old;
6821 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6822 /* there may be multiple mdat (or alike) buffers */
6824 if (demux->mdatbuffer)
6825 bs = gst_buffer_get_size (demux->mdatbuffer);
6828 if (size + bs > 10 * (1 << 20))
6830 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6831 demux->neededbytes = size;
6832 if (!demux->mdatbuffer)
6833 demux->mdatoffset = demux->offset;
6836 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6837 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6838 (_("This file is invalid and cannot be played.")),
6839 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6840 GST_FOURCC_ARGS (fourcc), size));
6841 ret = GST_FLOW_ERROR;
6844 /* this means we already started buffering and still no moov header,
6845 * let's continue buffering everything till we get moov */
6846 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6847 || fourcc == FOURCC_moof))
6849 demux->neededbytes = size;
6850 demux->state = QTDEMUX_STATE_HEADER;
6854 case QTDEMUX_STATE_HEADER:{
6858 GST_DEBUG_OBJECT (demux, "In header");
6860 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6862 /* parse the header */
6863 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6865 if (fourcc == FOURCC_moov) {
6866 /* in usual fragmented setup we could try to scan for more
6867 * and end up at the the moov (after mdat) again */
6868 if (demux->got_moov && demux->n_streams > 0 &&
6870 || demux->last_moov_offset == demux->offset)) {
6871 GST_DEBUG_OBJECT (demux,
6872 "Skipping moov atom as we have (this) one already");
6874 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6876 if (demux->got_moov && demux->fragmented) {
6877 GST_DEBUG_OBJECT (demux,
6878 "Got a second moov, clean up data from old one");
6879 if (demux->moov_node_compressed) {
6880 g_node_destroy (demux->moov_node_compressed);
6881 if (demux->moov_node)
6882 g_free (demux->moov_node->data);
6884 demux->moov_node_compressed = NULL;
6885 if (demux->moov_node)
6886 g_node_destroy (demux->moov_node);
6887 demux->moov_node = NULL;
6890 demux->last_moov_offset = demux->offset;
6892 /* Update streams with new moov */
6893 demux->old_streams =
6894 g_list_concat (demux->old_streams, demux->active_streams);
6895 demux->active_streams = NULL;
6897 qtdemux_parse_moov (demux, data, demux->neededbytes);
6898 qtdemux_node_dump (demux, demux->moov_node);
6899 qtdemux_parse_tree (demux);
6900 qtdemux_prepare_streams (demux);
6901 QTDEMUX_EXPOSE_LOCK (demux);
6902 qtdemux_expose_streams (demux);
6903 QTDEMUX_EXPOSE_UNLOCK (demux);
6905 demux->got_moov = TRUE;
6906 demux->need_segment = TRUE;
6908 /* Forward upstream driven time format segment, and also do not try
6909 * to map edit list with the upstream time format segment.
6910 * It's upstream element's role (the origin of time format segment)
6912 if (demux->upstream_format_is_time)
6913 gst_qtdemux_check_send_pending_segment (demux);
6915 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6918 demux->need_segment = FALSE;
6920 if (demux->moov_node_compressed) {
6921 g_node_destroy (demux->moov_node_compressed);
6922 g_free (demux->moov_node->data);
6924 demux->moov_node_compressed = NULL;
6925 g_node_destroy (demux->moov_node);
6926 demux->moov_node = NULL;
6927 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6929 } else if (fourcc == FOURCC_moof) {
6930 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6932 GstClockTime prev_pts;
6933 guint64 prev_offset;
6934 guint64 adapter_discont_offset, adapter_discont_dist;
6936 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6939 * The timestamp of the moof buffer is relevant as some scenarios
6940 * won't have the initial timestamp in the atoms. Whenever a new
6941 * buffer has started, we get that buffer's PTS and use it as a base
6942 * timestamp for the trun entries.
6944 * To keep track of the current buffer timestamp and starting point
6945 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6946 * from the beggining of the buffer, with the distance and demux->offset
6947 * we know if it is still the same buffer or not.
6949 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6950 prev_offset = demux->offset - dist;
6951 if (demux->fragment_start_offset == -1
6952 || prev_offset > demux->fragment_start_offset) {
6953 demux->fragment_start_offset = prev_offset;
6954 demux->fragment_start = prev_pts;
6955 GST_DEBUG_OBJECT (demux,
6956 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6957 GST_TIME_FORMAT, demux->fragment_start_offset,
6958 GST_TIME_ARGS (demux->fragment_start));
6961 /* We can't use prev_offset() here because this would require
6962 * upstream to set consistent and correct offsets on all buffers
6963 * since the discont. Nothing ever did that in the past and we
6964 * would break backwards compatibility here then.
6965 * Instead take the offset we had at the last discont and count
6966 * the bytes from there. This works with old code as there would
6967 * be no discont between moov and moof, and also works with
6968 * adaptivedemux which correctly sets offset and will set the
6969 * DISCONT flag accordingly when needed.
6971 * We also only do this for upstream TIME segments as otherwise
6972 * there are potential backwards compatibility problems with
6973 * seeking in PUSH mode and upstream providing inconsistent
6975 adapter_discont_offset =
6976 gst_adapter_offset_at_discont (demux->adapter);
6977 adapter_discont_dist =
6978 gst_adapter_distance_from_discont (demux->adapter);
6980 GST_DEBUG_OBJECT (demux,
6981 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6982 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6983 demux->offset, adapter_discont_offset, adapter_discont_dist);
6985 if (demux->upstream_format_is_time) {
6986 demux->moof_offset = adapter_discont_offset;
6987 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6988 demux->moof_offset += adapter_discont_dist;
6989 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6990 demux->moof_offset = demux->offset;
6992 demux->moof_offset = demux->offset;
6995 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6996 demux->moof_offset, NULL)) {
6997 gst_adapter_unmap (demux->adapter);
6998 ret = GST_FLOW_ERROR;
7002 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7003 if (demux->mss_mode && !demux->exposed) {
7004 QTDEMUX_EXPOSE_LOCK (demux);
7005 qtdemux_expose_streams (demux);
7006 QTDEMUX_EXPOSE_UNLOCK (demux);
7009 gst_qtdemux_check_send_pending_segment (demux);
7011 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7013 } else if (fourcc == FOURCC_ftyp) {
7014 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7015 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7016 } else if (fourcc == FOURCC_uuid) {
7017 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7018 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7019 } else if (fourcc == FOURCC_sidx) {
7020 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7021 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7025 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7029 /* [free] and [skip] are padding atoms */
7030 GST_DEBUG_OBJECT (demux,
7031 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7032 GST_FOURCC_ARGS (fourcc));
7035 GST_WARNING_OBJECT (demux,
7036 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7037 GST_FOURCC_ARGS (fourcc));
7038 /* Let's jump that one and go back to initial state */
7042 gst_adapter_unmap (demux->adapter);
7045 if (demux->mdatbuffer && demux->n_streams) {
7046 gsize remaining_data_size = 0;
7048 /* the mdat was before the header */
7049 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7050 demux->n_streams, demux->mdatbuffer);
7051 /* restore our adapter/offset view of things with upstream;
7052 * put preceding buffered data ahead of current moov data.
7053 * This should also handle evil mdat, moov, mdat cases and alike */
7054 gst_adapter_flush (demux->adapter, demux->neededbytes);
7056 /* Store any remaining data after the mdat for later usage */
7057 remaining_data_size = gst_adapter_available (demux->adapter);
7058 if (remaining_data_size > 0) {
7059 g_assert (demux->restoredata_buffer == NULL);
7060 demux->restoredata_buffer =
7061 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7062 demux->restoredata_offset = demux->offset + demux->neededbytes;
7063 GST_DEBUG_OBJECT (demux,
7064 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7065 G_GUINT64_FORMAT, remaining_data_size,
7066 demux->restoredata_offset);
7069 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7070 demux->mdatbuffer = NULL;
7071 demux->offset = demux->mdatoffset;
7072 demux->neededbytes = next_entry_size (demux);
7073 demux->state = QTDEMUX_STATE_MOVIE;
7074 demux->mdatleft = gst_adapter_available (demux->adapter);
7075 demux->mdatsize = demux->mdatleft;
7077 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7078 gst_adapter_flush (demux->adapter, demux->neededbytes);
7080 /* only go back to the mdat if there are samples to play */
7081 if (demux->got_moov && demux->first_mdat != -1
7082 && has_next_entry (demux)) {
7085 /* we need to seek back */
7086 res = qtdemux_seek_offset (demux, demux->first_mdat);
7088 demux->offset = demux->first_mdat;
7090 GST_DEBUG_OBJECT (demux, "Seek back failed");
7093 demux->offset += demux->neededbytes;
7095 demux->neededbytes = 16;
7096 demux->state = QTDEMUX_STATE_INITIAL;
7101 case QTDEMUX_STATE_BUFFER_MDAT:{
7105 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7107 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7108 gst_buffer_extract (buf, 0, fourcc, 4);
7109 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7110 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7111 if (demux->mdatbuffer)
7112 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7114 demux->mdatbuffer = buf;
7115 demux->offset += demux->neededbytes;
7116 demux->neededbytes = 16;
7117 demux->state = QTDEMUX_STATE_INITIAL;
7118 gst_qtdemux_post_progress (demux, 1, 1);
7122 case QTDEMUX_STATE_MOVIE:{
7123 QtDemuxStream *stream = NULL;
7124 QtDemuxSample *sample;
7125 GstClockTime dts, pts, duration;
7129 GST_DEBUG_OBJECT (demux,
7130 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7132 if (demux->fragmented) {
7133 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7135 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7136 /* if needed data starts within this atom,
7137 * then it should not exceed this atom */
7138 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7139 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7140 (_("This file is invalid and cannot be played.")),
7141 ("sample data crosses atom boundary"));
7142 ret = GST_FLOW_ERROR;
7145 demux->mdatleft -= demux->neededbytes;
7147 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7148 /* so we are dropping more than left in this atom */
7149 gst_qtdemux_drop_data (demux, demux->mdatleft);
7150 demux->mdatleft = 0;
7152 /* need to resume atom parsing so we do not miss any other pieces */
7153 demux->state = QTDEMUX_STATE_INITIAL;
7154 demux->neededbytes = 16;
7156 /* check if there was any stored post mdat data from previous buffers */
7157 if (demux->restoredata_buffer) {
7158 g_assert (gst_adapter_available (demux->adapter) == 0);
7160 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7161 demux->restoredata_buffer = NULL;
7162 demux->offset = demux->restoredata_offset;
7169 if (demux->todrop) {
7170 if (demux->cenc_aux_info_offset > 0) {
7174 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7175 data = gst_adapter_map (demux->adapter, demux->todrop);
7176 gst_byte_reader_init (&br, data + 8, demux->todrop);
7177 if (!qtdemux_parse_cenc_aux_info (demux,
7178 QTDEMUX_FIRST_STREAM (demux), &br,
7179 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7180 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7181 ret = GST_FLOW_ERROR;
7182 gst_adapter_unmap (demux->adapter);
7183 g_free (demux->cenc_aux_info_sizes);
7184 demux->cenc_aux_info_sizes = NULL;
7187 demux->cenc_aux_info_offset = 0;
7188 g_free (demux->cenc_aux_info_sizes);
7189 demux->cenc_aux_info_sizes = NULL;
7190 gst_adapter_unmap (demux->adapter);
7192 gst_qtdemux_drop_data (demux, demux->todrop);
7196 /* initial newsegment sent here after having added pads,
7197 * possible others in sink_event */
7198 gst_qtdemux_check_send_pending_segment (demux);
7200 /* Figure out which stream this packet belongs to */
7201 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7202 stream = QTDEMUX_STREAM (iter->data);
7203 if (stream->sample_index >= stream->n_samples) {
7204 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7208 GST_LOG_OBJECT (demux,
7209 "Checking track-id %u (sample_index:%d / offset:%"
7210 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7211 stream->sample_index,
7212 stream->samples[stream->sample_index].offset,
7213 stream->samples[stream->sample_index].size);
7215 if (stream->samples[stream->sample_index].offset == demux->offset)
7219 if (G_UNLIKELY (stream == NULL))
7220 goto unknown_stream;
7222 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7224 if (stream->new_caps) {
7225 gst_qtdemux_configure_stream (demux, stream);
7228 /* Put data in a buffer, set timestamps, caps, ... */
7229 sample = &stream->samples[stream->sample_index];
7231 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7232 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7233 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7235 dts = QTSAMPLE_DTS (stream, sample);
7236 pts = QTSAMPLE_PTS (stream, sample);
7237 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7238 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7240 /* check for segment end */
7241 if (G_UNLIKELY (demux->segment.stop != -1
7242 && demux->segment.stop <= pts && stream->on_keyframe)) {
7243 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7244 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7246 /* skip this data, stream is EOS */
7247 gst_adapter_flush (demux->adapter, demux->neededbytes);
7248 demux->offset += demux->neededbytes;
7250 /* check if all streams are eos */
7252 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7253 if (!STREAM_IS_EOS (QTDEMUX_STREAM (iter->data))) {
7262 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7264 /* FIXME: should either be an assert or a plain check */
7265 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7267 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7268 dts, pts, duration, keyframe, dts, demux->offset);
7272 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7274 /* skip this data, stream is EOS */
7275 gst_adapter_flush (demux->adapter, demux->neededbytes);
7278 stream->sample_index++;
7279 stream->offset_in_sample = 0;
7281 /* update current offset and figure out size of next buffer */
7282 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7283 demux->offset, demux->neededbytes);
7284 demux->offset += demux->neededbytes;
7285 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7289 if (ret == GST_FLOW_EOS) {
7290 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7291 demux->neededbytes = -1;
7295 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7296 if (demux->fragmented) {
7297 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7298 /* there may be more to follow, only finish this atom */
7299 demux->todrop = demux->mdatleft;
7300 demux->neededbytes = demux->todrop;
7305 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7306 goto non_ok_unlinked_flow;
7315 /* when buffering movie data, at least show user something is happening */
7316 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7317 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7318 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7319 demux->neededbytes);
7326 non_ok_unlinked_flow:
7328 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7329 gst_flow_get_name (ret));
7334 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7335 ret = GST_FLOW_ERROR;
7340 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7346 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7347 (NULL), ("qtdemuxer invalid state %d", demux->state));
7348 ret = GST_FLOW_ERROR;
7353 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7354 (NULL), ("no 'moov' atom within the first 10 MB"));
7355 ret = GST_FLOW_ERROR;
7361 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7366 query = gst_query_new_scheduling ();
7368 if (!gst_pad_peer_query (sinkpad, query)) {
7369 gst_query_unref (query);
7373 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7374 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7375 gst_query_unref (query);
7380 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7381 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7385 GST_DEBUG_OBJECT (sinkpad, "activating push");
7386 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7391 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7392 GstPadMode mode, gboolean active)
7395 GstQTDemux *demux = GST_QTDEMUX (parent);
7398 case GST_PAD_MODE_PUSH:
7399 demux->pullbased = FALSE;
7402 case GST_PAD_MODE_PULL:
7404 demux->pullbased = TRUE;
7405 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7408 res = gst_pad_stop_task (sinkpad);
7420 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7426 memset (&z, 0, sizeof (z));
7431 if ((ret = inflateInit (&z)) != Z_OK) {
7432 GST_ERROR ("inflateInit() returned %d", ret);
7436 z.next_in = z_buffer;
7437 z.avail_in = z_length;
7439 buffer = (guint8 *) g_malloc (*length);
7440 z.avail_out = *length;
7441 z.next_out = (Bytef *) buffer;
7443 ret = inflate (&z, Z_NO_FLUSH);
7444 if (ret == Z_STREAM_END) {
7446 } else if (ret != Z_OK) {
7447 GST_WARNING ("inflate() returned %d", ret);
7452 buffer = (guint8 *) g_realloc (buffer, *length);
7453 z.next_out = (Bytef *) (buffer + z.total_out);
7454 z.avail_out += 4096;
7455 } while (z.avail_in > 0);
7457 if (ret != Z_STREAM_END) {
7462 *length = z.total_out;
7469 #endif /* HAVE_ZLIB */
7472 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7476 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7478 /* counts as header data */
7479 qtdemux->header_size += length;
7481 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7482 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7484 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7491 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7492 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7493 if (dcom == NULL || cmvd == NULL)
7494 goto invalid_compression;
7496 dcom_len = QT_UINT32 (dcom->data);
7498 goto invalid_compression;
7500 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7504 guint uncompressed_length;
7505 guint compressed_length;
7509 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7511 goto invalid_compression;
7513 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7514 compressed_length = cmvd_len - 12;
7515 GST_LOG ("length = %u", uncompressed_length);
7518 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7519 compressed_length, &uncompressed_length);
7522 qtdemux->moov_node_compressed = qtdemux->moov_node;
7523 qtdemux->moov_node = g_node_new (buf);
7525 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7526 uncompressed_length);
7530 #endif /* HAVE_ZLIB */
7532 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7533 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7540 invalid_compression:
7542 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7548 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7551 while (G_UNLIKELY (buf < end)) {
7555 if (G_UNLIKELY (buf + 4 > end)) {
7556 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7559 len = QT_UINT32 (buf);
7560 if (G_UNLIKELY (len == 0)) {
7561 GST_LOG_OBJECT (qtdemux, "empty container");
7564 if (G_UNLIKELY (len < 8)) {
7565 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7568 if (G_UNLIKELY (len > (end - buf))) {
7569 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7570 (gint) (end - buf));
7574 child = g_node_new ((guint8 *) buf);
7575 g_node_append (node, child);
7576 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7577 qtdemux_parse_node (qtdemux, child, buf, len);
7585 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7588 int len = QT_UINT32 (xdxt->data);
7589 guint8 *buf = xdxt->data;
7590 guint8 *end = buf + len;
7593 /* skip size and type */
7601 size = QT_UINT32 (buf);
7602 type = QT_FOURCC (buf + 4);
7604 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7606 if (buf + size > end || size <= 0)
7612 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7613 GST_FOURCC_ARGS (type));
7617 buffer = gst_buffer_new_and_alloc (size);
7618 gst_buffer_fill (buffer, 0, buf, size);
7619 stream->buffers = g_slist_append (stream->buffers, buffer);
7620 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7623 buffer = gst_buffer_new_and_alloc (size);
7624 gst_buffer_fill (buffer, 0, buf, size);
7625 stream->buffers = g_slist_append (stream->buffers, buffer);
7626 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7629 buffer = gst_buffer_new_and_alloc (size);
7630 gst_buffer_fill (buffer, 0, buf, size);
7631 stream->buffers = g_slist_append (stream->buffers, buffer);
7632 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7635 GST_WARNING_OBJECT (qtdemux,
7636 "unknown theora cookie %" GST_FOURCC_FORMAT,
7637 GST_FOURCC_ARGS (type));
7646 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7650 guint32 node_length = 0;
7651 const QtNodeType *type;
7654 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7656 if (G_UNLIKELY (length < 8))
7657 goto not_enough_data;
7659 node_length = QT_UINT32 (buffer);
7660 fourcc = QT_FOURCC (buffer + 4);
7662 /* ignore empty nodes */
7663 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7666 type = qtdemux_type_get (fourcc);
7668 end = buffer + length;
7670 GST_LOG_OBJECT (qtdemux,
7671 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7672 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7674 if (node_length > length)
7675 goto broken_atom_size;
7677 if (type->flags & QT_FLAG_CONTAINER) {
7678 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7683 if (node_length < 20) {
7684 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7687 GST_DEBUG_OBJECT (qtdemux,
7688 "parsing stsd (sample table, sample description) atom");
7689 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7690 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7701 /* also read alac (or whatever) in stead of mp4a in the following,
7702 * since a similar layout is used in other cases as well */
7703 if (fourcc == FOURCC_mp4a)
7705 else if (fourcc == FOURCC_fLaC)
7710 /* There are two things we might encounter here: a true mp4a atom, and
7711 an mp4a entry in an stsd atom. The latter is what we're interested
7712 in, and it looks like an atom, but isn't really one. The true mp4a
7713 atom is short, so we detect it based on length here. */
7714 if (length < min_size) {
7715 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7716 GST_FOURCC_ARGS (fourcc));
7720 /* 'version' here is the sound sample description version. Types 0 and
7721 1 are documented in the QTFF reference, but type 2 is not: it's
7722 described in Apple header files instead (struct SoundDescriptionV2
7724 version = QT_UINT16 (buffer + 16);
7726 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7727 GST_FOURCC_ARGS (fourcc), version);
7729 /* parse any esds descriptors */
7741 GST_WARNING_OBJECT (qtdemux,
7742 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7743 GST_FOURCC_ARGS (fourcc), version);
7748 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7774 /* codec_data is contained inside these atoms, which all have
7775 * the same format. */
7776 /* video sample description size is 86 bytes without extension.
7777 * node_length have to be bigger than 86 bytes because video sample
7778 * description can include extenstions such as esds, fiel, glbl, etc. */
7779 if (node_length < 86) {
7780 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7781 " sample description length too short (%u < 86)",
7782 GST_FOURCC_ARGS (fourcc), node_length);
7786 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7787 GST_FOURCC_ARGS (fourcc));
7789 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7791 * revision level (2 bytes) : must be set to 0. */
7792 version = QT_UINT32 (buffer + 16);
7793 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7795 /* compressor name : PASCAL string and informative purposes
7796 * first byte : the number of bytes to be displayed.
7797 * it has to be less than 32 because it is reserved
7798 * space of 32 bytes total including itself. */
7799 str_len = QT_UINT8 (buffer + 50);
7801 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7802 (char *) buffer + 51);
7804 GST_WARNING_OBJECT (qtdemux,
7805 "compressorname length too big (%u > 31)", str_len);
7807 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7809 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7814 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7816 /* You are reading this correctly. QTFF specifies that the
7817 * metadata atom is a short atom, whereas ISO BMFF specifies
7818 * it's a full atom. But since so many people are doing things
7819 * differently, we actually peek into the atom to see which
7822 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7823 GST_FOURCC_ARGS (fourcc));
7826 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7827 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7828 * starts with a 'hdlr' atom */
7829 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7830 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7831 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7832 * with version/flags both set to zero */
7833 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7835 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7840 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7841 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7842 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7851 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7852 GST_FOURCC_ARGS (fourcc));
7856 version = QT_UINT32 (buffer + 12);
7857 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7864 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7869 if (length < offset) {
7870 GST_WARNING_OBJECT (qtdemux,
7871 "skipping too small %" GST_FOURCC_FORMAT " box",
7872 GST_FOURCC_ARGS (fourcc));
7875 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7881 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7886 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7891 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7895 if (!strcmp (type->name, "unknown"))
7896 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7900 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7901 GST_FOURCC_ARGS (fourcc));
7907 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7908 (_("This file is corrupt and cannot be played.")),
7909 ("Not enough data for an atom header, got only %u bytes", length));
7914 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7915 (_("This file is corrupt and cannot be played.")),
7916 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7917 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7924 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7928 guint32 child_fourcc;
7930 for (child = g_node_first_child (node); child;
7931 child = g_node_next_sibling (child)) {
7932 buffer = (guint8 *) child->data;
7934 child_fourcc = QT_FOURCC (buffer + 4);
7936 if (G_UNLIKELY (child_fourcc == fourcc)) {
7944 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7945 GstByteReader * parser)
7949 guint32 child_fourcc, child_len;
7951 for (child = g_node_first_child (node); child;
7952 child = g_node_next_sibling (child)) {
7953 buffer = (guint8 *) child->data;
7955 child_len = QT_UINT32 (buffer);
7956 child_fourcc = QT_FOURCC (buffer + 4);
7958 if (G_UNLIKELY (child_fourcc == fourcc)) {
7959 if (G_UNLIKELY (child_len < (4 + 4)))
7961 /* FIXME: must verify if atom length < parent atom length */
7962 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7970 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7972 return g_node_nth_child (node, index);
7976 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7977 GstByteReader * parser)
7981 guint32 child_fourcc, child_len;
7983 for (child = g_node_next_sibling (node); child;
7984 child = g_node_next_sibling (child)) {
7985 buffer = (guint8 *) child->data;
7987 child_fourcc = QT_FOURCC (buffer + 4);
7989 if (child_fourcc == fourcc) {
7991 child_len = QT_UINT32 (buffer);
7992 if (G_UNLIKELY (child_len < (4 + 4)))
7994 /* FIXME: must verify if atom length < parent atom length */
7995 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8004 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8006 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8010 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
8012 /* FIXME: This can only reliably work if demuxers have a
8013 * separate streaming thread per srcpad. This should be
8014 * done in a demuxer base class, which integrates parts
8017 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8022 query = gst_query_new_allocation (stream->caps, FALSE);
8024 if (!gst_pad_peer_query (stream->pad, query)) {
8025 /* not a problem, just debug a little */
8026 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8029 if (stream->allocator)
8030 gst_object_unref (stream->allocator);
8032 if (gst_query_get_n_allocation_params (query) > 0) {
8033 /* try the allocator */
8034 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8036 stream->use_allocator = TRUE;
8038 stream->allocator = NULL;
8039 gst_allocation_params_init (&stream->params);
8040 stream->use_allocator = FALSE;
8042 gst_query_unref (query);
8047 pad_query (const GValue * item, GValue * value, gpointer user_data)
8049 GstPad *pad = g_value_get_object (item);
8050 GstQuery *query = user_data;
8053 res = gst_pad_peer_query (pad, query);
8056 g_value_set_boolean (value, TRUE);
8060 GST_INFO_OBJECT (pad, "pad peer query failed");
8065 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8066 GstPadDirection direction)
8069 GstIteratorFoldFunction func = pad_query;
8070 GValue res = { 0, };
8072 g_value_init (&res, G_TYPE_BOOLEAN);
8073 g_value_set_boolean (&res, FALSE);
8076 if (direction == GST_PAD_SRC)
8077 it = gst_element_iterate_src_pads (element);
8079 it = gst_element_iterate_sink_pads (element);
8081 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8082 gst_iterator_resync (it);
8084 gst_iterator_free (it);
8086 return g_value_get_boolean (&res);
8090 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8091 QtDemuxStream * stream)
8095 GstElement *element = GST_ELEMENT (qtdemux);
8097 gchar **filtered_sys_ids;
8098 GValue event_list = G_VALUE_INIT;
8101 /* 1. Check if we already have the context. */
8102 if (qtdemux->preferred_protection_system_id != NULL) {
8103 GST_LOG_OBJECT (element,
8104 "already have the protection context, no need to request it again");
8108 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8109 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8110 (const gchar **) qtdemux->protection_system_ids->pdata);
8112 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8113 qtdemux->protection_system_ids->len - 1);
8114 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8115 "decryptors for %u of them, running context request",
8116 qtdemux->protection_system_ids->len, g_strv_length (filtered_sys_ids));
8118 if (stream->protection_scheme_event_queue.length) {
8119 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8120 stream->protection_scheme_event_queue.length);
8121 walk = stream->protection_scheme_event_queue.tail;
8123 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8124 qtdemux->protection_event_queue.length);
8125 walk = qtdemux->protection_event_queue.tail;
8128 g_value_init (&event_list, GST_TYPE_LIST);
8129 for (; walk; walk = g_list_previous (walk)) {
8130 GValue *event_value = g_new0 (GValue, 1);
8131 g_value_init (event_value, GST_TYPE_EVENT);
8132 g_value_set_boxed (event_value, walk->data);
8133 gst_value_list_append_and_take_value (&event_list, event_value);
8136 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8137 * check if downstream already has a context of the specific type
8138 * 2b) Query upstream as above.
8140 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8141 st = gst_query_writable_structure (query);
8142 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8143 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8145 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8146 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8147 gst_query_parse_context (query, &ctxt);
8148 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8149 gst_element_set_context (element, ctxt);
8150 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8151 gst_query_parse_context (query, &ctxt);
8152 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8153 gst_element_set_context (element, ctxt);
8155 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8156 * the required context type and afterwards check if a
8157 * usable context was set now as in 1). The message could
8158 * be handled by the parent bins of the element and the
8163 GST_INFO_OBJECT (element, "posting need context message");
8164 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8165 "drm-preferred-decryption-system-id");
8166 st = (GstStructure *) gst_message_get_structure (msg);
8167 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8168 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8171 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8172 gst_element_post_message (element, msg);
8175 g_strfreev (filtered_sys_ids);
8176 g_value_unset (&event_list);
8177 gst_query_unref (query);
8181 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8182 QtDemuxStream * stream)
8185 const gchar *selected_system = NULL;
8187 g_return_val_if_fail (qtdemux != NULL, FALSE);
8188 g_return_val_if_fail (stream != NULL, FALSE);
8189 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8192 if (stream->protection_scheme_type != FOURCC_cenc) {
8193 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
8196 if (qtdemux->protection_system_ids == NULL) {
8197 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8198 "cenc protection system information has been found");
8202 gst_qtdemux_request_protection_context (qtdemux, stream);
8203 if (qtdemux->preferred_protection_system_id != NULL) {
8204 const gchar *preferred_system_array[] =
8205 { qtdemux->preferred_protection_system_id, NULL };
8207 selected_system = gst_protection_select_system (preferred_system_array);
8209 if (selected_system) {
8210 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8211 qtdemux->preferred_protection_system_id);
8213 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8214 "because there is no available decryptor",
8215 qtdemux->preferred_protection_system_id);
8219 if (!selected_system) {
8220 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8221 selected_system = gst_protection_select_system ((const gchar **)
8222 qtdemux->protection_system_ids->pdata);
8223 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8224 qtdemux->protection_system_ids->len - 1);
8227 if (!selected_system) {
8228 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8229 "suitable decryptor element has been found");
8233 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8236 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8237 if (!gst_structure_has_name (s, "application/x-cenc")) {
8238 gst_structure_set (s,
8239 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8240 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8242 gst_structure_set_name (s, "application/x-cenc");
8248 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8250 if (stream->subtype == FOURCC_vide) {
8251 /* fps is calculated base on the duration of the average framerate since
8252 * qt does not have a fixed framerate. */
8253 gboolean fps_available = TRUE;
8254 guint32 first_duration = 0;
8256 if (stream->n_samples > 0)
8257 first_duration = stream->samples[0].duration;
8259 if ((stream->n_samples == 1 && first_duration == 0)
8260 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8262 CUR_STREAM (stream)->fps_n = 0;
8263 CUR_STREAM (stream)->fps_d = 1;
8265 if (stream->duration == 0 || stream->n_samples < 2) {
8266 CUR_STREAM (stream)->fps_n = stream->timescale;
8267 CUR_STREAM (stream)->fps_d = 1;
8268 fps_available = FALSE;
8270 GstClockTime avg_duration;
8274 /* duration and n_samples can be updated for fragmented format
8275 * so, framerate of fragmented format is calculated using data in a moof */
8276 if (qtdemux->fragmented && stream->n_samples_moof > 0
8277 && stream->duration_moof > 0) {
8278 n_samples = stream->n_samples_moof;
8279 duration = stream->duration_moof;
8281 n_samples = stream->n_samples;
8282 duration = stream->duration;
8285 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8286 /* stream->duration is guint64, timescale, n_samples are guint32 */
8288 gst_util_uint64_scale_round (duration -
8289 first_duration, GST_SECOND,
8290 (guint64) (stream->timescale) * (n_samples - 1));
8292 GST_LOG_OBJECT (qtdemux,
8293 "Calculating avg sample duration based on stream (or moof) duration %"
8295 " minus first sample %u, leaving %d samples gives %"
8296 GST_TIME_FORMAT, duration, first_duration,
8297 n_samples - 1, GST_TIME_ARGS (avg_duration));
8299 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8300 &CUR_STREAM (stream)->fps_d);
8302 GST_DEBUG_OBJECT (qtdemux,
8303 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8304 stream->timescale, CUR_STREAM (stream)->fps_n,
8305 CUR_STREAM (stream)->fps_d);
8309 if (CUR_STREAM (stream)->caps) {
8310 CUR_STREAM (stream)->caps =
8311 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8313 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8314 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8315 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8317 /* set framerate if calculated framerate is reliable */
8318 if (fps_available) {
8319 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8320 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8321 CUR_STREAM (stream)->fps_d, NULL);
8324 /* calculate pixel-aspect-ratio using display width and height */
8325 GST_DEBUG_OBJECT (qtdemux,
8326 "video size %dx%d, target display size %dx%d",
8327 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8328 stream->display_width, stream->display_height);
8329 /* qt file might have pasp atom */
8330 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8331 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8332 CUR_STREAM (stream)->par_h);
8333 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8334 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8335 CUR_STREAM (stream)->par_h, NULL);
8336 } else if (stream->display_width > 0 && stream->display_height > 0
8337 && CUR_STREAM (stream)->width > 0
8338 && CUR_STREAM (stream)->height > 0) {
8341 /* calculate the pixel aspect ratio using the display and pixel w/h */
8342 n = stream->display_width * CUR_STREAM (stream)->height;
8343 d = stream->display_height * CUR_STREAM (stream)->width;
8346 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8347 CUR_STREAM (stream)->par_w = n;
8348 CUR_STREAM (stream)->par_h = d;
8349 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8350 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8351 CUR_STREAM (stream)->par_h, NULL);
8354 if (CUR_STREAM (stream)->interlace_mode > 0) {
8355 if (CUR_STREAM (stream)->interlace_mode == 1) {
8356 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8357 G_TYPE_STRING, "progressive", NULL);
8358 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8359 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8360 G_TYPE_STRING, "interleaved", NULL);
8361 if (CUR_STREAM (stream)->field_order == 9) {
8362 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8363 G_TYPE_STRING, "top-field-first", NULL);
8364 } else if (CUR_STREAM (stream)->field_order == 14) {
8365 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8366 G_TYPE_STRING, "bottom-field-first", NULL);
8371 /* Create incomplete colorimetry here if needed */
8372 if (CUR_STREAM (stream)->colorimetry.range ||
8373 CUR_STREAM (stream)->colorimetry.matrix ||
8374 CUR_STREAM (stream)->colorimetry.transfer
8375 || CUR_STREAM (stream)->colorimetry.primaries) {
8376 gchar *colorimetry =
8377 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8378 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8379 G_TYPE_STRING, colorimetry, NULL);
8380 g_free (colorimetry);
8383 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8384 guint par_w = 1, par_h = 1;
8386 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8387 par_w = CUR_STREAM (stream)->par_w;
8388 par_h = CUR_STREAM (stream)->par_h;
8391 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8392 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8394 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8397 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8398 "multiview-mode", G_TYPE_STRING,
8399 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8400 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8401 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8406 else if (stream->subtype == FOURCC_soun) {
8407 if (CUR_STREAM (stream)->caps) {
8408 CUR_STREAM (stream)->caps =
8409 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8410 if (CUR_STREAM (stream)->rate > 0)
8411 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8412 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8413 if (CUR_STREAM (stream)->n_channels > 0)
8414 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8415 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8416 if (CUR_STREAM (stream)->n_channels > 2) {
8417 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8418 * correctly; this is just the minimum we can do - assume
8419 * we don't actually have any channel positions. */
8420 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8421 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8427 GstCaps *prev_caps = NULL;
8429 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8430 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8431 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8432 gst_pad_set_active (stream->pad, TRUE);
8434 gst_pad_use_fixed_caps (stream->pad);
8436 if (stream->protected) {
8437 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8438 GST_ERROR_OBJECT (qtdemux,
8439 "Failed to configure protected stream caps.");
8444 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8445 CUR_STREAM (stream)->caps);
8446 if (stream->new_stream) {
8448 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8451 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8454 gst_event_parse_stream_flags (event, &stream_flags);
8455 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8456 qtdemux->have_group_id = TRUE;
8458 qtdemux->have_group_id = FALSE;
8459 gst_event_unref (event);
8460 } else if (!qtdemux->have_group_id) {
8461 qtdemux->have_group_id = TRUE;
8462 qtdemux->group_id = gst_util_group_id_next ();
8465 stream->new_stream = FALSE;
8466 event = gst_event_new_stream_start (stream->stream_id);
8467 if (qtdemux->have_group_id)
8468 gst_event_set_group_id (event, qtdemux->group_id);
8469 if (stream->disabled)
8470 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8471 if (CUR_STREAM (stream)->sparse) {
8472 stream_flags |= GST_STREAM_FLAG_SPARSE;
8474 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8476 gst_event_set_stream_flags (event, stream_flags);
8477 gst_pad_push_event (stream->pad, event);
8480 prev_caps = gst_pad_get_current_caps (stream->pad);
8482 if (CUR_STREAM (stream)->caps) {
8484 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8485 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8486 CUR_STREAM (stream)->caps);
8487 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8489 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8492 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8496 gst_caps_unref (prev_caps);
8497 stream->new_caps = FALSE;
8503 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8504 QtDemuxStream * stream)
8506 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8509 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8510 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8511 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8512 stream->stsd_entries_length)) {
8513 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8514 (_("This file is invalid and cannot be played.")),
8515 ("New sample description id is out of bounds (%d >= %d)",
8516 stream->stsd_sample_description_id, stream->stsd_entries_length));
8518 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8519 stream->new_caps = TRUE;
8524 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8525 QtDemuxStream * stream, GstTagList * list)
8527 gboolean ret = TRUE;
8528 /* consistent default for push based mode */
8529 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8531 if (stream->subtype == FOURCC_vide) {
8532 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8535 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8538 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8539 gst_object_unref (stream->pad);
8545 qtdemux->n_video_streams++;
8546 } else if (stream->subtype == FOURCC_soun) {
8547 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8550 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8552 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8553 gst_object_unref (stream->pad);
8558 qtdemux->n_audio_streams++;
8559 } else if (stream->subtype == FOURCC_strm) {
8560 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8561 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8562 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8563 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8566 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8568 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8569 gst_object_unref (stream->pad);
8574 qtdemux->n_sub_streams++;
8575 } else if (CUR_STREAM (stream)->caps) {
8576 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8579 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8581 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8582 gst_object_unref (stream->pad);
8587 qtdemux->n_video_streams++;
8589 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8596 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8597 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8598 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8599 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8601 if (stream->stream_tags)
8602 gst_tag_list_unref (stream->stream_tags);
8603 stream->stream_tags = list;
8605 /* global tags go on each pad anyway */
8606 stream->send_global_tags = TRUE;
8607 /* send upstream GST_EVENT_PROTECTION events that were received before
8608 this source pad was created */
8609 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8610 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8614 gst_tag_list_unref (list);
8618 /* find next atom with @fourcc starting at @offset */
8619 static GstFlowReturn
8620 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8621 guint64 * length, guint32 fourcc)
8627 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8628 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8634 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8635 if (G_UNLIKELY (ret != GST_FLOW_OK))
8637 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8640 gst_buffer_unref (buf);
8643 gst_buffer_map (buf, &map, GST_MAP_READ);
8644 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8645 gst_buffer_unmap (buf, &map);
8646 gst_buffer_unref (buf);
8648 if (G_UNLIKELY (*length == 0)) {
8649 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8650 ret = GST_FLOW_ERROR;
8654 if (lfourcc == fourcc) {
8655 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8659 GST_LOG_OBJECT (qtdemux,
8660 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8661 GST_FOURCC_ARGS (fourcc), *offset);
8670 /* might simply have had last one */
8671 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8676 /* should only do something in pull mode */
8677 /* call with OBJECT lock */
8678 static GstFlowReturn
8679 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8681 guint64 length, offset;
8682 GstBuffer *buf = NULL;
8683 GstFlowReturn ret = GST_FLOW_OK;
8684 GstFlowReturn res = GST_FLOW_OK;
8687 offset = qtdemux->moof_offset;
8688 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8691 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8692 return GST_FLOW_EOS;
8695 /* best not do pull etc with lock held */
8696 GST_OBJECT_UNLOCK (qtdemux);
8698 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8699 if (ret != GST_FLOW_OK)
8702 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8703 if (G_UNLIKELY (ret != GST_FLOW_OK))
8705 gst_buffer_map (buf, &map, GST_MAP_READ);
8706 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8707 gst_buffer_unmap (buf, &map);
8708 gst_buffer_unref (buf);
8713 gst_buffer_unmap (buf, &map);
8714 gst_buffer_unref (buf);
8718 /* look for next moof */
8719 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8720 if (G_UNLIKELY (ret != GST_FLOW_OK))
8724 GST_OBJECT_LOCK (qtdemux);
8726 qtdemux->moof_offset = offset;
8732 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8734 res = GST_FLOW_ERROR;
8739 /* maybe upstream temporarily flushing */
8740 if (ret != GST_FLOW_FLUSHING) {
8741 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8744 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8745 /* resume at current position next time */
8752 /* initialise bytereaders for stbl sub-atoms */
8754 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8756 stream->stbl_index = -1; /* no samples have yet been parsed */
8757 stream->sample_index = -1;
8759 /* time-to-sample atom */
8760 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8763 /* copy atom data into a new buffer for later use */
8764 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8766 /* skip version + flags */
8767 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8768 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8770 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8772 /* make sure there's enough data */
8773 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8774 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8775 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8776 stream->n_sample_times);
8777 if (!stream->n_sample_times)
8781 /* sync sample atom */
8782 stream->stps_present = FALSE;
8783 if ((stream->stss_present =
8784 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8785 &stream->stss) ? TRUE : FALSE) == TRUE) {
8786 /* copy atom data into a new buffer for later use */
8787 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8789 /* skip version + flags */
8790 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8791 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8794 if (stream->n_sample_syncs) {
8795 /* make sure there's enough data */
8796 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8800 /* partial sync sample atom */
8801 if ((stream->stps_present =
8802 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8803 &stream->stps) ? TRUE : FALSE) == TRUE) {
8804 /* copy atom data into a new buffer for later use */
8805 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8807 /* skip version + flags */
8808 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8809 !gst_byte_reader_get_uint32_be (&stream->stps,
8810 &stream->n_sample_partial_syncs))
8813 /* if there are no entries, the stss table contains the real
8815 if (stream->n_sample_partial_syncs) {
8816 /* make sure there's enough data */
8817 if (!qt_atom_parser_has_chunks (&stream->stps,
8818 stream->n_sample_partial_syncs, 4))
8825 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8828 /* copy atom data into a new buffer for later use */
8829 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8831 /* skip version + flags */
8832 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8833 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8836 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8839 if (!stream->n_samples)
8842 /* sample-to-chunk atom */
8843 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8846 /* copy atom data into a new buffer for later use */
8847 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8849 /* skip version + flags */
8850 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8851 !gst_byte_reader_get_uint32_be (&stream->stsc,
8852 &stream->n_samples_per_chunk))
8855 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8856 stream->n_samples_per_chunk);
8858 /* make sure there's enough data */
8859 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8865 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8866 stream->co_size = sizeof (guint32);
8867 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8869 stream->co_size = sizeof (guint64);
8873 /* copy atom data into a new buffer for later use */
8874 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8876 /* skip version + flags */
8877 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8880 /* chunks_are_samples == TRUE means treat chunks as samples */
8881 stream->chunks_are_samples = stream->sample_size
8882 && !CUR_STREAM (stream)->sampled;
8883 if (stream->chunks_are_samples) {
8884 /* treat chunks as samples */
8885 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8888 /* skip number of entries */
8889 if (!gst_byte_reader_skip (&stream->stco, 4))
8892 /* make sure there are enough data in the stsz atom */
8893 if (!stream->sample_size) {
8894 /* different sizes for each sample */
8895 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8900 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8901 stream->n_samples, (guint) sizeof (QtDemuxSample),
8902 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8904 if (stream->n_samples >=
8905 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8906 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8907 "be larger than %uMB (broken file?)", stream->n_samples,
8908 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8912 g_assert (stream->samples == NULL);
8913 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8914 if (!stream->samples) {
8915 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8920 /* composition time-to-sample */
8921 if ((stream->ctts_present =
8922 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8923 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8924 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8926 /* copy atom data into a new buffer for later use */
8927 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8929 /* skip version + flags */
8930 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8931 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8932 &stream->n_composition_times))
8935 /* make sure there's enough data */
8936 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8940 /* This is optional, if missing we iterate the ctts */
8941 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8942 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8943 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8944 g_free ((gpointer) cslg.data);
8948 gint32 cslg_least = 0;
8949 guint num_entries, pos;
8952 pos = gst_byte_reader_get_pos (&stream->ctts);
8953 num_entries = stream->n_composition_times;
8955 stream->cslg_shift = 0;
8957 for (i = 0; i < num_entries; i++) {
8960 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8961 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8963 if (offset < cslg_least)
8964 cslg_least = offset;
8968 stream->cslg_shift = ABS (cslg_least);
8970 stream->cslg_shift = 0;
8972 /* reset the reader so we can generate sample table */
8973 gst_byte_reader_set_pos (&stream->ctts, pos);
8976 /* Ensure the cslg_shift value is consistent so we can use it
8977 * unconditionnally to produce TS and Segment */
8978 stream->cslg_shift = 0;
8985 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8986 (_("This file is corrupt and cannot be played.")), (NULL));
8991 gst_qtdemux_stbl_free (stream);
8992 if (!qtdemux->fragmented) {
8993 /* not quite good */
8994 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8997 /* may pick up samples elsewhere */
9003 /* collect samples from the next sample to be parsed up to sample @n for @stream
9004 * by reading the info from @stbl
9006 * This code can be executed from both the streaming thread and the seeking
9007 * thread so it takes the object lock to protect itself
9010 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9013 QtDemuxSample *samples, *first, *cur, *last;
9014 guint32 n_samples_per_chunk;
9017 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9018 GST_FOURCC_FORMAT ", pad %s",
9019 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9020 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9022 n_samples = stream->n_samples;
9025 goto out_of_samples;
9027 GST_OBJECT_LOCK (qtdemux);
9028 if (n <= stream->stbl_index)
9029 goto already_parsed;
9031 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9033 if (!stream->stsz.data) {
9034 /* so we already parsed and passed all the moov samples;
9035 * onto fragmented ones */
9036 g_assert (qtdemux->fragmented);
9040 /* pointer to the sample table */
9041 samples = stream->samples;
9043 /* starts from -1, moves to the next sample index to parse */
9044 stream->stbl_index++;
9046 /* keep track of the first and last sample to fill */
9047 first = &samples[stream->stbl_index];
9050 if (!stream->chunks_are_samples) {
9051 /* set the sample sizes */
9052 if (stream->sample_size == 0) {
9053 /* different sizes for each sample */
9054 for (cur = first; cur <= last; cur++) {
9055 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9056 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9057 (guint) (cur - samples), cur->size);
9060 /* samples have the same size */
9061 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9062 for (cur = first; cur <= last; cur++)
9063 cur->size = stream->sample_size;
9067 n_samples_per_chunk = stream->n_samples_per_chunk;
9070 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9073 if (stream->stsc_chunk_index >= stream->last_chunk
9074 || stream->stsc_chunk_index < stream->first_chunk) {
9075 stream->first_chunk =
9076 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9077 stream->samples_per_chunk =
9078 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9080 stream->stsd_sample_description_id =
9081 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9083 /* chunk numbers are counted from 1 it seems */
9084 if (G_UNLIKELY (stream->first_chunk == 0))
9087 --stream->first_chunk;
9089 /* the last chunk of each entry is calculated by taking the first chunk
9090 * of the next entry; except if there is no next, where we fake it with
9092 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9093 stream->last_chunk = G_MAXUINT32;
9095 stream->last_chunk =
9096 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9097 if (G_UNLIKELY (stream->last_chunk == 0))
9100 --stream->last_chunk;
9103 GST_LOG_OBJECT (qtdemux,
9104 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9105 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9106 stream->samples_per_chunk, stream->stsd_sample_description_id);
9108 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9111 if (stream->last_chunk != G_MAXUINT32) {
9112 if (!qt_atom_parser_peek_sub (&stream->stco,
9113 stream->first_chunk * stream->co_size,
9114 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9119 stream->co_chunk = stream->stco;
9120 if (!gst_byte_reader_skip (&stream->co_chunk,
9121 stream->first_chunk * stream->co_size))
9125 stream->stsc_chunk_index = stream->first_chunk;
9128 last_chunk = stream->last_chunk;
9130 if (stream->chunks_are_samples) {
9131 cur = &samples[stream->stsc_chunk_index];
9133 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9136 stream->stsc_chunk_index = j;
9141 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9144 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9145 "%" G_GUINT64_FORMAT, j, cur->offset);
9147 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9148 CUR_STREAM (stream)->bytes_per_frame > 0) {
9150 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9151 CUR_STREAM (stream)->samples_per_frame *
9152 CUR_STREAM (stream)->bytes_per_frame;
9154 cur->size = stream->samples_per_chunk;
9157 GST_DEBUG_OBJECT (qtdemux,
9158 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9159 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9160 stream->stco_sample_index)), cur->size);
9162 cur->timestamp = stream->stco_sample_index;
9163 cur->duration = stream->samples_per_chunk;
9164 cur->keyframe = TRUE;
9167 stream->stco_sample_index += stream->samples_per_chunk;
9169 stream->stsc_chunk_index = j;
9171 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9172 guint32 samples_per_chunk;
9173 guint64 chunk_offset;
9175 if (!stream->stsc_sample_index
9176 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9177 &stream->chunk_offset))
9180 samples_per_chunk = stream->samples_per_chunk;
9181 chunk_offset = stream->chunk_offset;
9183 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9184 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9185 G_GUINT64_FORMAT " and size %d",
9186 (guint) (cur - samples), chunk_offset, cur->size);
9188 cur->offset = chunk_offset;
9189 chunk_offset += cur->size;
9192 if (G_UNLIKELY (cur > last)) {
9194 stream->stsc_sample_index = k + 1;
9195 stream->chunk_offset = chunk_offset;
9196 stream->stsc_chunk_index = j;
9200 stream->stsc_sample_index = 0;
9202 stream->stsc_chunk_index = j;
9204 stream->stsc_index++;
9207 if (stream->chunks_are_samples)
9211 guint32 n_sample_times;
9213 n_sample_times = stream->n_sample_times;
9216 for (i = stream->stts_index; i < n_sample_times; i++) {
9217 guint32 stts_samples;
9218 gint32 stts_duration;
9221 if (stream->stts_sample_index >= stream->stts_samples
9222 || !stream->stts_sample_index) {
9224 stream->stts_samples =
9225 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9226 stream->stts_duration =
9227 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9229 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9230 i, stream->stts_samples, stream->stts_duration);
9232 stream->stts_sample_index = 0;
9235 stts_samples = stream->stts_samples;
9236 stts_duration = stream->stts_duration;
9237 stts_time = stream->stts_time;
9239 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9240 GST_DEBUG_OBJECT (qtdemux,
9241 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9242 (guint) (cur - samples), j,
9243 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9245 cur->timestamp = stts_time;
9246 cur->duration = stts_duration;
9248 /* avoid 32-bit wrap-around,
9249 * but still mind possible 'negative' duration */
9250 stts_time += (gint64) stts_duration;
9253 if (G_UNLIKELY (cur > last)) {
9255 stream->stts_time = stts_time;
9256 stream->stts_sample_index = j + 1;
9257 if (stream->stts_sample_index >= stream->stts_samples)
9258 stream->stts_index++;
9262 stream->stts_sample_index = 0;
9263 stream->stts_time = stts_time;
9264 stream->stts_index++;
9266 /* fill up empty timestamps with the last timestamp, this can happen when
9267 * the last samples do not decode and so we don't have timestamps for them.
9268 * We however look at the last timestamp to estimate the track length so we
9269 * need something in here. */
9270 for (; cur < last; cur++) {
9271 GST_DEBUG_OBJECT (qtdemux,
9272 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9273 (guint) (cur - samples),
9274 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9275 cur->timestamp = stream->stts_time;
9281 /* sample sync, can be NULL */
9282 if (stream->stss_present == TRUE) {
9283 guint32 n_sample_syncs;
9285 n_sample_syncs = stream->n_sample_syncs;
9287 if (!n_sample_syncs) {
9288 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9289 stream->all_keyframe = TRUE;
9291 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9292 /* note that the first sample is index 1, not 0 */
9295 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9297 if (G_LIKELY (index > 0 && index <= n_samples)) {
9299 samples[index].keyframe = TRUE;
9300 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9301 /* and exit if we have enough samples */
9302 if (G_UNLIKELY (index >= n)) {
9309 stream->stss_index = i;
9312 /* stps marks partial sync frames like open GOP I-Frames */
9313 if (stream->stps_present == TRUE) {
9314 guint32 n_sample_partial_syncs;
9316 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9318 /* if there are no entries, the stss table contains the real
9320 if (n_sample_partial_syncs) {
9321 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9322 /* note that the first sample is index 1, not 0 */
9325 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9327 if (G_LIKELY (index > 0 && index <= n_samples)) {
9329 samples[index].keyframe = TRUE;
9330 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9331 /* and exit if we have enough samples */
9332 if (G_UNLIKELY (index >= n)) {
9339 stream->stps_index = i;
9343 /* no stss, all samples are keyframes */
9344 stream->all_keyframe = TRUE;
9345 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9350 /* composition time to sample */
9351 if (stream->ctts_present == TRUE) {
9352 guint32 n_composition_times;
9354 gint32 ctts_soffset;
9356 /* Fill in the pts_offsets */
9358 n_composition_times = stream->n_composition_times;
9360 for (i = stream->ctts_index; i < n_composition_times; i++) {
9361 if (stream->ctts_sample_index >= stream->ctts_count
9362 || !stream->ctts_sample_index) {
9363 stream->ctts_count =
9364 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9365 stream->ctts_soffset =
9366 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9367 stream->ctts_sample_index = 0;
9370 ctts_count = stream->ctts_count;
9371 ctts_soffset = stream->ctts_soffset;
9373 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9374 cur->pts_offset = ctts_soffset;
9377 if (G_UNLIKELY (cur > last)) {
9379 stream->ctts_sample_index = j + 1;
9383 stream->ctts_sample_index = 0;
9384 stream->ctts_index++;
9388 stream->stbl_index = n;
9389 /* if index has been completely parsed, free data that is no-longer needed */
9390 if (n + 1 == stream->n_samples) {
9391 gst_qtdemux_stbl_free (stream);
9392 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9393 if (qtdemux->pullbased) {
9394 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9395 while (n + 1 == stream->n_samples)
9396 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9400 GST_OBJECT_UNLOCK (qtdemux);
9407 GST_LOG_OBJECT (qtdemux,
9408 "Tried to parse up to sample %u but this sample has already been parsed",
9410 /* if fragmented, there may be more */
9411 if (qtdemux->fragmented && n == stream->stbl_index)
9413 GST_OBJECT_UNLOCK (qtdemux);
9419 GST_LOG_OBJECT (qtdemux,
9420 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9422 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9423 (_("This file is corrupt and cannot be played.")), (NULL));
9428 GST_OBJECT_UNLOCK (qtdemux);
9429 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9430 (_("This file is corrupt and cannot be played.")), (NULL));
9435 /* collect all segment info for @stream.
9438 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9442 /* accept edts if they contain gaps at start and there is only
9443 * one media segment */
9444 gboolean allow_pushbased_edts = TRUE;
9445 gint media_segments_count = 0;
9447 /* parse and prepare segment info from the edit list */
9448 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9449 stream->n_segments = 0;
9450 stream->segments = NULL;
9451 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9454 gint segment_number, entry_size;
9457 const guint8 *buffer;
9461 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9462 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9465 buffer = elst->data;
9467 size = QT_UINT32 (buffer);
9468 /* version, flags, n_segments */
9470 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9473 version = QT_UINT8 (buffer + 8);
9474 entry_size = (version == 1) ? 20 : 12;
9476 n_segments = QT_UINT32 (buffer + 12);
9478 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9479 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9483 /* we might allocate a bit too much, at least allocate 1 segment */
9484 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9486 /* segments always start from 0 */
9490 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9493 gboolean empty_edit = FALSE;
9494 QtDemuxSegment *segment;
9496 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9499 media_time = QT_UINT64 (buffer + 8);
9500 duration = QT_UINT64 (buffer);
9501 if (media_time == G_MAXUINT64)
9504 media_time = QT_UINT32 (buffer + 4);
9505 duration = QT_UINT32 (buffer);
9506 if (media_time == G_MAXUINT32)
9511 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9513 segment = &stream->segments[segment_number];
9515 /* time and duration expressed in global timescale */
9516 segment->time = stime;
9517 if (duration != 0 || empty_edit) {
9518 /* edge case: empty edits with duration=zero are treated here.
9519 * (files should not have these anyway). */
9521 /* add non scaled values so we don't cause roundoff errors */
9523 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9524 segment->duration = stime - segment->time;
9526 /* zero duration does not imply media_start == media_stop
9527 * but, only specify media_start. The edit ends with the track. */
9528 stime = segment->duration = GST_CLOCK_TIME_NONE;
9529 /* Don't allow more edits after this one. */
9530 n_segments = segment_number + 1;
9532 segment->stop_time = stime;
9534 segment->trak_media_start = media_time;
9535 /* media_time expressed in stream timescale */
9537 segment->media_start = media_start;
9538 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9539 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9540 media_segments_count++;
9542 segment->media_start = GST_CLOCK_TIME_NONE;
9543 segment->media_stop = GST_CLOCK_TIME_NONE;
9545 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9547 if (rate_int <= 1) {
9548 /* 0 is not allowed, some programs write 1 instead of the floating point
9550 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9554 segment->rate = rate_int / 65536.0;
9557 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9558 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9559 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9560 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9561 segment_number, GST_TIME_ARGS (segment->time),
9562 GST_TIME_ARGS (segment->duration),
9563 GST_TIME_ARGS (segment->media_start), media_time,
9564 GST_TIME_ARGS (segment->media_stop),
9565 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9567 if (segment->stop_time > qtdemux->segment.stop) {
9568 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9569 " extends to %" GST_TIME_FORMAT
9570 " past the end of the file duration %" GST_TIME_FORMAT
9571 " it will be truncated", segment_number,
9572 GST_TIME_ARGS (segment->stop_time),
9573 GST_TIME_ARGS (qtdemux->segment.stop));
9574 qtdemux->segment.stop = segment->stop_time;
9577 buffer += entry_size;
9579 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9580 stream->n_segments = n_segments;
9581 if (media_segments_count != 1)
9582 allow_pushbased_edts = FALSE;
9586 /* push based does not handle segments, so act accordingly here,
9587 * and warn if applicable */
9588 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9589 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9590 /* remove and use default one below, we stream like it anyway */
9591 g_free (stream->segments);
9592 stream->segments = NULL;
9593 stream->n_segments = 0;
9596 /* no segments, create one to play the complete trak */
9597 if (stream->n_segments == 0) {
9598 GstClockTime stream_duration =
9599 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9601 if (stream->segments == NULL)
9602 stream->segments = g_new (QtDemuxSegment, 1);
9604 /* represent unknown our way */
9605 if (stream_duration == 0)
9606 stream_duration = GST_CLOCK_TIME_NONE;
9608 stream->segments[0].time = 0;
9609 stream->segments[0].stop_time = stream_duration;
9610 stream->segments[0].duration = stream_duration;
9611 stream->segments[0].media_start = 0;
9612 stream->segments[0].media_stop = stream_duration;
9613 stream->segments[0].rate = 1.0;
9614 stream->segments[0].trak_media_start = 0;
9616 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9617 GST_TIME_ARGS (stream_duration));
9618 stream->n_segments = 1;
9619 stream->dummy_segment = TRUE;
9621 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9627 * Parses the stsd atom of a svq3 trak looking for
9628 * the SMI and gama atoms.
9631 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9632 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9634 const guint8 *_gamma = NULL;
9635 GstBuffer *_seqh = NULL;
9636 const guint8 *stsd_data = stsd_entry_data;
9637 guint32 length = QT_UINT32 (stsd_data);
9641 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9647 version = QT_UINT16 (stsd_data);
9652 while (length > 8) {
9653 guint32 fourcc, size;
9655 size = QT_UINT32 (stsd_data);
9656 fourcc = QT_FOURCC (stsd_data + 4);
9657 data = stsd_data + 8;
9660 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9661 "svq3 atom parsing");
9670 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9671 " for gama atom, expected 12", size);
9676 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9678 if (_seqh != NULL) {
9679 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9680 " found, ignoring");
9682 seqh_size = QT_UINT32 (data + 4);
9683 if (seqh_size > 0) {
9684 _seqh = gst_buffer_new_and_alloc (seqh_size);
9685 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9692 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9693 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9697 if (size <= length) {
9703 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9706 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9707 G_GUINT16_FORMAT, version);
9718 gst_buffer_unref (_seqh);
9723 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9730 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9731 * atom that might contain a 'data' atom with the rtsp uri.
9732 * This case was reported in bug #597497, some info about
9733 * the hndl atom can be found in TN1195
9735 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9736 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9739 guint32 dref_num_entries = 0;
9740 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9741 gst_byte_reader_skip (&dref, 4) &&
9742 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9745 /* search dref entries for hndl atom */
9746 for (i = 0; i < dref_num_entries; i++) {
9747 guint32 size = 0, type;
9748 guint8 string_len = 0;
9749 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9750 qt_atom_parser_get_fourcc (&dref, &type)) {
9751 if (type == FOURCC_hndl) {
9752 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9754 /* skip data reference handle bytes and the
9755 * following pascal string and some extra 4
9756 * bytes I have no idea what are */
9757 if (!gst_byte_reader_skip (&dref, 4) ||
9758 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9759 !gst_byte_reader_skip (&dref, string_len + 4)) {
9760 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9764 /* iterate over the atoms to find the data atom */
9765 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9769 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9770 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9771 if (atom_type == FOURCC_data) {
9772 const guint8 *uri_aux = NULL;
9774 /* found the data atom that might contain the rtsp uri */
9775 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9776 "hndl atom, interpreting it as an URI");
9777 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9779 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9780 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9782 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9783 "didn't contain a rtsp address");
9785 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9790 /* skipping to the next entry */
9791 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9794 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9801 /* skip to the next entry */
9802 if (!gst_byte_reader_skip (&dref, size - 8))
9805 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9808 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9814 #define AMR_NB_ALL_MODES 0x81ff
9815 #define AMR_WB_ALL_MODES 0x83ff
9817 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9819 /* The 'damr' atom is of the form:
9821 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9822 * 32 b 8 b 16 b 8 b 8 b
9824 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9825 * represents the highest mode used in the stream (and thus the maximum
9826 * bitrate), with a couple of special cases as seen below.
9829 /* Map of frame type ID -> bitrate */
9830 static const guint nb_bitrates[] = {
9831 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9833 static const guint wb_bitrates[] = {
9834 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9840 gst_buffer_map (buf, &map, GST_MAP_READ);
9842 if (map.size != 0x11) {
9843 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9847 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9848 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9849 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9853 mode_set = QT_UINT16 (map.data + 13);
9855 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9856 max_mode = 7 + (wb ? 1 : 0);
9858 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9859 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9861 if (max_mode == -1) {
9862 GST_DEBUG ("No mode indication was found (mode set) = %x",
9867 gst_buffer_unmap (buf, &map);
9868 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9871 gst_buffer_unmap (buf, &map);
9876 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9877 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9880 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9886 if (gst_byte_reader_get_remaining (reader) < 36)
9889 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9890 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9891 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9892 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9893 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9894 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9895 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9896 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9897 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9899 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9900 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9901 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9903 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9904 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9906 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9907 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9914 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9915 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9922 * This macro will only compare value abdegh, it expects cfi to have already
9925 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9926 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9928 /* only handle the cases where the last column has standard values */
9929 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9930 const gchar *rotation_tag = NULL;
9932 /* no rotation needed */
9933 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9935 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9936 rotation_tag = "rotate-90";
9937 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9938 rotation_tag = "rotate-180";
9939 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9940 rotation_tag = "rotate-270";
9942 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9945 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9947 if (rotation_tag != NULL) {
9948 if (*taglist == NULL)
9949 *taglist = gst_tag_list_new_empty ();
9950 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9951 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9954 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9958 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9959 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9960 * Common Encryption (cenc), the function will also parse the tenc box (defined
9961 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9962 * (typically an enc[v|a|t|s] sample entry); the function will set
9963 * @original_fmt to the fourcc of the original unencrypted stream format.
9964 * Returns TRUE if successful; FALSE otherwise. */
9966 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9967 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9974 g_return_val_if_fail (qtdemux != NULL, FALSE);
9975 g_return_val_if_fail (stream != NULL, FALSE);
9976 g_return_val_if_fail (container != NULL, FALSE);
9977 g_return_val_if_fail (original_fmt != NULL, FALSE);
9979 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9980 if (G_UNLIKELY (!sinf)) {
9981 if (stream->protection_scheme_type == FOURCC_cenc) {
9982 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9983 "mandatory for Common Encryption");
9989 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9990 if (G_UNLIKELY (!frma)) {
9991 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9995 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9996 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9997 GST_FOURCC_ARGS (*original_fmt));
9999 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10001 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10004 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10005 stream->protection_scheme_version =
10006 QT_UINT32 ((const guint8 *) schm->data + 16);
10008 GST_DEBUG_OBJECT (qtdemux,
10009 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10010 "protection_scheme_version: %#010x",
10011 GST_FOURCC_ARGS (stream->protection_scheme_type),
10012 stream->protection_scheme_version);
10014 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10016 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10019 if (stream->protection_scheme_type == FOURCC_cenc) {
10020 QtDemuxCencSampleSetInfo *info;
10022 const guint8 *tenc_data;
10023 guint32 isEncrypted;
10025 const guint8 *default_kid;
10026 GstBuffer *kid_buf;
10028 if (G_UNLIKELY (!stream->protection_scheme_info))
10029 stream->protection_scheme_info =
10030 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10032 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10034 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10036 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10037 "which is mandatory for Common Encryption");
10040 tenc_data = (const guint8 *) tenc->data + 12;
10041 isEncrypted = QT_UINT24 (tenc_data);
10042 iv_size = QT_UINT8 (tenc_data + 3);
10043 default_kid = (tenc_data + 4);
10044 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
10045 gst_buffer_fill (kid_buf, 0, default_kid, 16);
10046 if (info->default_properties)
10047 gst_structure_free (info->default_properties);
10048 info->default_properties =
10049 gst_structure_new ("application/x-cenc",
10050 "iv_size", G_TYPE_UINT, iv_size,
10051 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
10052 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
10053 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
10054 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
10055 gst_buffer_unref (kid_buf);
10061 qtdemux_track_id_compare_func (QtDemuxStream * stream1, QtDemuxStream * stream2)
10063 return (gint) stream1->track_id - (gint) stream2->track_id;
10066 /* parse the traks.
10067 * With each track we associate a new QtDemuxStream that contains all the info
10069 * traks that do not decode to something (like strm traks) will not have a pad.
10072 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10074 GstByteReader tkhd;
10089 QtDemuxStream *stream = NULL;
10090 const guint8 *stsd_data;
10091 const guint8 *stsd_entry_data;
10092 guint remaining_stsd_len;
10093 guint stsd_entry_count;
10095 guint16 lang_code; /* quicktime lang code or packed iso code */
10097 guint32 tkhd_flags = 0;
10098 guint8 tkhd_version = 0;
10099 guint32 w = 0, h = 0;
10100 guint value_size, stsd_len, len;
10104 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10106 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10107 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10108 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10111 /* pick between 64 or 32 bits */
10112 value_size = tkhd_version == 1 ? 8 : 4;
10113 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10114 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10117 /* Check if current moov has duplicated track_id */
10118 if (qtdemux_find_stream (qtdemux, track_id))
10119 goto existing_stream;
10121 stream = _create_stream (qtdemux, track_id);
10122 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10124 /* need defaults for fragments */
10125 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10127 if ((tkhd_flags & 1) == 0)
10128 stream->disabled = TRUE;
10130 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10131 tkhd_version, tkhd_flags, stream->track_id);
10133 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10136 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10137 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10138 if (qtdemux->major_brand != FOURCC_mjp2 ||
10139 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10143 len = QT_UINT32 ((guint8 *) mdhd->data);
10144 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10145 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10146 if (version == 0x01000000) {
10149 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10150 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10151 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10155 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10156 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10157 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10160 if (lang_code < 0x400) {
10161 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10162 } else if (lang_code == 0x7fff) {
10163 stream->lang_id[0] = 0; /* unspecified */
10165 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10166 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10167 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10168 stream->lang_id[3] = 0;
10171 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10172 stream->timescale);
10173 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10175 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10176 lang_code, stream->lang_id);
10178 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10181 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10182 /* chapters track reference */
10183 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10185 gsize length = GST_READ_UINT32_BE (chap->data);
10186 if (qtdemux->chapters_track_id)
10187 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10189 if (length >= 12) {
10190 qtdemux->chapters_track_id =
10191 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10196 /* fragmented files may have bogus duration in moov */
10197 if (!qtdemux->fragmented &&
10198 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10199 guint64 tdur1, tdur2;
10201 /* don't overflow */
10202 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10203 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10206 * some of those trailers, nowadays, have prologue images that are
10207 * themselves video tracks as well. I haven't really found a way to
10208 * identify those yet, except for just looking at their duration. */
10209 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10210 GST_WARNING_OBJECT (qtdemux,
10211 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10212 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10213 "found, assuming preview image or something; skipping track",
10214 stream->duration, stream->timescale, qtdemux->duration,
10215 qtdemux->timescale);
10216 gst_qtdemux_stream_free (stream);
10221 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10224 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10225 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10227 len = QT_UINT32 ((guint8 *) hdlr->data);
10229 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10230 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10231 GST_FOURCC_ARGS (stream->subtype));
10233 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10236 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10239 /*parse svmi header if existing */
10240 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10242 len = QT_UINT32 ((guint8 *) svmi->data);
10243 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10245 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10246 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10247 guint8 frame_type, frame_layout;
10249 /* MPEG-A stereo video */
10250 if (qtdemux->major_brand == FOURCC_ss02)
10251 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10253 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10254 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10255 switch (frame_type) {
10257 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10260 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10263 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10266 /* mode 3 is primary/secondary view sequence, ie
10267 * left/right views in separate tracks. See section 7.2
10268 * of ISO/IEC 23000-11:2009 */
10269 GST_FIXME_OBJECT (qtdemux,
10270 "Implement stereo video in separate streams");
10273 if ((frame_layout & 0x1) == 0)
10274 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10276 GST_LOG_OBJECT (qtdemux,
10277 "StereoVideo: composition type: %u, is_left_first: %u",
10278 frame_type, frame_layout);
10279 stream->multiview_mode = mode;
10280 stream->multiview_flags = flags;
10284 /* parse rest of tkhd */
10285 if (stream->subtype == FOURCC_vide) {
10288 /* version 1 uses some 64-bit ints */
10289 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10292 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10295 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10296 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10299 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10300 &stream->stream_tags);
10304 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10306 stsd_data = (const guint8 *) stsd->data;
10308 /* stsd should at least have one entry */
10309 stsd_len = QT_UINT32 (stsd_data);
10310 if (stsd_len < 24) {
10311 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10312 if (stream->subtype == FOURCC_vivo) {
10313 gst_qtdemux_stream_free (stream);
10320 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10321 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10322 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10323 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10325 stsd_entry_data = stsd_data + 16;
10326 remaining_stsd_len = stsd_len - 16;
10327 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10329 gchar *codec = NULL;
10330 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10332 /* and that entry should fit within stsd */
10333 len = QT_UINT32 (stsd_entry_data);
10334 if (len > remaining_stsd_len)
10337 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10338 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10339 GST_FOURCC_ARGS (entry->fourcc));
10340 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10342 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10343 goto error_encrypted;
10345 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10346 /* FIXME this looks wrong, there might be multiple children
10347 * with the same type */
10348 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10349 stream->protected = TRUE;
10350 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10351 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10354 if (stream->subtype == FOURCC_vide) {
10359 gint depth, palette_size, palette_count;
10360 guint32 *palette_data = NULL;
10362 entry->sampled = TRUE;
10364 stream->display_width = w >> 16;
10365 stream->display_height = h >> 16;
10368 if (len < 86) /* TODO verify */
10371 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10372 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10373 entry->fps_n = 0; /* this is filled in later */
10374 entry->fps_d = 0; /* this is filled in later */
10375 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10376 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10378 /* if color_table_id is 0, ctab atom must follow; however some files
10379 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10380 * if color table is not present we'll correct the value */
10381 if (entry->color_table_id == 0 &&
10383 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10384 entry->color_table_id = -1;
10387 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10388 entry->width, entry->height, entry->bits_per_sample,
10389 entry->color_table_id);
10391 depth = entry->bits_per_sample;
10393 /* more than 32 bits means grayscale */
10394 gray = (depth > 32);
10395 /* low 32 bits specify the depth */
10398 /* different number of palette entries is determined by depth. */
10400 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10401 palette_count = (1 << depth);
10402 palette_size = palette_count * 4;
10404 if (entry->color_table_id) {
10405 switch (palette_count) {
10409 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10412 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10417 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10419 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10424 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10426 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10429 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10430 (_("The video in this file might not play correctly.")),
10431 ("unsupported palette depth %d", depth));
10435 gint i, j, start, end;
10441 start = QT_UINT32 (stsd_entry_data + offset + 70);
10442 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10443 end = QT_UINT16 (stsd_entry_data + offset + 76);
10445 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10446 start, end, palette_count);
10453 if (len < 94 + (end - start) * 8)
10456 /* palette is always the same size */
10457 palette_data = g_malloc0 (256 * 4);
10458 palette_size = 256 * 4;
10460 for (j = 0, i = start; i <= end; j++, i++) {
10461 guint32 a, r, g, b;
10463 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10464 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10465 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10466 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10468 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10469 (g & 0xff00) | (b >> 8);
10474 gst_caps_unref (entry->caps);
10477 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10479 if (G_UNLIKELY (!entry->caps)) {
10480 g_free (palette_data);
10481 goto unknown_stream;
10485 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10486 GST_TAG_VIDEO_CODEC, codec, NULL);
10491 if (palette_data) {
10494 if (entry->rgb8_palette)
10495 gst_memory_unref (entry->rgb8_palette);
10496 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10497 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10499 s = gst_caps_get_structure (entry->caps, 0);
10501 /* non-raw video has a palette_data property. raw video has the palette as
10502 * an extra plane that we append to the output buffers before we push
10504 if (!gst_structure_has_name (s, "video/x-raw")) {
10505 GstBuffer *palette;
10507 palette = gst_buffer_new ();
10508 gst_buffer_append_memory (palette, entry->rgb8_palette);
10509 entry->rgb8_palette = NULL;
10511 gst_caps_set_simple (entry->caps, "palette_data",
10512 GST_TYPE_BUFFER, palette, NULL);
10513 gst_buffer_unref (palette);
10515 } else if (palette_count != 0) {
10516 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10517 (NULL), ("Unsupported palette depth %d", depth));
10520 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10521 QT_UINT16 (stsd_entry_data + offset + 32));
10527 /* pick 'the' stsd child */
10528 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10529 if (!stream->protected) {
10530 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10534 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10540 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10541 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10542 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10543 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10547 const guint8 *pasp_data = (const guint8 *) pasp->data;
10548 gint len = QT_UINT32 (pasp_data);
10551 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10552 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10554 CUR_STREAM (stream)->par_w = 0;
10555 CUR_STREAM (stream)->par_h = 0;
10558 CUR_STREAM (stream)->par_w = 0;
10559 CUR_STREAM (stream)->par_h = 0;
10563 const guint8 *fiel_data = (const guint8 *) fiel->data;
10564 gint len = QT_UINT32 (fiel_data);
10567 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10568 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10573 const guint8 *colr_data = (const guint8 *) colr->data;
10574 gint len = QT_UINT32 (colr_data);
10576 if (len == 19 || len == 18) {
10577 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10579 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10580 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10581 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10582 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10583 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10585 switch (primaries) {
10587 CUR_STREAM (stream)->colorimetry.primaries =
10588 GST_VIDEO_COLOR_PRIMARIES_BT709;
10591 CUR_STREAM (stream)->colorimetry.primaries =
10592 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10595 CUR_STREAM (stream)->colorimetry.primaries =
10596 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10599 CUR_STREAM (stream)->colorimetry.primaries =
10600 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10606 switch (transfer_function) {
10608 CUR_STREAM (stream)->colorimetry.transfer =
10609 GST_VIDEO_TRANSFER_BT709;
10612 CUR_STREAM (stream)->colorimetry.transfer =
10613 GST_VIDEO_TRANSFER_SMPTE240M;
10621 CUR_STREAM (stream)->colorimetry.matrix =
10622 GST_VIDEO_COLOR_MATRIX_BT709;
10625 CUR_STREAM (stream)->colorimetry.matrix =
10626 GST_VIDEO_COLOR_MATRIX_BT601;
10629 CUR_STREAM (stream)->colorimetry.matrix =
10630 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10633 CUR_STREAM (stream)->colorimetry.matrix =
10634 GST_VIDEO_COLOR_MATRIX_BT2020;
10640 CUR_STREAM (stream)->colorimetry.range =
10641 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10642 GST_VIDEO_COLOR_RANGE_16_235;
10644 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10647 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10652 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10653 stream->stream_tags);
10660 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10661 const guint8 *avc_data = stsd_entry_data + 0x56;
10664 while (len >= 0x8) {
10667 if (QT_UINT32 (avc_data) <= len)
10668 size = QT_UINT32 (avc_data) - 0x8;
10673 /* No real data, so break out */
10676 switch (QT_FOURCC (avc_data + 0x4)) {
10679 /* parse, if found */
10682 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10684 /* First 4 bytes are the length of the atom, the next 4 bytes
10685 * are the fourcc, the next 1 byte is the version, and the
10686 * subsequent bytes are profile_tier_level structure like data. */
10687 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10688 avc_data + 8 + 1, size - 1);
10689 buf = gst_buffer_new_and_alloc (size);
10690 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10691 gst_caps_set_simple (entry->caps,
10692 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10693 gst_buffer_unref (buf);
10701 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10703 /* First 4 bytes are the length of the atom, the next 4 bytes
10704 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10705 * next 1 byte is the version, and the
10706 * subsequent bytes are sequence parameter set like data. */
10708 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10710 gst_codec_utils_h264_caps_set_level_and_profile
10711 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10713 buf = gst_buffer_new_and_alloc (size);
10714 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10715 gst_caps_set_simple (entry->caps,
10716 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10717 gst_buffer_unref (buf);
10723 guint avg_bitrate, max_bitrate;
10725 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10729 max_bitrate = QT_UINT32 (avc_data + 0xc);
10730 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10732 if (!max_bitrate && !avg_bitrate)
10735 /* Some muxers seem to swap the average and maximum bitrates
10736 * (I'm looking at you, YouTube), so we swap for sanity. */
10737 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10738 guint temp = avg_bitrate;
10740 avg_bitrate = max_bitrate;
10741 max_bitrate = temp;
10744 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10745 gst_tag_list_add (stream->stream_tags,
10746 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10747 max_bitrate, NULL);
10749 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10750 gst_tag_list_add (stream->stream_tags,
10751 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10763 avc_data += size + 8;
10772 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10773 const guint8 *hevc_data = stsd_entry_data + 0x56;
10776 while (len >= 0x8) {
10779 if (QT_UINT32 (hevc_data) <= len)
10780 size = QT_UINT32 (hevc_data) - 0x8;
10785 /* No real data, so break out */
10788 switch (QT_FOURCC (hevc_data + 0x4)) {
10791 /* parse, if found */
10794 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10796 /* First 4 bytes are the length of the atom, the next 4 bytes
10797 * are the fourcc, the next 1 byte is the version, and the
10798 * subsequent bytes are sequence parameter set like data. */
10799 gst_codec_utils_h265_caps_set_level_tier_and_profile
10800 (entry->caps, hevc_data + 8 + 1, size - 1);
10802 buf = gst_buffer_new_and_alloc (size);
10803 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10804 gst_caps_set_simple (entry->caps,
10805 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10806 gst_buffer_unref (buf);
10813 hevc_data += size + 8;
10826 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10827 GST_FOURCC_ARGS (fourcc));
10829 /* codec data might be in glbl extension atom */
10831 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10837 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10839 len = QT_UINT32 (data);
10842 buf = gst_buffer_new_and_alloc (len);
10843 gst_buffer_fill (buf, 0, data + 8, len);
10844 gst_caps_set_simple (entry->caps,
10845 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10846 gst_buffer_unref (buf);
10853 /* see annex I of the jpeg2000 spec */
10854 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10855 const guint8 *data;
10856 const gchar *colorspace = NULL;
10858 guint32 ncomp_map = 0;
10859 gint32 *comp_map = NULL;
10860 guint32 nchan_def = 0;
10861 gint32 *chan_def = NULL;
10863 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10864 /* some required atoms */
10865 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10868 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10872 /* number of components; redundant with info in codestream, but useful
10874 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10875 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10877 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10879 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10882 GST_DEBUG_OBJECT (qtdemux, "found colr");
10883 /* extract colour space info */
10884 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10885 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10887 colorspace = "sRGB";
10890 colorspace = "GRAY";
10893 colorspace = "sYUV";
10901 /* colr is required, and only values 16, 17, and 18 are specified,
10902 so error if we have no colorspace */
10905 /* extract component mapping */
10906 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10908 guint32 cmap_len = 0;
10910 cmap_len = QT_UINT32 (cmap->data);
10911 if (cmap_len >= 8) {
10912 /* normal box, subtract off header */
10914 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10915 if (cmap_len % 4 == 0) {
10916 ncomp_map = (cmap_len / 4);
10917 comp_map = g_new0 (gint32, ncomp_map);
10918 for (i = 0; i < ncomp_map; i++) {
10921 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10922 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10923 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10924 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10929 /* extract channel definitions */
10930 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10932 guint32 cdef_len = 0;
10934 cdef_len = QT_UINT32 (cdef->data);
10935 if (cdef_len >= 10) {
10936 /* normal box, subtract off header and len */
10938 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10939 if (cdef_len % 6 == 0) {
10940 nchan_def = (cdef_len / 6);
10941 chan_def = g_new0 (gint32, nchan_def);
10942 for (i = 0; i < nchan_def; i++)
10944 for (i = 0; i < nchan_def; i++) {
10945 guint16 cn, typ, asoc;
10946 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10947 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10948 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10949 if (cn < nchan_def) {
10952 chan_def[cn] = asoc;
10955 chan_def[cn] = 0; /* alpha */
10958 chan_def[cn] = -typ;
10966 gst_caps_set_simple (entry->caps,
10967 "num-components", G_TYPE_INT, ncomp, NULL);
10968 gst_caps_set_simple (entry->caps,
10969 "colorspace", G_TYPE_STRING, colorspace, NULL);
10972 GValue arr = { 0, };
10973 GValue elt = { 0, };
10975 g_value_init (&arr, GST_TYPE_ARRAY);
10976 g_value_init (&elt, G_TYPE_INT);
10977 for (i = 0; i < ncomp_map; i++) {
10978 g_value_set_int (&elt, comp_map[i]);
10979 gst_value_array_append_value (&arr, &elt);
10981 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10982 "component-map", &arr);
10983 g_value_unset (&elt);
10984 g_value_unset (&arr);
10989 GValue arr = { 0, };
10990 GValue elt = { 0, };
10992 g_value_init (&arr, GST_TYPE_ARRAY);
10993 g_value_init (&elt, G_TYPE_INT);
10994 for (i = 0; i < nchan_def; i++) {
10995 g_value_set_int (&elt, chan_def[i]);
10996 gst_value_array_append_value (&arr, &elt);
10998 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10999 "channel-definitions", &arr);
11000 g_value_unset (&elt);
11001 g_value_unset (&arr);
11005 /* some optional atoms */
11006 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11007 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11009 /* indicate possible fields in caps */
11011 data = (guint8 *) field->data + 8;
11013 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11014 (gint) * data, NULL);
11016 /* add codec_data if provided */
11021 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11022 data = prefix->data;
11023 len = QT_UINT32 (data);
11026 buf = gst_buffer_new_and_alloc (len);
11027 gst_buffer_fill (buf, 0, data + 8, len);
11028 gst_caps_set_simple (entry->caps,
11029 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11030 gst_buffer_unref (buf);
11039 GstBuffer *seqh = NULL;
11040 const guint8 *gamma_data = NULL;
11041 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11043 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11046 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11047 QT_FP32 (gamma_data), NULL);
11050 /* sorry for the bad name, but we don't know what this is, other
11051 * than its own fourcc */
11052 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11054 gst_buffer_unref (seqh);
11057 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11058 buf = gst_buffer_new_and_alloc (len);
11059 gst_buffer_fill (buf, 0, stsd_data, len);
11060 gst_caps_set_simple (entry->caps,
11061 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11062 gst_buffer_unref (buf);
11067 /* https://developer.apple.com/standards/qtff-2001.pdf,
11068 * page 92, "Video Sample Description", under table 3.1 */
11071 const gint compressor_offset =
11072 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11073 const gint min_size = compressor_offset + 32 + 2 + 2;
11076 guint16 color_table_id = 0;
11079 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11081 /* recover information on interlaced/progressive */
11082 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11086 len = QT_UINT32 (jpeg->data);
11087 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11089 if (len >= min_size) {
11090 gst_byte_reader_init (&br, jpeg->data, len);
11092 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11093 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11094 if (color_table_id != 0) {
11095 /* the spec says there can be concatenated chunks in the data, and we want
11096 * to find one called field. Walk through them. */
11097 gint offset = min_size;
11098 while (offset + 8 < len) {
11099 guint32 size = 0, tag;
11100 ok = gst_byte_reader_get_uint32_le (&br, &size);
11101 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11102 if (!ok || size < 8) {
11103 GST_WARNING_OBJECT (qtdemux,
11104 "Failed to walk optional chunk list");
11107 GST_DEBUG_OBJECT (qtdemux,
11108 "Found optional %4.4s chunk, size %u",
11109 (const char *) &tag, size);
11110 if (tag == FOURCC_fiel) {
11111 guint8 n_fields = 0, ordering = 0;
11112 gst_byte_reader_get_uint8 (&br, &n_fields);
11113 gst_byte_reader_get_uint8 (&br, &ordering);
11114 if (n_fields == 1 || n_fields == 2) {
11115 GST_DEBUG_OBJECT (qtdemux,
11116 "Found fiel tag with %u fields, ordering %u",
11117 n_fields, ordering);
11119 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11120 "interlace-mode", G_TYPE_STRING, "interleaved",
11123 GST_WARNING_OBJECT (qtdemux,
11124 "Found fiel tag with invalid fields (%u)", n_fields);
11130 GST_DEBUG_OBJECT (qtdemux,
11131 "Color table ID is 0, not trying to get interlacedness");
11134 GST_WARNING_OBJECT (qtdemux,
11135 "Length of jpeg chunk is too small, not trying to get interlacedness");
11143 gst_caps_set_simple (entry->caps,
11144 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11150 GNode *xith, *xdxt;
11152 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11153 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11157 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11161 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11162 /* collect the headers and store them in a stream list so that we can
11163 * send them out first */
11164 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11174 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11175 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11178 ovc1_data = ovc1->data;
11179 ovc1_len = QT_UINT32 (ovc1_data);
11180 if (ovc1_len <= 198) {
11181 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11184 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11185 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11186 gst_caps_set_simple (entry->caps,
11187 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11188 gst_buffer_unref (buf);
11193 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11194 const guint8 *vc1_data = stsd_entry_data + 0x56;
11200 if (QT_UINT32 (vc1_data) <= len)
11201 size = QT_UINT32 (vc1_data) - 8;
11206 /* No real data, so break out */
11209 switch (QT_FOURCC (vc1_data + 0x4)) {
11210 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11214 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11215 buf = gst_buffer_new_and_alloc (size);
11216 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11217 gst_caps_set_simple (entry->caps,
11218 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11219 gst_buffer_unref (buf);
11226 vc1_data += size + 8;
11235 GST_INFO_OBJECT (qtdemux,
11236 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11237 GST_FOURCC_ARGS (fourcc), entry->caps);
11239 } else if (stream->subtype == FOURCC_soun) {
11241 int version, samplesize;
11242 guint16 compression_id;
11243 gboolean amrwb = FALSE;
11246 /* sample description entry (16) + sound sample description v0 (20) */
11250 version = QT_UINT32 (stsd_entry_data + offset);
11251 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11252 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11253 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11254 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11256 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11257 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11258 QT_UINT32 (stsd_entry_data + offset + 4));
11259 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11260 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11261 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11262 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11263 QT_UINT16 (stsd_entry_data + offset + 14));
11264 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11266 if (compression_id == 0xfffe)
11267 entry->sampled = TRUE;
11269 /* first assume uncompressed audio */
11270 entry->bytes_per_sample = samplesize / 8;
11271 entry->samples_per_frame = entry->n_channels;
11272 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11273 entry->samples_per_packet = entry->samples_per_frame;
11274 entry->bytes_per_packet = entry->bytes_per_sample;
11278 /* Yes, these have to be hard-coded */
11281 entry->samples_per_packet = 6;
11282 entry->bytes_per_packet = 1;
11283 entry->bytes_per_frame = 1 * entry->n_channels;
11284 entry->bytes_per_sample = 1;
11285 entry->samples_per_frame = 6 * entry->n_channels;
11290 entry->samples_per_packet = 3;
11291 entry->bytes_per_packet = 1;
11292 entry->bytes_per_frame = 1 * entry->n_channels;
11293 entry->bytes_per_sample = 1;
11294 entry->samples_per_frame = 3 * entry->n_channels;
11299 entry->samples_per_packet = 64;
11300 entry->bytes_per_packet = 34;
11301 entry->bytes_per_frame = 34 * entry->n_channels;
11302 entry->bytes_per_sample = 2;
11303 entry->samples_per_frame = 64 * entry->n_channels;
11309 entry->samples_per_packet = 1;
11310 entry->bytes_per_packet = 1;
11311 entry->bytes_per_frame = 1 * entry->n_channels;
11312 entry->bytes_per_sample = 1;
11313 entry->samples_per_frame = 1 * entry->n_channels;
11318 entry->samples_per_packet = 160;
11319 entry->bytes_per_packet = 33;
11320 entry->bytes_per_frame = 33 * entry->n_channels;
11321 entry->bytes_per_sample = 2;
11322 entry->samples_per_frame = 160 * entry->n_channels;
11329 if (version == 0x00010000) {
11330 /* sample description entry (16) + sound sample description v1 (20+16) */
11342 /* only parse extra decoding config for non-pcm audio */
11343 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11344 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11345 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11346 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11348 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11349 entry->samples_per_packet);
11350 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11351 entry->bytes_per_packet);
11352 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11353 entry->bytes_per_frame);
11354 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11355 entry->bytes_per_sample);
11357 if (!entry->sampled && entry->bytes_per_packet) {
11358 entry->samples_per_frame = (entry->bytes_per_frame /
11359 entry->bytes_per_packet) * entry->samples_per_packet;
11360 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11361 entry->samples_per_frame);
11366 } else if (version == 0x00020000) {
11373 /* sample description entry (16) + sound sample description v2 (56) */
11377 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11378 entry->rate = qtfp.fp;
11379 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11381 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11382 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11383 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11384 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11385 QT_UINT32 (stsd_entry_data + offset + 20));
11386 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11387 QT_UINT32 (stsd_entry_data + offset + 24));
11388 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11389 QT_UINT32 (stsd_entry_data + offset + 28));
11390 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11391 QT_UINT32 (stsd_entry_data + offset + 32));
11392 } else if (version != 0x00000) {
11393 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11398 gst_caps_unref (entry->caps);
11400 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11401 stsd_entry_data + 32, len - 16, &codec);
11409 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11411 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11413 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11415 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11418 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11419 gst_caps_set_simple (entry->caps,
11420 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11427 const guint8 *owma_data;
11428 const gchar *codec_name = NULL;
11432 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11433 /* FIXME this should also be gst_riff_strf_auds,
11434 * but the latter one is actually missing bits-per-sample :( */
11439 gint32 nSamplesPerSec;
11440 gint32 nAvgBytesPerSec;
11441 gint16 nBlockAlign;
11442 gint16 wBitsPerSample;
11445 WAVEFORMATEX *wfex;
11447 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11448 owma_data = stsd_entry_data;
11449 owma_len = QT_UINT32 (owma_data);
11450 if (owma_len <= 54) {
11451 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11454 wfex = (WAVEFORMATEX *) (owma_data + 36);
11455 buf = gst_buffer_new_and_alloc (owma_len - 54);
11456 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11457 if (wfex->wFormatTag == 0x0161) {
11458 codec_name = "Windows Media Audio";
11460 } else if (wfex->wFormatTag == 0x0162) {
11461 codec_name = "Windows Media Audio 9 Pro";
11463 } else if (wfex->wFormatTag == 0x0163) {
11464 codec_name = "Windows Media Audio 9 Lossless";
11465 /* is that correct? gstffmpegcodecmap.c is missing it, but
11466 * fluendo codec seems to support it */
11470 gst_caps_set_simple (entry->caps,
11471 "codec_data", GST_TYPE_BUFFER, buf,
11472 "wmaversion", G_TYPE_INT, version,
11473 "block_align", G_TYPE_INT,
11474 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11475 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11476 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11477 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11478 gst_buffer_unref (buf);
11482 codec = g_strdup (codec_name);
11488 gint len = QT_UINT32 (stsd_entry_data) - offset;
11489 const guint8 *wfex_data = stsd_entry_data + offset;
11490 const gchar *codec_name = NULL;
11492 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11493 /* FIXME this should also be gst_riff_strf_auds,
11494 * but the latter one is actually missing bits-per-sample :( */
11499 gint32 nSamplesPerSec;
11500 gint32 nAvgBytesPerSec;
11501 gint16 nBlockAlign;
11502 gint16 wBitsPerSample;
11507 /* FIXME: unify with similar wavformatex parsing code above */
11508 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11514 if (QT_UINT32 (wfex_data) <= len)
11515 size = QT_UINT32 (wfex_data) - 8;
11520 /* No real data, so break out */
11523 switch (QT_FOURCC (wfex_data + 4)) {
11524 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11526 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11531 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11532 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11533 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11534 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11535 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11536 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11537 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11539 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11540 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11541 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11542 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11543 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11544 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11546 if (wfex.wFormatTag == 0x0161) {
11547 codec_name = "Windows Media Audio";
11549 } else if (wfex.wFormatTag == 0x0162) {
11550 codec_name = "Windows Media Audio 9 Pro";
11552 } else if (wfex.wFormatTag == 0x0163) {
11553 codec_name = "Windows Media Audio 9 Lossless";
11554 /* is that correct? gstffmpegcodecmap.c is missing it, but
11555 * fluendo codec seems to support it */
11559 gst_caps_set_simple (entry->caps,
11560 "wmaversion", G_TYPE_INT, version,
11561 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11562 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11563 "width", G_TYPE_INT, wfex.wBitsPerSample,
11564 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11566 if (size > wfex.cbSize) {
11569 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11570 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11571 size - wfex.cbSize);
11572 gst_caps_set_simple (entry->caps,
11573 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11574 gst_buffer_unref (buf);
11576 GST_WARNING_OBJECT (qtdemux, "no codec data");
11581 codec = g_strdup (codec_name);
11589 wfex_data += size + 8;
11595 const guint8 *opus_data;
11596 guint8 *channel_mapping = NULL;
11599 guint8 channel_mapping_family;
11600 guint8 stream_count;
11601 guint8 coupled_count;
11604 opus_data = stsd_entry_data;
11606 channels = GST_READ_UINT8 (opus_data + 45);
11607 rate = GST_READ_UINT32_LE (opus_data + 48);
11608 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11609 stream_count = GST_READ_UINT8 (opus_data + 55);
11610 coupled_count = GST_READ_UINT8 (opus_data + 56);
11612 if (channels > 0) {
11613 channel_mapping = g_malloc (channels * sizeof (guint8));
11614 for (i = 0; i < channels; i++)
11615 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11618 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11619 channel_mapping_family, stream_count, coupled_count,
11631 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11632 GST_TAG_AUDIO_CODEC, codec, NULL);
11636 /* some bitrate info may have ended up in caps */
11637 s = gst_caps_get_structure (entry->caps, 0);
11638 gst_structure_get_int (s, "bitrate", &bitrate);
11640 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11641 GST_TAG_BITRATE, bitrate, NULL);
11644 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11645 if (!stream->protected) {
11647 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11651 if (stream->protected && fourcc == FOURCC_mp4a) {
11652 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11656 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11664 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11666 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11668 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11672 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11673 16 bits is a byte-swapped wave-style codec identifier,
11674 and we can find a WAVE header internally to a 'wave' atom here.
11675 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11676 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11679 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11680 if (len < offset + 20) {
11681 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11683 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11684 const guint8 *data = stsd_entry_data + offset + 16;
11686 GNode *waveheadernode;
11688 wavenode = g_node_new ((guint8 *) data);
11689 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11690 const guint8 *waveheader;
11693 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11694 if (waveheadernode) {
11695 waveheader = (const guint8 *) waveheadernode->data;
11696 headerlen = QT_UINT32 (waveheader);
11698 if (headerlen > 8) {
11699 gst_riff_strf_auds *header = NULL;
11700 GstBuffer *headerbuf;
11706 headerbuf = gst_buffer_new_and_alloc (headerlen);
11707 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11709 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11710 headerbuf, &header, &extra)) {
11711 gst_caps_unref (entry->caps);
11712 /* FIXME: Need to do something with the channel reorder map */
11714 gst_riff_create_audio_caps (header->format, NULL, header,
11715 extra, NULL, NULL, NULL);
11718 gst_buffer_unref (extra);
11723 GST_DEBUG ("Didn't find waveheadernode for this codec");
11725 g_node_destroy (wavenode);
11728 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11729 stream->stream_tags);
11733 /* FIXME: what is in the chunk? */
11736 gint len = QT_UINT32 (stsd_data);
11738 /* seems to be always = 116 = 0x74 */
11744 gint len = QT_UINT32 (stsd_entry_data);
11747 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11749 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11750 gst_caps_set_simple (entry->caps,
11751 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11752 gst_buffer_unref (buf);
11754 gst_caps_set_simple (entry->caps,
11755 "samplesize", G_TYPE_INT, samplesize, NULL);
11760 GNode *alac, *wave = NULL;
11762 /* apparently, m4a has this atom appended directly in the stsd entry,
11763 * while mov has it in a wave atom */
11764 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11766 /* alac now refers to stsd entry atom */
11767 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11769 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11771 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11774 const guint8 *alac_data = alac->data;
11775 gint len = QT_UINT32 (alac->data);
11779 GST_DEBUG_OBJECT (qtdemux,
11780 "discarding alac atom with unexpected len %d", len);
11782 /* codec-data contains alac atom size and prefix,
11783 * ffmpeg likes it that way, not quite gst-ish though ...*/
11784 buf = gst_buffer_new_and_alloc (len);
11785 gst_buffer_fill (buf, 0, alac->data, len);
11786 gst_caps_set_simple (entry->caps,
11787 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11788 gst_buffer_unref (buf);
11790 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11791 entry->n_channels = QT_UINT8 (alac_data + 21);
11792 entry->rate = QT_UINT32 (alac_data + 32);
11795 gst_caps_set_simple (entry->caps,
11796 "samplesize", G_TYPE_INT, samplesize, NULL);
11801 /* The codingname of the sample entry is 'fLaC' */
11802 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11805 /* The 'dfLa' box is added to the sample entry to convey
11806 initializing information for the decoder. */
11807 const GNode *dfla =
11808 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11811 const guint32 len = QT_UINT32 (dfla->data);
11813 /* Must contain at least dfLa box header (12),
11814 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11816 GST_DEBUG_OBJECT (qtdemux,
11817 "discarding dfla atom with unexpected len %d", len);
11819 /* skip dfLa header to get the METADATA_BLOCKs */
11820 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11821 const guint32 metadata_blocks_len = len - 12;
11823 gchar *stream_marker = g_strdup ("fLaC");
11824 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11825 strlen (stream_marker));
11828 guint32 remainder = 0;
11829 guint32 block_size = 0;
11830 gboolean is_last = FALSE;
11832 GValue array = G_VALUE_INIT;
11833 GValue value = G_VALUE_INIT;
11835 g_value_init (&array, GST_TYPE_ARRAY);
11836 g_value_init (&value, GST_TYPE_BUFFER);
11838 gst_value_set_buffer (&value, block);
11839 gst_value_array_append_value (&array, &value);
11840 g_value_reset (&value);
11842 gst_buffer_unref (block);
11844 /* check there's at least one METADATA_BLOCK_HEADER's worth
11845 * of data, and we haven't already finished parsing */
11846 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11847 remainder = metadata_blocks_len - index;
11849 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11851 (metadata_blocks[index + 1] << 16) +
11852 (metadata_blocks[index + 2] << 8) +
11853 metadata_blocks[index + 3];
11855 /* be careful not to read off end of box */
11856 if (block_size > remainder) {
11860 is_last = metadata_blocks[index] >> 7;
11862 block = gst_buffer_new_and_alloc (block_size);
11864 gst_buffer_fill (block, 0, &metadata_blocks[index],
11867 gst_value_set_buffer (&value, block);
11868 gst_value_array_append_value (&array, &value);
11869 g_value_reset (&value);
11871 gst_buffer_unref (block);
11873 index += block_size;
11876 /* only append the metadata if we successfully read all of it */
11878 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11879 (stream)->caps, 0), "streamheader", &array);
11881 GST_WARNING_OBJECT (qtdemux,
11882 "discarding all METADATA_BLOCKs due to invalid "
11883 "block_size %d at idx %d, rem %d", block_size, index,
11887 g_value_unset (&value);
11888 g_value_unset (&array);
11890 /* The sample rate obtained from the stsd may not be accurate
11891 * since it cannot represent rates greater than 65535Hz, so
11892 * override that value with the sample rate from the
11893 * METADATA_BLOCK_STREAMINFO block */
11894 CUR_STREAM (stream)->rate =
11895 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11906 gint len = QT_UINT32 (stsd_entry_data);
11909 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11912 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11914 /* If we have enough data, let's try to get the 'damr' atom. See
11915 * the 3GPP container spec (26.244) for more details. */
11916 if ((len - 0x34) > 8 &&
11917 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11918 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11919 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11922 gst_caps_set_simple (entry->caps,
11923 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11924 gst_buffer_unref (buf);
11930 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11931 gint len = QT_UINT32 (stsd_entry_data);
11934 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11936 if (sound_version == 1) {
11937 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11938 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11939 guint8 codec_data[2];
11941 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11943 gint sample_rate_index =
11944 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11946 /* build AAC codec data */
11947 codec_data[0] = profile << 3;
11948 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11949 codec_data[1] = (sample_rate_index & 0x01) << 7;
11950 codec_data[1] |= (channels & 0xF) << 3;
11952 buf = gst_buffer_new_and_alloc (2);
11953 gst_buffer_fill (buf, 0, codec_data, 2);
11954 gst_caps_set_simple (entry->caps,
11955 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11956 gst_buffer_unref (buf);
11962 /* Fully handled elsewhere */
11965 GST_INFO_OBJECT (qtdemux,
11966 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11970 GST_INFO_OBJECT (qtdemux,
11971 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11972 GST_FOURCC_ARGS (fourcc), entry->caps);
11974 } else if (stream->subtype == FOURCC_strm) {
11975 if (fourcc == FOURCC_rtsp) {
11976 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11978 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11979 GST_FOURCC_ARGS (fourcc));
11980 goto unknown_stream;
11982 entry->sampled = TRUE;
11983 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11984 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
11985 || stream->subtype == FOURCC_clcp) {
11987 entry->sampled = TRUE;
11988 entry->sparse = TRUE;
11991 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11994 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11995 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12000 /* hunt for sort-of codec data */
12004 GNode *mp4s = NULL;
12005 GNode *esds = NULL;
12007 /* look for palette in a stsd->mp4s->esds sub-atom */
12008 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12010 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12011 if (esds == NULL) {
12013 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12017 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12018 stream->stream_tags);
12022 GST_INFO_OBJECT (qtdemux,
12023 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12026 GST_INFO_OBJECT (qtdemux,
12027 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12028 GST_FOURCC_ARGS (fourcc), entry->caps);
12030 /* everything in 1 sample */
12031 entry->sampled = TRUE;
12034 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12037 if (entry->caps == NULL)
12038 goto unknown_stream;
12041 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12042 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12048 /* promote to sampled format */
12049 if (entry->fourcc == FOURCC_samr) {
12050 /* force mono 8000 Hz for AMR */
12051 entry->sampled = TRUE;
12052 entry->n_channels = 1;
12053 entry->rate = 8000;
12054 } else if (entry->fourcc == FOURCC_sawb) {
12055 /* force mono 16000 Hz for AMR-WB */
12056 entry->sampled = TRUE;
12057 entry->n_channels = 1;
12058 entry->rate = 16000;
12059 } else if (entry->fourcc == FOURCC_mp4a) {
12060 entry->sampled = TRUE;
12064 stsd_entry_data += len;
12065 remaining_stsd_len -= len;
12069 /* collect sample information */
12070 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12071 goto samples_failed;
12073 if (qtdemux->fragmented) {
12076 /* need all moov samples as basis; probably not many if any at all */
12077 /* prevent moof parsing taking of at this time */
12078 offset = qtdemux->moof_offset;
12079 qtdemux->moof_offset = 0;
12080 if (stream->n_samples &&
12081 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12082 qtdemux->moof_offset = offset;
12083 goto samples_failed;
12085 qtdemux->moof_offset = 0;
12086 /* movie duration more reliable in this case (e.g. mehd) */
12087 if (qtdemux->segment.duration &&
12088 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12090 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12093 /* configure segments */
12094 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12095 goto segments_failed;
12097 /* add some language tag, if useful */
12098 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12099 strcmp (stream->lang_id, "und")) {
12100 const gchar *lang_code;
12102 /* convert ISO 639-2 code to ISO 639-1 */
12103 lang_code = gst_tag_get_language_code (stream->lang_id);
12104 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12105 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12108 /* Check for UDTA tags */
12109 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12110 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12113 /* Insert and sort new stream in track-id order.
12114 * This will help in comparing old/new streams during stream update check */
12115 qtdemux->active_streams =
12116 g_list_insert_sorted (qtdemux->active_streams, stream,
12117 (GCompareFunc) qtdemux_track_id_compare_func);
12118 qtdemux->n_streams++;
12119 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
12126 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12127 (_("This file is corrupt and cannot be played.")), (NULL));
12129 gst_qtdemux_stream_free (stream);
12134 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12135 gst_qtdemux_stream_free (stream);
12141 /* we posted an error already */
12142 /* free stbl sub-atoms */
12143 gst_qtdemux_stbl_free (stream);
12144 gst_qtdemux_stream_free (stream);
12149 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12155 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12156 GST_FOURCC_ARGS (stream->subtype));
12157 gst_qtdemux_stream_free (stream);
12162 /* If we can estimate the overall bitrate, and don't have information about the
12163 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12164 * the overall bitrate minus the sum of the bitrates of all other streams. This
12165 * should be useful for the common case where we have one audio and one video
12166 * stream and can estimate the bitrate of one, but not the other. */
12168 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12170 QtDemuxStream *stream = NULL;
12171 gint64 size, sys_bitrate, sum_bitrate = 0;
12172 GstClockTime duration;
12176 if (qtdemux->fragmented)
12179 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12181 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12183 GST_DEBUG_OBJECT (qtdemux,
12184 "Size in bytes of the stream not known - bailing");
12188 /* Subtract the header size */
12189 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12190 size, qtdemux->header_size);
12192 if (size < qtdemux->header_size)
12195 size = size - qtdemux->header_size;
12197 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12198 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12202 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12203 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
12204 switch (str->subtype) {
12207 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12208 CUR_STREAM (str)->caps);
12209 /* retrieve bitrate, prefer avg then max */
12211 if (str->stream_tags) {
12212 if (gst_tag_list_get_uint (str->stream_tags,
12213 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12214 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12215 if (gst_tag_list_get_uint (str->stream_tags,
12216 GST_TAG_NOMINAL_BITRATE, &bitrate))
12217 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12218 if (gst_tag_list_get_uint (str->stream_tags,
12219 GST_TAG_BITRATE, &bitrate))
12220 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12223 sum_bitrate += bitrate;
12226 GST_DEBUG_OBJECT (qtdemux,
12227 ">1 stream with unknown bitrate - bailing");
12234 /* For other subtypes, we assume no significant impact on bitrate */
12240 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12244 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12246 if (sys_bitrate < sum_bitrate) {
12247 /* This can happen, since sum_bitrate might be derived from maximum
12248 * bitrates and not average bitrates */
12249 GST_DEBUG_OBJECT (qtdemux,
12250 "System bitrate less than sum bitrate - bailing");
12254 bitrate = sys_bitrate - sum_bitrate;
12255 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12256 ", Stream bitrate = %u", sys_bitrate, bitrate);
12258 if (!stream->stream_tags)
12259 stream->stream_tags = gst_tag_list_new_empty ();
12261 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12263 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12264 GST_TAG_BITRATE, bitrate, NULL);
12267 static GstFlowReturn
12268 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12270 GstFlowReturn ret = GST_FLOW_OK;
12271 GList *iter, *next;
12273 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12275 for (iter = qtdemux->active_streams; ret == GST_FLOW_OK && iter; iter = next) {
12276 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12277 guint32 sample_num = 0;
12281 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12282 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12284 if (qtdemux->fragmented) {
12285 /* need all moov samples first */
12286 GST_OBJECT_LOCK (qtdemux);
12287 while (stream->n_samples == 0)
12288 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12290 GST_OBJECT_UNLOCK (qtdemux);
12292 /* discard any stray moof */
12293 qtdemux->moof_offset = 0;
12296 /* prepare braking */
12297 if (ret != GST_FLOW_ERROR)
12300 /* in pull mode, we should have parsed some sample info by now;
12301 * and quite some code will not handle no samples.
12302 * in push mode, we'll just have to deal with it */
12303 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12304 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12305 gst_qtdemux_remove_stream (qtdemux, stream);
12307 } else if (stream->track_id == qtdemux->chapters_track_id &&
12308 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12309 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12310 so that it doesn't look like a subtitle track */
12311 gst_qtdemux_remove_stream (qtdemux, stream);
12315 /* parse the initial sample for use in setting the frame rate cap */
12316 while (sample_num == 0 && sample_num < stream->n_samples) {
12317 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12327 _stream_in_list (GList * list, QtDemuxStream * stream)
12331 for (iter = list; iter; iter = g_list_next (iter)) {
12332 QtDemuxStream *tmp = QTDEMUX_STREAM (iter->data);
12333 if (!g_strcmp0 (tmp->stream_id, stream->stream_id))
12341 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12345 g_return_val_if_fail (qtdemux->active_streams != NULL, FALSE);
12347 /* streams in list are sorted in track-id order */
12348 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12349 new = g_list_next (new), old = g_list_next (old)) {
12351 /* Different stream-id, updated */
12352 if (g_strcmp0 (QTDEMUX_STREAM (new->data)->stream_id,
12353 QTDEMUX_STREAM (old->data)->stream_id))
12357 /* Different length, updated */
12358 if (new != NULL || old != NULL)
12365 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12366 QtDemuxStream * oldstream, QtDemuxStream * newstream)
12368 /* Connect old stream's srcpad to new stream */
12369 newstream->pad = oldstream->pad;
12370 oldstream->pad = NULL;
12372 /* unset new_stream to prevent stream-start event */
12373 newstream->new_stream = FALSE;
12375 return gst_qtdemux_configure_stream (qtdemux, newstream);
12379 qtdemux_update_streams (GstQTDemux * qtdemux)
12381 GList *iter, *next;
12383 /* At below, figure out which stream in active_streams has identical stream-id
12384 * with that of in old_streams. If there is matching stream-id,
12385 * corresponding newstream will not be exposed again,
12386 * but demux will reuse srcpad of matched old stream
12388 * active_streams : newly created streams from the latest moov
12389 * old_streams : existing streams (belong to previous moov)
12392 /* Count n_streams again */
12393 qtdemux->n_streams = 0;
12395 for (iter = qtdemux->active_streams; iter; iter = next) {
12397 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12401 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12402 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12404 qtdemux->n_streams++;
12406 if (qtdemux->streams_aware
12407 && (tmp = _stream_in_list (qtdemux->old_streams, stream)) != NULL
12408 && QTDEMUX_STREAM (tmp->data)->pad) {
12409 QtDemuxStream *oldstream = QTDEMUX_STREAM (tmp->data);
12411 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12413 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12416 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, oldstream);
12417 gst_qtdemux_stream_free (oldstream);
12421 /* now we have all info and can expose */
12422 list = stream->stream_tags;
12423 stream->stream_tags = NULL;
12424 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12432 /* Must be called with expose lock */
12433 static GstFlowReturn
12434 qtdemux_expose_streams (GstQTDemux * qtdemux)
12436 GList *iter, *next;
12438 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12440 if (!qtdemux_is_streams_update (qtdemux)) {
12443 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12444 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12445 new = g_list_next (new), old = g_list_next (old)) {
12446 if (!qtdemux_reuse_and_configure_stream (qtdemux,
12447 QTDEMUX_STREAM (old->data), QTDEMUX_STREAM (new->data)))
12448 return GST_FLOW_ERROR;
12451 g_list_free_full (qtdemux->old_streams,
12452 (GDestroyNotify) gst_qtdemux_stream_free);
12453 qtdemux->old_streams = NULL;
12455 return GST_FLOW_OK;
12458 if (qtdemux->streams_aware) {
12459 if (!qtdemux_update_streams (qtdemux))
12460 return GST_FLOW_ERROR;
12462 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12463 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12466 /* now we have all info and can expose */
12467 list = stream->stream_tags;
12468 stream->stream_tags = NULL;
12469 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12470 return GST_FLOW_ERROR;
12475 gst_qtdemux_guess_bitrate (qtdemux);
12477 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12479 /* If we have still old_streams, it's no more used stream */
12480 for (iter = qtdemux->old_streams; iter; iter = next) {
12481 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12482 next = g_list_next (iter);
12487 event = gst_event_new_eos ();
12488 if (qtdemux->segment_seqnum)
12489 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12491 gst_pad_push_event (stream->pad, event);
12494 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, stream);
12495 gst_qtdemux_stream_free (stream);
12498 /* check if we should post a redirect in case there is a single trak
12499 * and it is a redirecting trak */
12500 if (qtdemux->n_streams == 1 &&
12501 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri != NULL) {
12504 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12505 "an external content");
12506 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12507 gst_structure_new ("redirect",
12508 "new-location", G_TYPE_STRING,
12509 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri, NULL));
12510 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12511 qtdemux->posted_redirect = TRUE;
12514 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12515 qtdemux_do_allocation (qtdemux, QTDEMUX_STREAM (iter->data));
12518 qtdemux->exposed = TRUE;
12519 return GST_FLOW_OK;
12522 /* check if major or compatible brand is 3GP */
12523 static inline gboolean
12524 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12527 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12529 } else if (qtdemux->comp_brands != NULL) {
12533 gboolean res = FALSE;
12535 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12538 while (size >= 4) {
12539 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12544 gst_buffer_unmap (qtdemux->comp_brands, &map);
12551 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12552 static inline gboolean
12553 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12555 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12556 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12557 || fourcc == FOURCC_albm;
12561 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12562 const char *tag, const char *dummy, GNode * node)
12564 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12568 gdouble longitude, latitude, altitude;
12571 len = QT_UINT32 (node->data);
12578 /* TODO: language code skipped */
12580 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12583 /* do not alarm in trivial case, but bail out otherwise */
12584 if (*(data + offset) != 0) {
12585 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12589 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12590 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12591 offset += strlen (name);
12595 if (len < offset + 2 + 4 + 4 + 4)
12598 /* +1 +1 = skip null-terminator and location role byte */
12600 /* table in spec says unsigned, semantics say negative has meaning ... */
12601 longitude = QT_SFP32 (data + offset);
12604 latitude = QT_SFP32 (data + offset);
12607 altitude = QT_SFP32 (data + offset);
12609 /* one invalid means all are invalid */
12610 if (longitude >= -180.0 && longitude <= 180.0 &&
12611 latitude >= -90.0 && latitude <= 90.0) {
12612 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12613 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12614 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12615 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12618 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12625 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12632 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12633 const char *tag, const char *dummy, GNode * node)
12639 len = QT_UINT32 (node->data);
12643 y = QT_UINT16 ((guint8 *) node->data + 12);
12645 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12648 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12650 date = g_date_new_dmy (1, 1, y);
12651 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12652 g_date_free (date);
12656 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12657 const char *tag, const char *dummy, GNode * node)
12660 char *tag_str = NULL;
12665 len = QT_UINT32 (node->data);
12670 entity = (guint8 *) node->data + offset;
12671 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12672 GST_DEBUG_OBJECT (qtdemux,
12673 "classification info: %c%c%c%c invalid classification entity",
12674 entity[0], entity[1], entity[2], entity[3]);
12679 table = QT_UINT16 ((guint8 *) node->data + offset);
12681 /* Language code skipped */
12685 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12686 * XXXX: classification entity, fixed length 4 chars.
12687 * Y[YYYY]: classification table, max 5 chars.
12689 tag_str = g_strdup_printf ("----://%u/%s",
12690 table, (char *) node->data + offset);
12692 /* memcpy To be sure we're preserving byte order */
12693 memcpy (tag_str, entity, 4);
12694 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12696 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12705 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12711 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12712 const char *tag, const char *dummy, GNode * node)
12714 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12720 gboolean ret = TRUE;
12721 const gchar *charset = NULL;
12723 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12725 len = QT_UINT32 (data->data);
12726 type = QT_UINT32 ((guint8 *) data->data + 8);
12727 if (type == 0x00000001 && len > 16) {
12728 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12731 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12732 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12735 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12739 len = QT_UINT32 (node->data);
12740 type = QT_UINT32 ((guint8 *) node->data + 4);
12741 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12745 /* Type starts with the (C) symbol, so the next data is a list
12746 * of (string size(16), language code(16), string) */
12748 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12749 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12751 /* the string + fourcc + size + 2 16bit fields,
12752 * means that there are more tags in this atom */
12753 if (len > str_len + 8 + 4) {
12754 /* TODO how to represent the same tag in different languages? */
12755 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12756 "text alternatives, reading only first one");
12760 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12761 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12763 if (lang_code < 0x800) { /* MAC encoded string */
12766 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12767 QT_FOURCC ((guint8 *) node->data + 4))) {
12768 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12770 /* we go for 3GP style encoding if major brands claims so,
12771 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12772 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12773 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12774 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12776 /* 16-bit Language code is ignored here as well */
12777 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12784 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12785 ret = FALSE; /* may have to fallback */
12788 GError *err = NULL;
12790 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12791 charset, NULL, NULL, &err);
12793 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12794 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12796 g_error_free (err);
12799 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12800 len - offset, env_vars);
12803 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12804 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12808 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12815 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12816 const char *tag, const char *dummy, GNode * node)
12818 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12822 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12823 const char *tag, const char *dummy, GNode * node)
12825 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12827 char *s, *t, *k = NULL;
12832 /* first try normal string tag if major brand not 3GP */
12833 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12834 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12835 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12836 * let's try it 3gpp way after minor safety check */
12838 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12844 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12848 len = QT_UINT32 (data);
12852 count = QT_UINT8 (data + 14);
12854 for (; count; count--) {
12857 if (offset + 1 > len)
12859 slen = QT_UINT8 (data + offset);
12861 if (offset + slen > len)
12863 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12866 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12868 t = g_strjoin (",", k, s, NULL);
12876 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12883 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12884 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12893 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12899 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12900 const char *tag1, const char *tag2, GNode * node)
12907 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12909 len = QT_UINT32 (data->data);
12910 type = QT_UINT32 ((guint8 *) data->data + 8);
12911 if (type == 0x00000000 && len >= 22) {
12912 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12913 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12915 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12916 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12919 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12920 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12927 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12928 const char *tag1, const char *dummy, GNode * node)
12935 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12937 len = QT_UINT32 (data->data);
12938 type = QT_UINT32 ((guint8 *) data->data + 8);
12939 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12940 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12941 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12942 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12944 /* do not add bpm=0 */
12945 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12946 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12954 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12955 const char *tag1, const char *dummy, GNode * node)
12962 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12964 len = QT_UINT32 (data->data);
12965 type = QT_UINT32 ((guint8 *) data->data + 8);
12966 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12967 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12968 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12969 num = QT_UINT32 ((guint8 *) data->data + 16);
12971 /* do not add num=0 */
12972 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12973 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12980 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12981 const char *tag1, const char *dummy, GNode * node)
12988 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12990 len = QT_UINT32 (data->data);
12991 type = QT_UINT32 ((guint8 *) data->data + 8);
12992 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12993 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12994 GstTagImageType image_type;
12996 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12997 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12999 image_type = GST_TAG_IMAGE_TYPE_NONE;
13002 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13003 len - 16, image_type))) {
13004 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13005 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13006 gst_sample_unref (sample);
13013 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
13014 const char *tag, const char *dummy, GNode * node)
13017 GstDateTime *datetime = NULL;
13022 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13024 len = QT_UINT32 (data->data);
13025 type = QT_UINT32 ((guint8 *) data->data + 8);
13026 if (type == 0x00000001 && len > 16) {
13027 guint y, m = 1, d = 1;
13030 s = g_strndup ((char *) data->data + 16, len - 16);
13031 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13032 datetime = gst_date_time_new_from_iso8601_string (s);
13033 if (datetime != NULL) {
13034 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13036 gst_date_time_unref (datetime);
13039 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13040 if (ret >= 1 && y > 1500 && y < 3000) {
13043 date = g_date_new_dmy (d, m, y);
13044 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13045 g_date_free (date);
13047 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13055 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13056 const char *tag, const char *dummy, GNode * node)
13060 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13062 /* re-route to normal string tag if major brand says so
13063 * or no data atom and compatible brand suggests so */
13064 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13065 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13066 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13071 guint len, type, n;
13073 len = QT_UINT32 (data->data);
13074 type = QT_UINT32 ((guint8 *) data->data + 8);
13075 if (type == 0x00000000 && len >= 18) {
13076 n = QT_UINT16 ((guint8 *) data->data + 16);
13078 const gchar *genre;
13080 genre = gst_tag_id3_genre_get (n - 1);
13081 if (genre != NULL) {
13082 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13083 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13091 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13092 const gchar * tag, guint8 * data, guint32 datasize)
13097 /* make a copy to have \0 at the end */
13098 datacopy = g_strndup ((gchar *) data, datasize);
13100 /* convert the str to double */
13101 if (sscanf (datacopy, "%lf", &value) == 1) {
13102 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13103 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13105 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13113 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13114 const char *tag, const char *tag_bis, GNode * node)
13123 const gchar *meanstr;
13124 const gchar *namestr;
13126 /* checking the whole ---- atom size for consistency */
13127 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13128 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13132 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13134 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13138 meansize = QT_UINT32 (mean->data);
13139 if (meansize <= 12) {
13140 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13143 meanstr = ((gchar *) mean->data) + 12;
13146 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13148 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13152 namesize = QT_UINT32 (name->data);
13153 if (namesize <= 12) {
13154 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13157 namestr = ((gchar *) name->data) + 12;
13165 * uint24 - data type
13169 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13171 GST_WARNING_OBJECT (demux, "No data atom in this tag");
13174 datasize = QT_UINT32 (data->data);
13175 if (datasize <= 16) {
13176 GST_WARNING_OBJECT (demux, "Data atom too small");
13179 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13181 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13182 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13183 static const struct
13185 const gchar name[28];
13186 const gchar tag[28];
13189 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13190 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13191 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13192 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13193 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13194 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13195 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13196 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13200 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13201 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13202 switch (gst_tag_get_type (tags[i].tag)) {
13203 case G_TYPE_DOUBLE:
13204 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13205 ((guint8 *) data->data) + 16, datasize - 16);
13207 case G_TYPE_STRING:
13208 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13217 if (i == G_N_ELEMENTS (tags))
13227 #ifndef GST_DISABLE_GST_DEBUG
13229 gchar *namestr_dbg;
13230 gchar *meanstr_dbg;
13232 meanstr_dbg = g_strndup (meanstr, meansize);
13233 namestr_dbg = g_strndup (namestr, namesize);
13235 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13236 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13238 g_free (namestr_dbg);
13239 g_free (meanstr_dbg);
13246 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13247 const char *tag_bis, GNode * node)
13252 GstTagList *id32_taglist = NULL;
13254 GST_LOG_OBJECT (demux, "parsing ID32");
13257 len = GST_READ_UINT32_BE (data);
13259 /* need at least full box and language tag */
13263 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13264 gst_buffer_fill (buf, 0, data + 14, len - 14);
13266 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13267 if (id32_taglist) {
13268 GST_LOG_OBJECT (demux, "parsing ok");
13269 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13270 gst_tag_list_unref (id32_taglist);
13272 GST_LOG_OBJECT (demux, "parsing failed");
13275 gst_buffer_unref (buf);
13278 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13279 const char *tag, const char *tag_bis, GNode * node);
13282 FOURCC_pcst -> if media is a podcast -> bool
13283 FOURCC_cpil -> if media is part of a compilation -> bool
13284 FOURCC_pgap -> if media is part of a gapless context -> bool
13285 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13288 static const struct
13291 const gchar *gst_tag;
13292 const gchar *gst_tag_bis;
13293 const GstQTDemuxAddTagFunc func;
13296 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13297 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13298 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13299 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13300 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13301 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13302 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13303 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13304 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13305 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13306 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13307 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13308 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13309 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13310 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13311 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13312 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13313 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13314 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13315 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13316 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13317 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13318 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13319 qtdemux_tag_add_num}, {
13320 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13321 qtdemux_tag_add_num}, {
13322 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13323 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13324 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13325 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13326 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13327 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13328 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13329 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13330 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13331 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13332 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13333 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13334 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13335 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13336 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13337 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13338 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13339 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13340 qtdemux_tag_add_classification}, {
13341 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13342 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13343 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13345 /* This is a special case, some tags are stored in this
13346 * 'reverse dns naming', according to:
13347 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13350 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13351 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13352 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13355 struct _GstQtDemuxTagList
13358 GstTagList *taglist;
13360 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13363 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13369 const gchar *style;
13374 GstQTDemux *demux = qtdemuxtaglist->demux;
13375 GstTagList *taglist = qtdemuxtaglist->taglist;
13378 len = QT_UINT32 (data);
13379 buf = gst_buffer_new_and_alloc (len);
13380 gst_buffer_fill (buf, 0, data, len);
13382 /* heuristic to determine style of tag */
13383 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13384 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13386 else if (demux->major_brand == FOURCC_qt__)
13387 style = "quicktime";
13388 /* fall back to assuming iso/3gp tag style */
13392 /* santize the name for the caps. */
13393 for (i = 0; i < 4; i++) {
13394 guint8 d = data[4 + i];
13395 if (g_ascii_isalnum (d))
13396 ndata[i] = g_ascii_tolower (d);
13401 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13402 ndata[0], ndata[1], ndata[2], ndata[3]);
13403 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13405 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13406 sample = gst_sample_new (buf, NULL, NULL, s);
13407 gst_buffer_unref (buf);
13408 g_free (media_type);
13410 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13413 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13414 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13416 gst_sample_unref (sample);
13420 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13427 GstQtDemuxTagList demuxtaglist;
13429 demuxtaglist.demux = qtdemux;
13430 demuxtaglist.taglist = taglist;
13432 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13433 if (meta != NULL) {
13434 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13435 if (ilst == NULL) {
13436 GST_LOG_OBJECT (qtdemux, "no ilst");
13441 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13445 while (i < G_N_ELEMENTS (add_funcs)) {
13446 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13450 len = QT_UINT32 (node->data);
13452 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13453 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13455 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13456 add_funcs[i].gst_tag_bis, node);
13458 g_node_destroy (node);
13464 /* parsed nodes have been removed, pass along remainder as blob */
13465 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13466 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13468 /* parse up XMP_ node if existing */
13469 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13470 if (xmp_ != NULL) {
13472 GstTagList *xmptaglist;
13474 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13475 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13476 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13477 gst_buffer_unref (buf);
13479 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13481 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13487 GstStructure *structure; /* helper for sort function */
13489 guint min_req_bitrate;
13490 guint min_req_qt_version;
13494 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13496 GstQtReference *ref_a = (GstQtReference *) a;
13497 GstQtReference *ref_b = (GstQtReference *) b;
13499 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13500 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13502 /* known bitrates go before unknown; higher bitrates go first */
13503 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13506 /* sort the redirects and post a message for the application.
13509 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13511 GstQtReference *best;
13514 GValue list_val = { 0, };
13517 g_assert (references != NULL);
13519 references = g_list_sort (references, qtdemux_redirects_sort_func);
13521 best = (GstQtReference *) references->data;
13523 g_value_init (&list_val, GST_TYPE_LIST);
13525 for (l = references; l != NULL; l = l->next) {
13526 GstQtReference *ref = (GstQtReference *) l->data;
13527 GValue struct_val = { 0, };
13529 ref->structure = gst_structure_new ("redirect",
13530 "new-location", G_TYPE_STRING, ref->location, NULL);
13532 if (ref->min_req_bitrate > 0) {
13533 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13534 ref->min_req_bitrate, NULL);
13537 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13538 g_value_set_boxed (&struct_val, ref->structure);
13539 gst_value_list_append_value (&list_val, &struct_val);
13540 g_value_unset (&struct_val);
13541 /* don't free anything here yet, since we need best->structure below */
13544 g_assert (best != NULL);
13545 s = gst_structure_copy (best->structure);
13547 if (g_list_length (references) > 1) {
13548 gst_structure_set_value (s, "locations", &list_val);
13551 g_value_unset (&list_val);
13553 for (l = references; l != NULL; l = l->next) {
13554 GstQtReference *ref = (GstQtReference *) l->data;
13556 gst_structure_free (ref->structure);
13557 g_free (ref->location);
13560 g_list_free (references);
13562 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13563 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13564 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13565 qtdemux->posted_redirect = TRUE;
13568 /* look for redirect nodes, collect all redirect information and
13572 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13574 GNode *rmra, *rmda, *rdrf;
13576 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13578 GList *redirects = NULL;
13580 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13582 GstQtReference ref = { NULL, NULL, 0, 0 };
13583 GNode *rmdr, *rmvc;
13585 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13586 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13587 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13588 ref.min_req_bitrate);
13591 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13592 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13593 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13595 #ifndef GST_DISABLE_GST_DEBUG
13596 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13598 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13600 GST_LOG_OBJECT (qtdemux,
13601 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13602 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13603 bitmask, check_type);
13604 if (package == FOURCC_qtim && check_type == 0) {
13605 ref.min_req_qt_version = version;
13609 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13615 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13616 if (ref_len > 20) {
13617 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13618 ref_data = (guint8 *) rdrf->data + 20;
13619 if (ref_type == FOURCC_alis) {
13620 guint record_len, record_version, fn_len;
13622 if (ref_len > 70) {
13623 /* MacOSX alias record, google for alias-layout.txt */
13624 record_len = QT_UINT16 (ref_data + 4);
13625 record_version = QT_UINT16 (ref_data + 4 + 2);
13626 fn_len = QT_UINT8 (ref_data + 50);
13627 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13628 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13631 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13634 } else if (ref_type == FOURCC_url_) {
13635 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13637 GST_DEBUG_OBJECT (qtdemux,
13638 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13639 GST_FOURCC_ARGS (ref_type));
13641 if (ref.location != NULL) {
13642 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13644 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13646 GST_WARNING_OBJECT (qtdemux,
13647 "Failed to extract redirect location from rdrf atom");
13650 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13654 /* look for others */
13655 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13658 if (redirects != NULL) {
13659 qtdemux_process_redirects (qtdemux, redirects);
13665 static GstTagList *
13666 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13670 if (tags == NULL) {
13671 tags = gst_tag_list_new_empty ();
13672 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13675 if (qtdemux->major_brand == FOURCC_mjp2)
13676 fmt = "Motion JPEG 2000";
13677 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13679 else if (qtdemux->major_brand == FOURCC_qt__)
13681 else if (qtdemux->fragmented)
13684 fmt = "ISO MP4/M4A";
13686 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13687 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13689 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13695 /* we have read the complete moov node now.
13696 * This function parses all of the relevant info, creates the traks and
13697 * prepares all data structures for playback
13700 qtdemux_parse_tree (GstQTDemux * qtdemux)
13706 GstClockTime duration;
13708 guint64 creation_time;
13709 GstDateTime *datetime = NULL;
13712 /* make sure we have a usable taglist */
13713 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13715 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13716 if (mvhd == NULL) {
13717 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13718 return qtdemux_parse_redirects (qtdemux);
13721 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13722 if (version == 1) {
13723 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13724 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13725 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13726 } else if (version == 0) {
13727 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13728 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13729 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13731 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13735 /* Moving qt creation time (secs since 1904) to unix time */
13736 if (creation_time != 0) {
13737 /* Try to use epoch first as it should be faster and more commonly found */
13738 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13741 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13742 /* some data cleansing sanity */
13743 g_get_current_time (&now);
13744 if (now.tv_sec + 24 * 3600 < creation_time) {
13745 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13747 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13750 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13751 GDateTime *dt, *dt_local;
13753 dt = g_date_time_add_seconds (base_dt, creation_time);
13754 dt_local = g_date_time_to_local (dt);
13755 datetime = gst_date_time_new_from_g_date_time (dt_local);
13757 g_date_time_unref (base_dt);
13758 g_date_time_unref (dt);
13762 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13763 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13765 gst_date_time_unref (datetime);
13768 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13769 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13771 /* check for fragmented file and get some (default) data */
13772 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13775 GstByteReader mehd_data;
13777 /* let track parsing or anyone know weird stuff might happen ... */
13778 qtdemux->fragmented = TRUE;
13780 /* compensate for total duration */
13781 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13783 qtdemux_parse_mehd (qtdemux, &mehd_data);
13786 /* set duration in the segment info */
13787 gst_qtdemux_get_duration (qtdemux, &duration);
13789 qtdemux->segment.duration = duration;
13790 /* also do not exceed duration; stop is set that way post seek anyway,
13791 * and segment activation falls back to duration,
13792 * whereas loop only checks stop, so let's align this here as well */
13793 qtdemux->segment.stop = duration;
13796 /* parse all traks */
13797 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13799 qtdemux_parse_trak (qtdemux, trak);
13800 /* iterate all siblings */
13801 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13804 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13807 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13809 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13811 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13814 /* maybe also some tags in meta box */
13815 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13817 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13818 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13820 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13823 /* parse any protection system info */
13824 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13826 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13827 qtdemux_parse_pssh (qtdemux, pssh);
13828 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13831 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13836 /* taken from ffmpeg */
13838 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13850 len = (len << 7) | (c & 0x7f);
13859 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13860 gsize codec_data_size)
13862 GList *list = NULL;
13863 guint8 *p = codec_data;
13864 gint i, offset, num_packets;
13865 guint *length, last;
13867 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13869 if (codec_data == NULL || codec_data_size == 0)
13872 /* start of the stream and vorbis audio or theora video, need to
13873 * send the codec_priv data as first three packets */
13874 num_packets = p[0] + 1;
13875 GST_DEBUG_OBJECT (qtdemux,
13876 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13877 (guint) num_packets, codec_data_size);
13879 /* Let's put some limits, Don't think there even is a xiph codec
13880 * with more than 3-4 headers */
13881 if (G_UNLIKELY (num_packets > 16)) {
13882 GST_WARNING_OBJECT (qtdemux,
13883 "Unlikely number of xiph headers, most likely not valid");
13887 length = g_alloca (num_packets * sizeof (guint));
13891 /* first packets, read length values */
13892 for (i = 0; i < num_packets - 1; i++) {
13894 while (offset < codec_data_size) {
13895 length[i] += p[offset];
13896 if (p[offset++] != 0xff)
13901 if (offset + last > codec_data_size)
13904 /* last packet is the remaining size */
13905 length[i] = codec_data_size - offset - last;
13907 for (i = 0; i < num_packets; i++) {
13910 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13912 if (offset + length[i] > codec_data_size)
13915 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
13916 list = g_list_append (list, hdr);
13918 offset += length[i];
13927 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13933 /* this can change the codec originally present in @list */
13935 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13936 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13938 int len = QT_UINT32 (esds->data);
13939 guint8 *ptr = esds->data;
13940 guint8 *end = ptr + len;
13942 guint8 *data_ptr = NULL;
13944 guint8 object_type_id = 0;
13945 guint8 stream_type = 0;
13946 const char *codec_name = NULL;
13947 GstCaps *caps = NULL;
13949 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13951 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13953 while (ptr + 1 < end) {
13954 tag = QT_UINT8 (ptr);
13955 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13957 len = read_descr_size (ptr, end, &ptr);
13958 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13960 /* Check the stated amount of data is available for reading */
13961 if (len < 0 || ptr + len > end)
13965 case ES_DESCRIPTOR_TAG:
13966 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13967 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13970 case DECODER_CONFIG_DESC_TAG:{
13971 guint max_bitrate, avg_bitrate;
13973 object_type_id = QT_UINT8 (ptr);
13974 stream_type = QT_UINT8 (ptr + 1) >> 2;
13975 max_bitrate = QT_UINT32 (ptr + 5);
13976 avg_bitrate = QT_UINT32 (ptr + 9);
13977 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13978 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13979 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13980 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13981 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13982 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13983 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13984 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13986 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13987 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13988 avg_bitrate, NULL);
13993 case DECODER_SPECIFIC_INFO_TAG:
13994 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13995 if (object_type_id == 0xe0 && len == 0x40) {
14001 GST_DEBUG_OBJECT (qtdemux,
14002 "Have VOBSUB palette. Creating palette event");
14003 /* move to decConfigDescr data and read palette */
14005 for (i = 0; i < 16; i++) {
14006 clut[i] = QT_UINT32 (data);
14010 s = gst_structure_new ("application/x-gst-dvd", "event",
14011 G_TYPE_STRING, "dvd-spu-clut-change",
14012 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14013 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14014 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14015 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14016 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14017 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14018 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14019 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14022 /* store event and trigger custom processing */
14023 stream->pending_event =
14024 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14026 /* Generic codec_data handler puts it on the caps */
14033 case SL_CONFIG_DESC_TAG:
14034 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14038 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14040 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14046 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14047 * in use, and should also be used to override some other parameters for some
14049 switch (object_type_id) {
14050 case 0x20: /* MPEG-4 */
14051 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14052 * profile_and_level_indication */
14053 if (data_ptr != NULL && data_len >= 5 &&
14054 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14055 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14056 data_ptr + 4, data_len - 4);
14058 break; /* Nothing special needed here */
14059 case 0x21: /* H.264 */
14060 codec_name = "H.264 / AVC";
14061 caps = gst_caps_new_simple ("video/x-h264",
14062 "stream-format", G_TYPE_STRING, "avc",
14063 "alignment", G_TYPE_STRING, "au", NULL);
14065 case 0x40: /* AAC (any) */
14066 case 0x66: /* AAC Main */
14067 case 0x67: /* AAC LC */
14068 case 0x68: /* AAC SSR */
14069 /* Override channels and rate based on the codec_data, as it's often
14071 /* Only do so for basic setup without HE-AAC extension */
14072 if (data_ptr && data_len == 2) {
14073 guint channels, rate;
14075 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14077 entry->n_channels = channels;
14079 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14081 entry->rate = rate;
14084 /* Set level and profile if possible */
14085 if (data_ptr != NULL && data_len >= 2) {
14086 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14087 data_ptr, data_len);
14089 const gchar *profile_str = NULL;
14092 guint8 *codec_data;
14093 gint rate_idx, profile;
14095 /* No codec_data, let's invent something.
14096 * FIXME: This is wrong for SBR! */
14098 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14100 buffer = gst_buffer_new_and_alloc (2);
14101 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14102 codec_data = map.data;
14105 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14108 switch (object_type_id) {
14110 profile_str = "main";
14114 profile_str = "lc";
14118 profile_str = "ssr";
14126 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14128 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14130 gst_buffer_unmap (buffer, &map);
14131 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14132 GST_TYPE_BUFFER, buffer, NULL);
14133 gst_buffer_unref (buffer);
14136 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14137 G_TYPE_STRING, profile_str, NULL);
14141 case 0x60: /* MPEG-2, various profiles */
14147 codec_name = "MPEG-2 video";
14148 caps = gst_caps_new_simple ("video/mpeg",
14149 "mpegversion", G_TYPE_INT, 2,
14150 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14152 case 0x69: /* MPEG-2 BC audio */
14153 case 0x6B: /* MPEG-1 audio */
14154 caps = gst_caps_new_simple ("audio/mpeg",
14155 "mpegversion", G_TYPE_INT, 1, NULL);
14156 codec_name = "MPEG-1 audio";
14158 case 0x6A: /* MPEG-1 */
14159 codec_name = "MPEG-1 video";
14160 caps = gst_caps_new_simple ("video/mpeg",
14161 "mpegversion", G_TYPE_INT, 1,
14162 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14164 case 0x6C: /* MJPEG */
14166 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14168 codec_name = "Motion-JPEG";
14170 case 0x6D: /* PNG */
14172 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14174 codec_name = "PNG still images";
14176 case 0x6E: /* JPEG2000 */
14177 codec_name = "JPEG-2000";
14178 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14180 case 0xA4: /* Dirac */
14181 codec_name = "Dirac";
14182 caps = gst_caps_new_empty_simple ("video/x-dirac");
14184 case 0xA5: /* AC3 */
14185 codec_name = "AC-3 audio";
14186 caps = gst_caps_new_simple ("audio/x-ac3",
14187 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14189 case 0xA9: /* AC3 */
14190 codec_name = "DTS audio";
14191 caps = gst_caps_new_simple ("audio/x-dts",
14192 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14195 if (stream_type == 0x05 && data_ptr) {
14197 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14200 GValue arr_val = G_VALUE_INIT;
14201 GValue buf_val = G_VALUE_INIT;
14204 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14205 codec_name = "Vorbis";
14206 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14207 g_value_init (&arr_val, GST_TYPE_ARRAY);
14208 g_value_init (&buf_val, GST_TYPE_BUFFER);
14209 for (tmp = headers; tmp; tmp = tmp->next) {
14210 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14211 gst_value_array_append_value (&arr_val, &buf_val);
14213 s = gst_caps_get_structure (caps, 0);
14214 gst_structure_take_value (s, "streamheader", &arr_val);
14215 g_value_unset (&buf_val);
14216 g_list_free (headers);
14223 case 0xE1: /* QCELP */
14224 /* QCELP, the codec_data is a riff tag (little endian) with
14225 * 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). */
14226 caps = gst_caps_new_empty_simple ("audio/qcelp");
14227 codec_name = "QCELP";
14233 /* If we have a replacement caps, then change our caps for this stream */
14235 gst_caps_unref (entry->caps);
14236 entry->caps = caps;
14239 if (codec_name && list)
14240 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14241 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14243 /* Add the codec_data attribute to caps, if we have it */
14247 buffer = gst_buffer_new_and_alloc (data_len);
14248 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14250 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14251 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14253 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14255 gst_buffer_unref (buffer);
14260 static inline GstCaps *
14261 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14265 char *s, fourstr[5];
14267 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14268 for (i = 0; i < 4; i++) {
14269 if (!g_ascii_isalnum (fourstr[i]))
14272 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14273 caps = gst_caps_new_empty_simple (s);
14278 #define _codec(name) \
14280 if (codec_name) { \
14281 *codec_name = g_strdup (name); \
14286 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14287 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14288 const guint8 * stsd_entry_data, gchar ** codec_name)
14290 GstCaps *caps = NULL;
14291 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14295 _codec ("PNG still images");
14296 caps = gst_caps_new_empty_simple ("image/png");
14299 _codec ("JPEG still images");
14301 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14304 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14305 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14306 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14307 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14308 _codec ("Motion-JPEG");
14310 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14313 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14314 _codec ("Motion-JPEG format B");
14315 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14318 _codec ("JPEG-2000");
14319 /* override to what it should be according to spec, avoid palette_data */
14320 entry->bits_per_sample = 24;
14321 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14324 _codec ("Sorensen video v.3");
14325 caps = gst_caps_new_simple ("video/x-svq",
14326 "svqversion", G_TYPE_INT, 3, NULL);
14328 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14329 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14330 _codec ("Sorensen video v.1");
14331 caps = gst_caps_new_simple ("video/x-svq",
14332 "svqversion", G_TYPE_INT, 1, NULL);
14334 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14335 caps = gst_caps_new_empty_simple ("video/x-raw");
14336 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14337 _codec ("Windows Raw RGB");
14338 stream->alignment = 32;
14344 bps = QT_UINT16 (stsd_entry_data + 82);
14347 format = GST_VIDEO_FORMAT_RGB15;
14350 format = GST_VIDEO_FORMAT_RGB16;
14353 format = GST_VIDEO_FORMAT_RGB;
14356 format = GST_VIDEO_FORMAT_ARGB;
14364 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14365 format = GST_VIDEO_FORMAT_I420;
14367 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14368 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14369 format = GST_VIDEO_FORMAT_I420;
14372 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14373 format = GST_VIDEO_FORMAT_UYVY;
14375 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14376 format = GST_VIDEO_FORMAT_v308;
14378 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14379 format = GST_VIDEO_FORMAT_v216;
14382 format = GST_VIDEO_FORMAT_v210;
14384 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14385 format = GST_VIDEO_FORMAT_r210;
14387 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14388 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14389 format = GST_VIDEO_FORMAT_v410;
14392 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14393 * but different order than AYUV
14394 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14395 format = GST_VIDEO_FORMAT_v408;
14398 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14399 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14400 _codec ("MPEG-1 video");
14401 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14402 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14404 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14405 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14406 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14407 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14408 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14409 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14410 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14411 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14412 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14413 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14414 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14415 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14416 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14417 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14418 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14419 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14420 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14421 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14422 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14423 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14424 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14425 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14426 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14427 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14428 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14429 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14430 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14431 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14432 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14433 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14434 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14435 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14436 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14437 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14438 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14439 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14440 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14441 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14442 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14443 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14444 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14445 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14446 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14447 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14448 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14449 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14450 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14451 _codec ("MPEG-2 video");
14452 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14453 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14455 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14456 _codec ("GIF still images");
14457 caps = gst_caps_new_empty_simple ("image/gif");
14460 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14462 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14464 /* ffmpeg uses the height/width props, don't know why */
14465 caps = gst_caps_new_simple ("video/x-h263",
14466 "variant", G_TYPE_STRING, "itu", NULL);
14470 _codec ("MPEG-4 video");
14471 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14472 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14474 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14475 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14476 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14477 caps = gst_caps_new_simple ("video/x-msmpeg",
14478 "msmpegversion", G_TYPE_INT, 43, NULL);
14480 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14482 caps = gst_caps_new_simple ("video/x-divx",
14483 "divxversion", G_TYPE_INT, 3, NULL);
14485 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14486 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14488 caps = gst_caps_new_simple ("video/x-divx",
14489 "divxversion", G_TYPE_INT, 4, NULL);
14491 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14493 caps = gst_caps_new_simple ("video/x-divx",
14494 "divxversion", G_TYPE_INT, 5, NULL);
14497 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14499 caps = gst_caps_new_simple ("video/x-ffv",
14500 "ffvversion", G_TYPE_INT, 1, NULL);
14503 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14504 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14509 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14510 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14511 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14515 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14516 _codec ("Cinepak");
14517 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14519 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14520 _codec ("Apple QuickDraw");
14521 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14523 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14524 _codec ("Apple video");
14525 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14529 _codec ("H.264 / AVC");
14530 caps = gst_caps_new_simple ("video/x-h264",
14531 "stream-format", G_TYPE_STRING, "avc",
14532 "alignment", G_TYPE_STRING, "au", NULL);
14535 _codec ("H.264 / AVC");
14536 caps = gst_caps_new_simple ("video/x-h264",
14537 "stream-format", G_TYPE_STRING, "avc3",
14538 "alignment", G_TYPE_STRING, "au", NULL);
14542 _codec ("H.265 / HEVC");
14543 caps = gst_caps_new_simple ("video/x-h265",
14544 "stream-format", G_TYPE_STRING, "hvc1",
14545 "alignment", G_TYPE_STRING, "au", NULL);
14548 _codec ("H.265 / HEVC");
14549 caps = gst_caps_new_simple ("video/x-h265",
14550 "stream-format", G_TYPE_STRING, "hev1",
14551 "alignment", G_TYPE_STRING, "au", NULL);
14554 _codec ("Run-length encoding");
14555 caps = gst_caps_new_simple ("video/x-rle",
14556 "layout", G_TYPE_STRING, "quicktime", NULL);
14559 _codec ("Run-length encoding");
14560 caps = gst_caps_new_simple ("video/x-rle",
14561 "layout", G_TYPE_STRING, "microsoft", NULL);
14563 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14564 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14565 _codec ("Indeo Video 3");
14566 caps = gst_caps_new_simple ("video/x-indeo",
14567 "indeoversion", G_TYPE_INT, 3, NULL);
14569 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14570 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14571 _codec ("Intel Video 4");
14572 caps = gst_caps_new_simple ("video/x-indeo",
14573 "indeoversion", G_TYPE_INT, 4, NULL);
14577 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14578 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14579 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14580 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14581 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14582 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14583 _codec ("DV Video");
14584 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14585 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14587 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14588 case FOURCC_dv5p: /* DVCPRO50 PAL */
14589 _codec ("DVCPro50 Video");
14590 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14591 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14593 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14594 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14595 _codec ("DVCProHD Video");
14596 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14597 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14599 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14600 _codec ("Apple Graphics (SMC)");
14601 caps = gst_caps_new_empty_simple ("video/x-smc");
14603 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14605 caps = gst_caps_new_empty_simple ("video/x-vp3");
14607 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14608 _codec ("VP6 Flash");
14609 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14613 caps = gst_caps_new_empty_simple ("video/x-theora");
14614 /* theora uses one byte of padding in the data stream because it does not
14615 * allow 0 sized packets while theora does */
14616 entry->padding = 1;
14620 caps = gst_caps_new_empty_simple ("video/x-dirac");
14622 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14623 _codec ("TIFF still images");
14624 caps = gst_caps_new_empty_simple ("image/tiff");
14626 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14627 _codec ("Apple Intermediate Codec");
14628 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14630 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14631 _codec ("AVID DNxHD");
14632 caps = gst_caps_from_string ("video/x-dnxhd");
14636 _codec ("On2 VP8");
14637 caps = gst_caps_from_string ("video/x-vp8");
14640 _codec ("Google VP9");
14641 caps = gst_caps_from_string ("video/x-vp9");
14644 _codec ("Apple ProRes LT");
14646 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14650 _codec ("Apple ProRes HQ");
14652 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14656 _codec ("Apple ProRes");
14658 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14662 _codec ("Apple ProRes Proxy");
14664 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14668 _codec ("Apple ProRes 4444");
14670 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14674 _codec ("Apple ProRes 4444 XQ");
14676 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14680 _codec ("GoPro CineForm");
14681 caps = gst_caps_from_string ("video/x-cineform");
14686 caps = gst_caps_new_simple ("video/x-wmv",
14687 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14689 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14692 caps = _get_unknown_codec_name ("video", fourcc);
14697 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14700 gst_video_info_init (&info);
14701 gst_video_info_set_format (&info, format, entry->width, entry->height);
14703 caps = gst_video_info_to_caps (&info);
14704 *codec_name = gst_pb_utils_get_codec_description (caps);
14706 /* enable clipping for raw video streams */
14707 stream->need_clip = TRUE;
14708 stream->alignment = 32;
14715 round_up_pow2 (guint n)
14727 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14728 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14729 int len, gchar ** codec_name)
14732 const GstStructure *s;
14735 GstAudioFormat format = 0;
14738 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14740 depth = entry->bytes_per_packet * 8;
14743 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14745 /* 8-bit audio is unsigned */
14747 format = GST_AUDIO_FORMAT_U8;
14748 /* otherwise it's signed and big-endian just like 'twos' */
14750 endian = G_BIG_ENDIAN;
14757 endian = G_LITTLE_ENDIAN;
14760 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14762 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14766 caps = gst_caps_new_simple ("audio/x-raw",
14767 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14768 "layout", G_TYPE_STRING, "interleaved", NULL);
14769 stream->alignment = GST_ROUND_UP_8 (depth);
14770 stream->alignment = round_up_pow2 (stream->alignment);
14773 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14774 _codec ("Raw 64-bit floating-point audio");
14775 caps = gst_caps_new_simple ("audio/x-raw",
14776 "format", G_TYPE_STRING, "F64BE",
14777 "layout", G_TYPE_STRING, "interleaved", NULL);
14778 stream->alignment = 8;
14780 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14781 _codec ("Raw 32-bit floating-point audio");
14782 caps = gst_caps_new_simple ("audio/x-raw",
14783 "format", G_TYPE_STRING, "F32BE",
14784 "layout", G_TYPE_STRING, "interleaved", NULL);
14785 stream->alignment = 4;
14788 _codec ("Raw 24-bit PCM audio");
14789 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14791 caps = gst_caps_new_simple ("audio/x-raw",
14792 "format", G_TYPE_STRING, "S24BE",
14793 "layout", G_TYPE_STRING, "interleaved", NULL);
14794 stream->alignment = 4;
14796 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14797 _codec ("Raw 32-bit PCM audio");
14798 caps = gst_caps_new_simple ("audio/x-raw",
14799 "format", G_TYPE_STRING, "S32BE",
14800 "layout", G_TYPE_STRING, "interleaved", NULL);
14801 stream->alignment = 4;
14803 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14804 _codec ("Raw 16-bit PCM audio");
14805 caps = gst_caps_new_simple ("audio/x-raw",
14806 "format", G_TYPE_STRING, "S16LE",
14807 "layout", G_TYPE_STRING, "interleaved", NULL);
14808 stream->alignment = 2;
14811 _codec ("Mu-law audio");
14812 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14815 _codec ("A-law audio");
14816 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14820 _codec ("Microsoft ADPCM");
14821 /* Microsoft ADPCM-ACM code 2 */
14822 caps = gst_caps_new_simple ("audio/x-adpcm",
14823 "layout", G_TYPE_STRING, "microsoft", NULL);
14827 _codec ("DVI/IMA ADPCM");
14828 caps = gst_caps_new_simple ("audio/x-adpcm",
14829 "layout", G_TYPE_STRING, "dvi", NULL);
14833 _codec ("DVI/Intel IMA ADPCM");
14834 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14835 caps = gst_caps_new_simple ("audio/x-adpcm",
14836 "layout", G_TYPE_STRING, "quicktime", NULL);
14840 /* MPEG layer 3, CBR only (pre QT4.1) */
14842 _codec ("MPEG-1 layer 3");
14843 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14844 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14845 "mpegversion", G_TYPE_INT, 1, NULL);
14847 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14848 _codec ("MPEG-1 layer 2");
14850 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14851 "mpegversion", G_TYPE_INT, 1, NULL);
14854 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14855 _codec ("EAC-3 audio");
14856 caps = gst_caps_new_simple ("audio/x-eac3",
14857 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14858 entry->sampled = TRUE;
14860 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14862 _codec ("AC-3 audio");
14863 caps = gst_caps_new_simple ("audio/x-ac3",
14864 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14865 entry->sampled = TRUE;
14867 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14868 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14869 _codec ("DTS audio");
14870 caps = gst_caps_new_simple ("audio/x-dts",
14871 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14872 entry->sampled = TRUE;
14874 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14875 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14876 _codec ("DTS-HD audio");
14877 caps = gst_caps_new_simple ("audio/x-dts",
14878 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14879 entry->sampled = TRUE;
14883 caps = gst_caps_new_simple ("audio/x-mace",
14884 "maceversion", G_TYPE_INT, 3, NULL);
14888 caps = gst_caps_new_simple ("audio/x-mace",
14889 "maceversion", G_TYPE_INT, 6, NULL);
14891 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14893 caps = gst_caps_new_empty_simple ("application/ogg");
14895 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14896 _codec ("DV audio");
14897 caps = gst_caps_new_empty_simple ("audio/x-dv");
14900 _codec ("MPEG-4 AAC audio");
14901 caps = gst_caps_new_simple ("audio/mpeg",
14902 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14903 "stream-format", G_TYPE_STRING, "raw", NULL);
14905 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14906 _codec ("QDesign Music");
14907 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14910 _codec ("QDesign Music v.2");
14911 /* FIXME: QDesign music version 2 (no constant) */
14912 if (FALSE && data) {
14913 caps = gst_caps_new_simple ("audio/x-qdm2",
14914 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14915 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14916 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14918 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14922 _codec ("GSM audio");
14923 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14926 _codec ("AMR audio");
14927 caps = gst_caps_new_empty_simple ("audio/AMR");
14930 _codec ("AMR-WB audio");
14931 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14934 _codec ("Quicktime IMA ADPCM");
14935 caps = gst_caps_new_simple ("audio/x-adpcm",
14936 "layout", G_TYPE_STRING, "quicktime", NULL);
14939 _codec ("Apple lossless audio");
14940 caps = gst_caps_new_empty_simple ("audio/x-alac");
14943 _codec ("Free Lossless Audio Codec");
14944 caps = gst_caps_new_simple ("audio/x-flac",
14945 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14947 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14948 _codec ("QualComm PureVoice");
14949 caps = gst_caps_from_string ("audio/qcelp");
14954 caps = gst_caps_new_empty_simple ("audio/x-wma");
14958 caps = gst_caps_new_empty_simple ("audio/x-opus");
14965 GstAudioFormat format;
14968 FLAG_IS_FLOAT = 0x1,
14969 FLAG_IS_BIG_ENDIAN = 0x2,
14970 FLAG_IS_SIGNED = 0x4,
14971 FLAG_IS_PACKED = 0x8,
14972 FLAG_IS_ALIGNED_HIGH = 0x10,
14973 FLAG_IS_NON_INTERLEAVED = 0x20
14975 _codec ("Raw LPCM audio");
14977 if (data && len >= 36) {
14978 depth = QT_UINT32 (data + 24);
14979 flags = QT_UINT32 (data + 28);
14980 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14982 if ((flags & FLAG_IS_FLOAT) == 0) {
14987 if ((flags & FLAG_IS_ALIGNED_HIGH))
14990 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14991 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14992 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14993 caps = gst_caps_new_simple ("audio/x-raw",
14994 "format", G_TYPE_STRING,
14996 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14997 "UNKNOWN", "layout", G_TYPE_STRING,
14998 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14999 "interleaved", NULL);
15000 stream->alignment = GST_ROUND_UP_8 (depth);
15001 stream->alignment = round_up_pow2 (stream->alignment);
15006 if (flags & FLAG_IS_BIG_ENDIAN)
15007 format = GST_AUDIO_FORMAT_F64BE;
15009 format = GST_AUDIO_FORMAT_F64LE;
15011 if (flags & FLAG_IS_BIG_ENDIAN)
15012 format = GST_AUDIO_FORMAT_F32BE;
15014 format = GST_AUDIO_FORMAT_F32LE;
15016 caps = gst_caps_new_simple ("audio/x-raw",
15017 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15018 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15019 "non-interleaved" : "interleaved", NULL);
15020 stream->alignment = width / 8;
15024 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15028 caps = _get_unknown_codec_name ("audio", fourcc);
15034 GstCaps *templ_caps =
15035 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15036 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15037 gst_caps_unref (caps);
15038 gst_caps_unref (templ_caps);
15039 caps = intersection;
15042 /* enable clipping for raw audio streams */
15043 s = gst_caps_get_structure (caps, 0);
15044 name = gst_structure_get_name (s);
15045 if (g_str_has_prefix (name, "audio/x-raw")) {
15046 stream->need_clip = TRUE;
15047 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15048 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15054 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15055 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15056 const guint8 * stsd_entry_data, gchar ** codec_name)
15060 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15064 _codec ("DVD subtitle");
15065 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15066 stream->need_process = TRUE;
15069 _codec ("Quicktime timed text");
15072 _codec ("3GPP timed text");
15074 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15076 /* actual text piece needs to be extracted */
15077 stream->need_process = TRUE;
15080 _codec ("XML subtitles");
15081 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15084 _codec ("CEA 608 Closed Caption");
15086 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15087 G_TYPE_STRING, "cc_data", NULL);
15088 stream->need_process = TRUE;
15091 _codec ("CEA 708 Closed Caption");
15093 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15094 G_TYPE_STRING, "cdp", NULL);
15095 stream->need_process = TRUE;
15100 caps = _get_unknown_codec_name ("text", fourcc);
15108 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15109 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15110 const guint8 * stsd_entry_data, gchar ** codec_name)
15116 _codec ("MPEG 1 video");
15117 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15118 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15128 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15129 const gchar * system_id)
15133 if (!qtdemux->protection_system_ids)
15134 qtdemux->protection_system_ids =
15135 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15136 /* Check whether we already have an entry for this system ID. */
15137 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15138 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15139 if (g_ascii_strcasecmp (system_id, id) == 0) {
15143 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15144 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,