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 GstClockTime min_ts;
1042 GstEvent *newsegment;
1044 if (!gst_qtdemux_streams_have_samples (qtdemux)) {
1045 /* No samples yet, can't decide on segment.start */
1046 GST_DEBUG_OBJECT (qtdemux, "No samples yet, postponing segment event");
1050 min_ts = gst_qtdemux_streams_get_first_sample_ts (qtdemux);
1052 /* have_samples() above should guarantee we have a valid time */
1053 g_assert (GST_CLOCK_TIME_IS_VALID (min_ts));
1055 qtdemux->segment.start = min_ts;
1056 newsegment = gst_event_new_segment (&qtdemux->segment);
1057 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
1058 gst_event_set_seqnum (newsegment, qtdemux->segment_seqnum);
1059 qtdemux->need_segment = FALSE;
1060 gst_qtdemux_push_event (qtdemux, newsegment);
1070 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1072 if ((gint64) s1->timestamp > *media_time)
1074 if ((gint64) s1->timestamp == *media_time)
1080 /* find the index of the sample that includes the data for @media_time using a
1081 * binary search. Only to be called in optimized cases of linear search below.
1083 * Returns the index of the sample with the corresponding *DTS*.
1086 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1089 QtDemuxSample *result;
1092 /* convert media_time to mov format */
1094 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1096 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1097 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1098 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1100 if (G_LIKELY (result))
1101 index = result - str->samples;
1110 /* find the index of the sample that includes the data for @media_offset using a
1113 * Returns the index of the sample.
1116 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1117 QtDemuxStream * str, gint64 media_offset)
1119 QtDemuxSample *result = str->samples;
1122 if (result == NULL || str->n_samples == 0)
1125 if (media_offset == result->offset)
1129 while (index < str->n_samples - 1) {
1130 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1133 if (media_offset < result->offset)
1144 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1149 /* find the index of the sample that includes the data for @media_time using a
1150 * linear search, and keeping in mind that not all samples may have been parsed
1151 * yet. If possible, it will delegate to binary search.
1153 * Returns the index of the sample.
1156 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1157 GstClockTime media_time)
1161 QtDemuxSample *sample;
1163 /* convert media_time to mov format */
1165 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1167 sample = str->samples;
1168 if (mov_time == sample->timestamp + sample->pts_offset)
1171 /* use faster search if requested time in already parsed range */
1172 sample = str->samples + str->stbl_index;
1173 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1174 index = gst_qtdemux_find_index (qtdemux, str, media_time);
1175 sample = str->samples + index;
1177 while (index < str->n_samples - 1) {
1178 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1181 sample = str->samples + index + 1;
1182 if (mov_time < sample->timestamp) {
1183 sample = str->samples + index;
1191 /* sample->timestamp is now <= media_time, need to find the corresponding
1192 * PTS now by looking backwards */
1193 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1195 sample = str->samples + index;
1203 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1208 /* find the index of the keyframe needed to decode the sample at @index
1209 * of stream @str, or of a subsequent keyframe (depending on @next)
1211 * Returns the index of the keyframe.
1214 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1215 guint32 index, gboolean next)
1217 guint32 new_index = index;
1219 if (index >= str->n_samples) {
1220 new_index = str->n_samples;
1224 /* all keyframes, return index */
1225 if (str->all_keyframe) {
1230 /* else search until we have a keyframe */
1231 while (new_index < str->n_samples) {
1232 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1235 if (str->samples[new_index].keyframe)
1247 if (new_index == str->n_samples) {
1248 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1253 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1254 "gave %u", next ? "after" : "before", index, new_index);
1261 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1266 /* find the segment for @time_position for @stream
1268 * Returns the index of the segment containing @time_position.
1269 * Returns the last segment and sets the @eos variable to TRUE
1270 * if the time is beyond the end. @eos may be NULL
1273 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1274 GstClockTime time_position)
1279 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1280 GST_TIME_ARGS (time_position));
1283 for (i = 0; i < stream->n_segments; i++) {
1284 QtDemuxSegment *segment = &stream->segments[i];
1286 GST_LOG_OBJECT (stream->pad,
1287 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1288 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1290 /* For the last segment we include stop_time in the last segment */
1291 if (i < stream->n_segments - 1) {
1292 if (segment->time <= time_position && time_position < segment->stop_time) {
1293 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1298 /* Last segment always matches */
1306 /* move the stream @str to the sample position @index.
1308 * Updates @str->sample_index and marks discontinuity if needed.
1311 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1314 /* no change needed */
1315 if (index == str->sample_index)
1318 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1321 /* position changed, we have a discont */
1322 str->sample_index = index;
1323 str->offset_in_sample = 0;
1324 /* Each time we move in the stream we store the position where we are
1326 str->from_sample = index;
1327 str->discont = TRUE;
1331 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1332 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1335 gint64 min_byte_offset = -1;
1338 min_offset = desired_time;
1340 /* for each stream, find the index of the sample in the segment
1341 * and move back to the previous keyframe. */
1342 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1344 guint32 index, kindex;
1346 GstClockTime media_start;
1347 GstClockTime media_time;
1348 GstClockTime seg_time;
1349 QtDemuxSegment *seg;
1350 gboolean empty_segment = FALSE;
1352 str = QTDEMUX_STREAM (iter->data);
1354 if (CUR_STREAM (str)->sparse && !use_sparse)
1357 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1358 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1360 /* get segment and time in the segment */
1361 seg = &str->segments[seg_idx];
1362 seg_time = (desired_time - seg->time) * seg->rate;
1364 while (QTSEGMENT_IS_EMPTY (seg)) {
1366 empty_segment = TRUE;
1367 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1370 if (seg_idx == str->n_segments)
1372 seg = &str->segments[seg_idx];
1375 if (seg_idx == str->n_segments) {
1376 /* FIXME track shouldn't have the last segment as empty, but if it
1377 * happens we better handle it */
1381 /* get the media time in the segment */
1382 media_start = seg->media_start + seg_time;
1384 /* get the index of the sample with media time */
1385 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1386 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1387 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1388 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1391 /* shift to next frame if we are looking for next keyframe */
1392 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1393 && index < str->stbl_index)
1396 if (!empty_segment) {
1397 /* find previous keyframe */
1398 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1400 /* we will settle for one before if none found after */
1401 if (next && kindex == -1)
1402 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1404 /* if the keyframe is at a different position, we need to update the
1405 * requested seek time */
1406 if (index != kindex) {
1409 /* get timestamp of keyframe */
1410 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1411 GST_DEBUG_OBJECT (qtdemux,
1412 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1413 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1414 str->samples[kindex].offset);
1416 /* keyframes in the segment get a chance to change the
1417 * desired_offset. keyframes out of the segment are
1419 if (media_time >= seg->media_start) {
1420 GstClockTime seg_time;
1422 /* this keyframe is inside the segment, convert back to
1424 seg_time = (media_time - seg->media_start) + seg->time;
1425 if ((!next && (seg_time < min_offset)) ||
1426 (next && (seg_time > min_offset)))
1427 min_offset = seg_time;
1432 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1433 min_byte_offset = str->samples[index].offset;
1437 *key_time = min_offset;
1439 *key_offset = min_byte_offset;
1443 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1444 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1448 g_return_val_if_fail (format != NULL, FALSE);
1449 g_return_val_if_fail (cur != NULL, FALSE);
1450 g_return_val_if_fail (stop != NULL, FALSE);
1452 if (*format == GST_FORMAT_TIME)
1456 if (cur_type != GST_SEEK_TYPE_NONE)
1457 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1458 if (res && stop_type != GST_SEEK_TYPE_NONE)
1459 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1462 *format = GST_FORMAT_TIME;
1467 /* perform seek in push based mode:
1468 find BYTE position to move to based on time and delegate to upstream
1471 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1476 GstSeekType cur_type, stop_type;
1477 gint64 cur, stop, key_cur;
1480 gint64 original_stop;
1483 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1485 gst_event_parse_seek (event, &rate, &format, &flags,
1486 &cur_type, &cur, &stop_type, &stop);
1487 seqnum = gst_event_get_seqnum (event);
1489 /* only forward streaming and seeking is possible */
1491 goto unsupported_seek;
1493 /* convert to TIME if needed and possible */
1494 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1498 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1499 * the original stop position to use when upstream pushes the new segment
1501 original_stop = stop;
1504 /* find reasonable corresponding BYTE position,
1505 * also try to mind about keyframes, since we can not go back a bit for them
1507 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1508 * mostly just work, but let's not yet boldly go there ... */
1509 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1514 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1515 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1518 GST_OBJECT_LOCK (qtdemux);
1519 qtdemux->seek_offset = byte_cur;
1520 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1521 qtdemux->push_seek_start = cur;
1523 qtdemux->push_seek_start = key_cur;
1526 if (stop_type == GST_SEEK_TYPE_NONE) {
1527 qtdemux->push_seek_stop = qtdemux->segment.stop;
1529 qtdemux->push_seek_stop = original_stop;
1531 GST_OBJECT_UNLOCK (qtdemux);
1533 /* BYTE seek event */
1534 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1536 gst_event_set_seqnum (event, seqnum);
1537 res = gst_pad_push_event (qtdemux->sinkpad, event);
1544 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1550 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1555 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1560 /* perform the seek.
1562 * We set all segment_indexes in the streams to unknown and
1563 * adjust the time_position to the desired position. this is enough
1564 * to trigger a segment switch in the streaming thread to start
1565 * streaming from the desired position.
1567 * Keyframe seeking is a little more complicated when dealing with
1568 * segments. Ideally we want to move to the previous keyframe in
1569 * the segment but there might not be a keyframe in the segment. In
1570 * fact, none of the segments could contain a keyframe. We take a
1571 * practical approach: seek to the previous keyframe in the segment,
1572 * if there is none, seek to the beginning of the segment.
1574 * Called with STREAM_LOCK
1577 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1578 guint32 seqnum, GstSeekFlags flags)
1580 gint64 desired_offset;
1583 desired_offset = segment->position;
1585 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1586 GST_TIME_ARGS (desired_offset));
1588 /* may not have enough fragmented info to do this adjustment,
1589 * and we can't scan (and probably should not) at this time with
1590 * possibly flushing upstream */
1591 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1593 gboolean next, before, after;
1595 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1596 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1597 next = after && !before;
1598 if (segment->rate < 0)
1601 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1603 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1604 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1605 desired_offset = min_offset;
1608 /* and set all streams to the final position */
1609 gst_flow_combiner_reset (qtdemux->flowcombiner);
1610 qtdemux->segment_seqnum = seqnum;
1611 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1612 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1614 stream->time_position = desired_offset;
1615 stream->accumulated_base = 0;
1616 stream->sample_index = -1;
1617 stream->offset_in_sample = 0;
1618 stream->segment_index = -1;
1619 stream->sent_eos = FALSE;
1621 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1622 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1624 segment->position = desired_offset;
1625 segment->time = desired_offset;
1626 if (segment->rate >= 0) {
1627 segment->start = desired_offset;
1629 /* we stop at the end */
1630 if (segment->stop == -1)
1631 segment->stop = segment->duration;
1633 segment->stop = desired_offset;
1636 if (qtdemux->fragmented)
1637 qtdemux->fragmented_seek_pending = TRUE;
1642 /* do a seek in pull based mode */
1644 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1649 GstSeekType cur_type, stop_type;
1653 GstSegment seeksegment;
1654 guint32 seqnum = GST_SEQNUM_INVALID;
1655 GstEvent *flush_event;
1659 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1661 gst_event_parse_seek (event, &rate, &format, &flags,
1662 &cur_type, &cur, &stop_type, &stop);
1663 seqnum = gst_event_get_seqnum (event);
1665 /* we have to have a format as the segment format. Try to convert
1667 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1671 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1673 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1677 flush = flags & GST_SEEK_FLAG_FLUSH;
1679 /* stop streaming, either by flushing or by pausing the task */
1681 flush_event = gst_event_new_flush_start ();
1682 if (seqnum != GST_SEQNUM_INVALID)
1683 gst_event_set_seqnum (flush_event, seqnum);
1684 /* unlock upstream pull_range */
1685 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1686 /* make sure out loop function exits */
1687 gst_qtdemux_push_event (qtdemux, flush_event);
1689 /* non flushing seek, pause the task */
1690 gst_pad_pause_task (qtdemux->sinkpad);
1693 /* wait for streaming to finish */
1694 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1696 /* copy segment, we need this because we still need the old
1697 * segment when we close the current segment. */
1698 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1701 /* configure the segment with the seek variables */
1702 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1703 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1704 cur_type, cur, stop_type, stop, &update)) {
1706 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1708 /* now do the seek */
1709 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1712 /* now do the seek */
1713 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1716 /* prepare for streaming again */
1718 flush_event = gst_event_new_flush_stop (TRUE);
1719 if (seqnum != GST_SEQNUM_INVALID)
1720 gst_event_set_seqnum (flush_event, seqnum);
1722 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1723 gst_qtdemux_push_event (qtdemux, flush_event);
1726 /* commit the new segment */
1727 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1729 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1730 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1731 qtdemux->segment.format, qtdemux->segment.position);
1732 if (seqnum != GST_SEQNUM_INVALID)
1733 gst_message_set_seqnum (msg, seqnum);
1734 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1737 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1738 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1739 qtdemux->sinkpad, NULL);
1741 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1748 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1754 qtdemux_ensure_index (GstQTDemux * qtdemux)
1758 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1760 /* Build complete index */
1761 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1762 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
1764 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1765 GST_LOG_OBJECT (qtdemux,
1766 "Building complete index of track-id %u for seeking failed!",
1776 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1779 gboolean res = TRUE;
1780 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1782 switch (GST_EVENT_TYPE (event)) {
1783 case GST_EVENT_SEEK:
1785 #ifndef GST_DISABLE_GST_DEBUG
1786 GstClockTime ts = gst_util_get_timestamp ();
1788 guint32 seqnum = gst_event_get_seqnum (event);
1790 if (seqnum == qtdemux->segment_seqnum) {
1791 GST_LOG_OBJECT (pad,
1792 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1793 gst_event_unref (event);
1797 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1798 /* seek should be handled by upstream, we might need to re-download fragments */
1799 GST_DEBUG_OBJECT (qtdemux,
1800 "let upstream handle seek for fragmented playback");
1804 /* Build complete index for seeking;
1805 * if not a fragmented file at least */
1806 if (!qtdemux->fragmented)
1807 if (!qtdemux_ensure_index (qtdemux))
1809 #ifndef GST_DISABLE_GST_DEBUG
1810 ts = gst_util_get_timestamp () - ts;
1811 GST_INFO_OBJECT (qtdemux,
1812 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1815 if (qtdemux->pullbased) {
1816 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1817 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1818 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1820 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1821 && !qtdemux->fragmented) {
1822 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1824 GST_DEBUG_OBJECT (qtdemux,
1825 "ignoring seek in push mode in current state");
1828 gst_event_unref (event);
1832 res = gst_pad_event_default (pad, parent, event);
1842 GST_ERROR_OBJECT (qtdemux, "Index failed");
1843 gst_event_unref (event);
1849 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1851 * If @fw is false, the coding order is explored backwards.
1853 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1854 * sample is found for that track.
1856 * The stream and sample index of the sample with the minimum offset in the direction explored
1857 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1859 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1860 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1861 * @_stream and @_index. */
1863 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1864 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1867 gint64 time, min_time;
1868 QtDemuxStream *stream;
1875 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
1878 gboolean set_sample;
1880 str = QTDEMUX_STREAM (iter->data);
1887 i = str->n_samples - 1;
1891 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1892 if (str->samples[i].size == 0)
1895 if (fw && (str->samples[i].offset < byte_pos))
1898 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1901 /* move stream to first available sample */
1903 gst_qtdemux_move_stream (qtdemux, str, i);
1907 /* avoid index from sparse streams since they might be far away */
1908 if (!CUR_STREAM (str)->sparse) {
1909 /* determine min/max time */
1910 time = QTSAMPLE_PTS (str, &str->samples[i]);
1911 if (min_time == -1 || (!fw && time > min_time) ||
1912 (fw && time < min_time)) {
1916 /* determine stream with leading sample, to get its position */
1918 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1919 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1927 /* no sample for this stream, mark eos */
1929 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1940 /* Copied from mpegtsbase code */
1941 /* FIXME: replace this function when we add new util function for stream-id creation */
1943 _get_upstream_id (GstQTDemux * demux)
1945 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1948 /* Try to create one from the upstream URI, else use a randome number */
1952 /* Try to generate one from the URI query and
1953 * if it fails take a random number instead */
1954 query = gst_query_new_uri ();
1955 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1956 gst_query_parse_uri (query, &uri);
1962 /* And then generate an SHA256 sum of the URI */
1963 cs = g_checksum_new (G_CHECKSUM_SHA256);
1964 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1966 upstream_id = g_strdup (g_checksum_get_string (cs));
1967 g_checksum_free (cs);
1969 /* Just get some random number if the URI query fails */
1970 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1971 "implementing a deterministic way of creating a stream-id");
1973 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1974 g_random_int (), g_random_int ());
1977 gst_query_unref (query);
1982 static QtDemuxStream *
1983 _create_stream (GstQTDemux * demux, guint32 track_id)
1985 QtDemuxStream *stream;
1988 stream = g_new0 (QtDemuxStream, 1);
1989 stream->demux = demux;
1990 stream->track_id = track_id;
1991 upstream_id = _get_upstream_id (demux);
1992 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1993 g_free (upstream_id);
1994 /* new streams always need a discont */
1995 stream->discont = TRUE;
1996 /* we enable clipping for raw audio/video streams */
1997 stream->need_clip = FALSE;
1998 stream->need_process = FALSE;
1999 stream->segment_index = -1;
2000 stream->time_position = 0;
2001 stream->sample_index = -1;
2002 stream->offset_in_sample = 0;
2003 stream->new_stream = TRUE;
2004 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2005 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2006 stream->protected = FALSE;
2007 stream->protection_scheme_type = 0;
2008 stream->protection_scheme_version = 0;
2009 stream->protection_scheme_info = NULL;
2010 stream->n_samples_moof = 0;
2011 stream->duration_moof = 0;
2012 stream->duration_last_moof = 0;
2013 stream->alignment = 1;
2014 stream->stream_tags = gst_tag_list_new_empty ();
2015 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2016 g_queue_init (&stream->protection_scheme_event_queue);
2021 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2023 GstStructure *structure;
2024 const gchar *variant;
2025 const GstCaps *mediacaps = NULL;
2027 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2029 structure = gst_caps_get_structure (caps, 0);
2030 variant = gst_structure_get_string (structure, "variant");
2032 if (variant && strcmp (variant, "mss-fragmented") == 0) {
2033 QtDemuxStream *stream;
2034 const GValue *value;
2036 demux->fragmented = TRUE;
2037 demux->mss_mode = TRUE;
2039 if (demux->n_streams > 1) {
2040 /* can't do this, we can only renegotiate for another mss format */
2044 value = gst_structure_get_value (structure, "media-caps");
2047 const GValue *timescale_v;
2049 /* TODO update when stream changes during playback */
2051 if (demux->n_streams == 0) {
2052 stream = _create_stream (demux, 1);
2053 demux->active_streams = g_list_append (demux->active_streams, stream);
2054 demux->n_streams = 1;
2055 /* mss has no stsd/stsd entry, use id 0 as default */
2056 stream->stsd_entries_length = 1;
2057 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2058 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2060 stream = QTDEMUX_FIRST_STREAM (demux);
2063 timescale_v = gst_structure_get_value (structure, "timescale");
2065 stream->timescale = g_value_get_uint64 (timescale_v);
2067 /* default mss timescale */
2068 stream->timescale = 10000000;
2070 demux->timescale = stream->timescale;
2072 mediacaps = gst_value_get_caps (value);
2073 if (!CUR_STREAM (stream)->caps
2074 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2075 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2077 stream->new_caps = TRUE;
2079 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2080 structure = gst_caps_get_structure (mediacaps, 0);
2081 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2082 stream->subtype = FOURCC_vide;
2084 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2085 gst_structure_get_int (structure, "height",
2086 &CUR_STREAM (stream)->height);
2087 gst_structure_get_fraction (structure, "framerate",
2088 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2089 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2091 stream->subtype = FOURCC_soun;
2092 gst_structure_get_int (structure, "channels",
2093 &CUR_STREAM (stream)->n_channels);
2094 gst_structure_get_int (structure, "rate", &rate);
2095 CUR_STREAM (stream)->rate = rate;
2098 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2100 demux->mss_mode = FALSE;
2107 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2111 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2112 gst_pad_stop_task (qtdemux->sinkpad);
2114 if (hard || qtdemux->upstream_format_is_time) {
2115 qtdemux->state = QTDEMUX_STATE_INITIAL;
2116 qtdemux->neededbytes = 16;
2117 qtdemux->todrop = 0;
2118 qtdemux->pullbased = FALSE;
2119 qtdemux->posted_redirect = FALSE;
2120 qtdemux->first_mdat = -1;
2121 qtdemux->header_size = 0;
2122 qtdemux->mdatoffset = -1;
2123 qtdemux->restoredata_offset = -1;
2124 if (qtdemux->mdatbuffer)
2125 gst_buffer_unref (qtdemux->mdatbuffer);
2126 if (qtdemux->restoredata_buffer)
2127 gst_buffer_unref (qtdemux->restoredata_buffer);
2128 qtdemux->mdatbuffer = NULL;
2129 qtdemux->restoredata_buffer = NULL;
2130 qtdemux->mdatleft = 0;
2131 qtdemux->mdatsize = 0;
2132 if (qtdemux->comp_brands)
2133 gst_buffer_unref (qtdemux->comp_brands);
2134 qtdemux->comp_brands = NULL;
2135 qtdemux->last_moov_offset = -1;
2136 if (qtdemux->moov_node_compressed) {
2137 g_node_destroy (qtdemux->moov_node_compressed);
2138 if (qtdemux->moov_node)
2139 g_free (qtdemux->moov_node->data);
2141 qtdemux->moov_node_compressed = NULL;
2142 if (qtdemux->moov_node)
2143 g_node_destroy (qtdemux->moov_node);
2144 qtdemux->moov_node = NULL;
2145 if (qtdemux->tag_list)
2146 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2147 qtdemux->tag_list = gst_tag_list_new_empty ();
2148 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2150 if (qtdemux->element_index)
2151 gst_object_unref (qtdemux->element_index);
2152 qtdemux->element_index = NULL;
2154 qtdemux->major_brand = 0;
2155 qtdemux->upstream_format_is_time = FALSE;
2156 qtdemux->upstream_seekable = FALSE;
2157 qtdemux->upstream_size = 0;
2159 qtdemux->fragment_start = -1;
2160 qtdemux->fragment_start_offset = -1;
2161 qtdemux->duration = 0;
2162 qtdemux->moof_offset = 0;
2163 qtdemux->chapters_track_id = 0;
2164 qtdemux->have_group_id = FALSE;
2165 qtdemux->group_id = G_MAXUINT;
2167 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2169 g_queue_clear (&qtdemux->protection_event_queue);
2171 qtdemux->offset = 0;
2172 gst_adapter_clear (qtdemux->adapter);
2173 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2174 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2175 qtdemux->need_segment = TRUE;
2178 g_list_free_full (qtdemux->active_streams,
2179 (GDestroyNotify) gst_qtdemux_stream_free);
2180 g_list_free_full (qtdemux->old_streams,
2181 (GDestroyNotify) gst_qtdemux_stream_free);
2182 qtdemux->active_streams = NULL;
2183 qtdemux->old_streams = NULL;
2184 qtdemux->n_streams = 0;
2185 qtdemux->n_video_streams = 0;
2186 qtdemux->n_audio_streams = 0;
2187 qtdemux->n_sub_streams = 0;
2188 qtdemux->exposed = FALSE;
2189 qtdemux->fragmented = FALSE;
2190 qtdemux->mss_mode = FALSE;
2191 gst_caps_replace (&qtdemux->media_caps, NULL);
2192 qtdemux->timescale = 0;
2193 qtdemux->got_moov = FALSE;
2194 qtdemux->cenc_aux_info_offset = 0;
2195 qtdemux->cenc_aux_info_sizes = NULL;
2196 qtdemux->cenc_aux_sample_count = 0;
2197 if (qtdemux->protection_system_ids) {
2198 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2199 qtdemux->protection_system_ids = NULL;
2201 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2202 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2203 GST_BIN_FLAG_STREAMS_AWARE);
2205 if (qtdemux->preferred_protection_system_id) {
2206 g_free (qtdemux->preferred_protection_system_id);
2207 qtdemux->preferred_protection_system_id = NULL;
2209 } else if (qtdemux->mss_mode) {
2210 gst_flow_combiner_reset (qtdemux->flowcombiner);
2211 g_list_foreach (qtdemux->active_streams,
2212 (GFunc) gst_qtdemux_stream_clear, NULL);
2214 gst_flow_combiner_reset (qtdemux->flowcombiner);
2215 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2216 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2217 stream->sent_eos = FALSE;
2218 stream->time_position = 0;
2219 stream->accumulated_base = 0;
2225 /* Maps the @segment to the qt edts internal segments and pushes
2226 * the correspnding segment event.
2228 * If it ends up being at a empty segment, a gap will be pushed and the next
2229 * edts segment will be activated in sequence.
2231 * To be used in push-mode only */
2233 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2238 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
2239 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
2241 stream->time_position = segment->start;
2243 /* in push mode we should be guaranteed that we will have empty segments
2244 * at the beginning and then one segment after, other scenarios are not
2245 * supported and are discarded when parsing the edts */
2246 for (i = 0; i < stream->n_segments; i++) {
2247 if (stream->segments[i].stop_time > segment->start) {
2248 /* push the empty segment and move to the next one */
2249 gst_qtdemux_activate_segment (qtdemux, stream, i,
2250 stream->time_position);
2251 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2252 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2253 stream->time_position);
2255 /* accumulate previous segments */
2256 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2257 stream->accumulated_base +=
2258 (stream->segment.stop -
2259 stream->segment.start) / ABS (stream->segment.rate);
2263 g_assert (i == stream->n_segments - 1);
2270 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2273 GstQTDemux *demux = GST_QTDEMUX (parent);
2274 gboolean res = TRUE;
2276 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2278 switch (GST_EVENT_TYPE (event)) {
2279 case GST_EVENT_SEGMENT:
2282 QtDemuxStream *stream;
2286 /* some debug output */
2287 gst_event_copy_segment (event, &segment);
2288 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2291 if (segment.format == GST_FORMAT_TIME) {
2292 demux->upstream_format_is_time = TRUE;
2294 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2295 "not in time format");
2297 /* chain will send initial newsegment after pads have been added */
2298 if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2299 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2304 /* check if this matches a time seek we received previously
2305 * FIXME for backwards compatibility reasons we use the
2306 * seek_offset here to compare. In the future we might want to
2307 * change this to use the seqnum as it uniquely should identify
2308 * the segment that corresponds to the seek. */
2309 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2310 ", received segment offset %" G_GINT64_FORMAT,
2311 demux->seek_offset, segment.start);
2312 if (segment.format == GST_FORMAT_BYTES
2313 && demux->seek_offset == segment.start) {
2314 GST_OBJECT_LOCK (demux);
2315 offset = segment.start;
2317 segment.format = GST_FORMAT_TIME;
2318 segment.start = demux->push_seek_start;
2319 segment.stop = demux->push_seek_stop;
2320 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2321 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2322 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2323 GST_OBJECT_UNLOCK (demux);
2326 /* we only expect a BYTE segment, e.g. following a seek */
2327 if (segment.format == GST_FORMAT_BYTES) {
2328 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2329 offset = segment.start;
2331 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2332 NULL, (gint64 *) & segment.start);
2333 if ((gint64) segment.start < 0)
2336 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2337 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2338 NULL, (gint64 *) & segment.stop);
2339 /* keyframe seeking should already arrange for start >= stop,
2340 * but make sure in other rare cases */
2341 segment.stop = MAX (segment.stop, segment.start);
2343 } else if (segment.format == GST_FORMAT_TIME) {
2344 /* push all data on the adapter before starting this
2346 gst_qtdemux_process_adapter (demux, TRUE);
2348 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2352 /* We shouldn't modify upstream driven TIME FORMAT segment */
2353 if (!demux->upstream_format_is_time) {
2354 /* accept upstream's notion of segment and distribute along */
2355 segment.format = GST_FORMAT_TIME;
2356 segment.position = segment.time = segment.start;
2357 segment.duration = demux->segment.duration;
2358 segment.base = gst_segment_to_running_time (&demux->segment,
2359 GST_FORMAT_TIME, demux->segment.position);
2362 gst_segment_copy_into (&segment, &demux->segment);
2363 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2365 /* map segment to internal qt segments and push on each stream */
2366 if (demux->n_streams) {
2367 if (demux->fragmented) {
2368 GstEvent *segment_event = gst_event_new_segment (&segment);
2370 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2371 gst_qtdemux_push_event (demux, segment_event);
2373 gst_qtdemux_map_and_push_segments (demux, &segment);
2375 /* keep need-segment as is in case this is the segment before
2376 * fragmented data, we might not have pads yet to push it */
2378 demux->need_segment = FALSE;
2381 /* clear leftover in current segment, if any */
2382 gst_adapter_clear (demux->adapter);
2384 /* set up streaming thread */
2385 demux->offset = offset;
2386 if (demux->upstream_format_is_time) {
2387 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2388 "set values to restart reading from a new atom");
2389 demux->neededbytes = 16;
2392 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2395 demux->todrop = stream->samples[idx].offset - offset;
2396 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2398 /* set up for EOS */
2399 demux->neededbytes = -1;
2404 gst_event_unref (event);
2408 case GST_EVENT_FLUSH_START:
2410 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2411 gst_event_unref (event);
2414 QTDEMUX_EXPOSE_LOCK (demux);
2415 res = gst_pad_event_default (demux->sinkpad, parent, event);
2416 QTDEMUX_EXPOSE_UNLOCK (demux);
2419 case GST_EVENT_FLUSH_STOP:
2423 dur = demux->segment.duration;
2424 gst_qtdemux_reset (demux, FALSE);
2425 demux->segment.duration = dur;
2427 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2428 gst_event_unref (event);
2434 /* If we are in push mode, and get an EOS before we've seen any streams,
2435 * then error out - we have nowhere to send the EOS */
2436 if (!demux->pullbased) {
2438 gboolean has_valid_stream = FALSE;
2439 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
2440 if (QTDEMUX_STREAM (iter->data)->pad != NULL) {
2441 has_valid_stream = TRUE;
2445 if (!has_valid_stream)
2446 gst_qtdemux_post_no_playable_stream_error (demux);
2448 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2449 (guint) gst_adapter_available (demux->adapter));
2450 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2456 case GST_EVENT_CAPS:{
2457 GstCaps *caps = NULL;
2459 gst_event_parse_caps (event, &caps);
2460 gst_qtdemux_setcaps (demux, caps);
2462 gst_event_unref (event);
2465 case GST_EVENT_PROTECTION:
2467 const gchar *system_id = NULL;
2469 gst_event_parse_protection (event, &system_id, NULL, NULL);
2470 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2472 gst_qtdemux_append_protection_system_id (demux, system_id);
2473 /* save the event for later, for source pads that have not been created */
2474 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2475 /* send it to all pads that already exist */
2476 gst_qtdemux_push_event (demux, event);
2480 case GST_EVENT_STREAM_START:
2483 gst_event_unref (event);
2485 /* Drain all the buffers */
2486 gst_qtdemux_process_adapter (demux, TRUE);
2487 gst_qtdemux_reset (demux, FALSE);
2488 /* We expect new moov box after new stream-start event */
2489 demux->old_streams =
2490 g_list_concat (demux->old_streams, demux->active_streams);
2491 demux->active_streams = NULL;
2499 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2507 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2509 GstQTDemux *demux = GST_QTDEMUX (element);
2511 GST_OBJECT_LOCK (demux);
2512 if (demux->element_index)
2513 gst_object_unref (demux->element_index);
2515 demux->element_index = gst_object_ref (index);
2517 demux->element_index = NULL;
2519 GST_OBJECT_UNLOCK (demux);
2520 /* object lock might be taken again */
2522 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2523 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2524 demux->element_index, demux->index_id);
2528 gst_qtdemux_get_index (GstElement * element)
2530 GstIndex *result = NULL;
2531 GstQTDemux *demux = GST_QTDEMUX (element);
2533 GST_OBJECT_LOCK (demux);
2534 if (demux->element_index)
2535 result = gst_object_ref (demux->element_index);
2536 GST_OBJECT_UNLOCK (demux);
2538 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2545 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2547 g_free ((gpointer) stream->stco.data);
2548 stream->stco.data = NULL;
2549 g_free ((gpointer) stream->stsz.data);
2550 stream->stsz.data = NULL;
2551 g_free ((gpointer) stream->stsc.data);
2552 stream->stsc.data = NULL;
2553 g_free ((gpointer) stream->stts.data);
2554 stream->stts.data = NULL;
2555 g_free ((gpointer) stream->stss.data);
2556 stream->stss.data = NULL;
2557 g_free ((gpointer) stream->stps.data);
2558 stream->stps.data = NULL;
2559 g_free ((gpointer) stream->ctts.data);
2560 stream->ctts.data = NULL;
2564 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2566 g_free (stream->segments);
2567 stream->segments = NULL;
2568 stream->segment_index = -1;
2569 stream->accumulated_base = 0;
2573 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2575 g_free (stream->samples);
2576 stream->samples = NULL;
2577 gst_qtdemux_stbl_free (stream);
2580 g_free (stream->ra_entries);
2581 stream->ra_entries = NULL;
2582 stream->n_ra_entries = 0;
2584 stream->sample_index = -1;
2585 stream->stbl_index = -1;
2586 stream->n_samples = 0;
2587 stream->time_position = 0;
2589 stream->n_samples_moof = 0;
2590 stream->duration_moof = 0;
2591 stream->duration_last_moof = 0;
2595 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2598 if (stream->allocator)
2599 gst_object_unref (stream->allocator);
2600 while (stream->buffers) {
2601 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2602 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2604 for (i = 0; i < stream->stsd_entries_length; i++) {
2605 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2606 if (entry->rgb8_palette) {
2607 gst_memory_unref (entry->rgb8_palette);
2608 entry->rgb8_palette = NULL;
2610 entry->sparse = FALSE;
2613 if (stream->stream_tags)
2614 gst_tag_list_unref (stream->stream_tags);
2616 stream->stream_tags = gst_tag_list_new_empty ();
2617 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2618 g_free (stream->redirect_uri);
2619 stream->redirect_uri = NULL;
2620 stream->sent_eos = FALSE;
2621 stream->protected = FALSE;
2622 if (stream->protection_scheme_info) {
2623 if (stream->protection_scheme_type == FOURCC_cenc) {
2624 QtDemuxCencSampleSetInfo *info =
2625 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2626 if (info->default_properties)
2627 gst_structure_free (info->default_properties);
2628 if (info->crypto_info)
2629 g_ptr_array_free (info->crypto_info, TRUE);
2631 g_free (stream->protection_scheme_info);
2632 stream->protection_scheme_info = NULL;
2634 stream->protection_scheme_type = 0;
2635 stream->protection_scheme_version = 0;
2636 g_queue_foreach (&stream->protection_scheme_event_queue,
2637 (GFunc) gst_event_unref, NULL);
2638 g_queue_clear (&stream->protection_scheme_event_queue);
2639 gst_qtdemux_stream_flush_segments_data (stream);
2640 gst_qtdemux_stream_flush_samples_data (stream);
2644 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2647 gst_qtdemux_stream_clear (stream);
2648 for (i = 0; i < stream->stsd_entries_length; i++) {
2649 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2651 gst_caps_unref (entry->caps);
2655 g_free (stream->stsd_entries);
2656 stream->stsd_entries = NULL;
2657 stream->stsd_entries_length = 0;
2662 gst_qtdemux_stream_free (QtDemuxStream * stream)
2664 gst_qtdemux_stream_reset (stream);
2665 gst_tag_list_unref (stream->stream_tags);
2667 GstQTDemux *demux = stream->demux;
2668 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2669 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2671 g_free (stream->stream_id);
2676 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
2678 qtdemux->active_streams = g_list_remove (qtdemux->active_streams, stream);
2679 gst_qtdemux_stream_free (stream);
2680 qtdemux->n_streams--;
2683 static GstStateChangeReturn
2684 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2686 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2687 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2689 switch (transition) {
2690 case GST_STATE_CHANGE_READY_TO_PAUSED:
2691 gst_qtdemux_reset (qtdemux, TRUE);
2697 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2699 switch (transition) {
2700 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2701 gst_qtdemux_reset (qtdemux, TRUE);
2712 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2714 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2716 g_return_if_fail (GST_IS_CONTEXT (context));
2718 if (gst_context_has_context_type (context,
2719 "drm-preferred-decryption-system-id")) {
2720 const GstStructure *s;
2722 s = gst_context_get_structure (context);
2723 g_free (qtdemux->preferred_protection_system_id);
2724 qtdemux->preferred_protection_system_id =
2725 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2726 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2727 qtdemux->preferred_protection_system_id);
2730 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2734 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2736 /* counts as header data */
2737 qtdemux->header_size += length;
2739 /* only consider at least a sufficiently complete ftyp atom */
2743 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2744 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2745 GST_FOURCC_ARGS (qtdemux->major_brand));
2746 if (qtdemux->comp_brands)
2747 gst_buffer_unref (qtdemux->comp_brands);
2748 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2749 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2754 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2755 GstTagList * xmptaglist)
2757 /* Strip out bogus fields */
2759 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2760 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2761 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2763 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2766 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2768 /* prioritize native tags using _KEEP mode */
2769 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2770 gst_tag_list_unref (xmptaglist);
2775 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2783 QtDemuxStream *stream;
2784 GstStructure *structure;
2785 QtDemuxCencSampleSetInfo *ss_info = NULL;
2786 const gchar *system_id;
2787 gboolean uses_sub_sample_encryption = FALSE;
2788 guint32 sample_count;
2790 stream = QTDEMUX_FIRST_STREAM (qtdemux);
2794 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2795 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2796 GST_WARNING_OBJECT (qtdemux,
2797 "Attempting PIFF box parsing on an unencrypted stream.");
2801 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2802 G_TYPE_STRING, &system_id, NULL);
2803 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2805 stream->protected = TRUE;
2806 stream->protection_scheme_type = FOURCC_cenc;
2808 if (!stream->protection_scheme_info)
2809 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2811 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2813 if (ss_info->default_properties)
2814 gst_structure_free (ss_info->default_properties);
2816 ss_info->default_properties =
2817 gst_structure_new ("application/x-cenc",
2818 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
2820 if (ss_info->crypto_info) {
2821 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2822 g_ptr_array_free (ss_info->crypto_info, TRUE);
2823 ss_info->crypto_info = NULL;
2827 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2829 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2830 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2834 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2835 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2839 if ((flags & 0x000001)) {
2840 guint32 algorithm_id = 0;
2843 gboolean is_encrypted = TRUE;
2845 if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
2846 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2851 if (algorithm_id == 0) {
2852 is_encrypted = FALSE;
2853 } else if (algorithm_id == 1) {
2854 /* FIXME: maybe store this in properties? */
2855 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2856 } else if (algorithm_id == 2) {
2857 /* FIXME: maybe store this in properties? */
2858 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2861 if (!gst_byte_reader_get_uint8 (&br, &iv_size))
2864 if (!gst_byte_reader_get_data (&br, 16, &kid))
2867 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2868 gst_buffer_fill (kid_buf, 0, kid, 16);
2869 if (ss_info->default_properties)
2870 gst_structure_free (ss_info->default_properties);
2871 ss_info->default_properties =
2872 gst_structure_new ("application/x-cenc",
2873 "iv_size", G_TYPE_UINT, iv_size,
2874 "encrypted", G_TYPE_BOOLEAN, is_encrypted,
2875 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2876 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2877 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2878 gst_buffer_unref (kid_buf);
2879 } else if ((flags & 0x000002)) {
2880 uses_sub_sample_encryption = TRUE;
2883 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2884 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2888 ss_info->crypto_info =
2889 g_ptr_array_new_full (sample_count,
2890 (GDestroyNotify) qtdemux_gst_structure_free);
2892 for (i = 0; i < sample_count; ++i) {
2893 GstStructure *properties;
2897 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2898 if (properties == NULL) {
2899 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2900 qtdemux->cenc_aux_sample_count = i;
2904 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2905 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2906 gst_structure_free (properties);
2907 qtdemux->cenc_aux_sample_count = i;
2910 buf = gst_buffer_new_wrapped (data, iv_size);
2911 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2912 gst_buffer_unref (buf);
2914 if (uses_sub_sample_encryption) {
2915 guint16 n_subsamples;
2917 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2918 || n_subsamples == 0) {
2919 GST_ERROR_OBJECT (qtdemux,
2920 "failed to get subsample count for sample %u", i);
2921 gst_structure_free (properties);
2922 qtdemux->cenc_aux_sample_count = i;
2925 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
2926 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
2927 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
2929 gst_structure_free (properties);
2930 qtdemux->cenc_aux_sample_count = i;
2933 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
2934 gst_structure_set (properties,
2935 "subsample_count", G_TYPE_UINT, n_subsamples,
2936 "subsamples", GST_TYPE_BUFFER, buf, NULL);
2937 gst_buffer_unref (buf);
2939 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
2942 g_ptr_array_add (ss_info->crypto_info, properties);
2945 qtdemux->cenc_aux_sample_count = sample_count;
2949 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2951 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2952 0x97, 0xA9, 0x42, 0xE8,
2953 0x9C, 0x71, 0x99, 0x94,
2954 0x91, 0xE3, 0xAF, 0xAC
2956 static const guint8 playready_uuid[] = {
2957 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2958 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2961 static const guint8 piff_sample_encryption_uuid[] = {
2962 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
2963 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
2968 /* counts as header data */
2969 qtdemux->header_size += length;
2971 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2973 if (length <= offset + 16) {
2974 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2978 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2980 GstTagList *taglist;
2982 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2983 length - offset - 16, NULL);
2984 taglist = gst_tag_list_from_xmp_buffer (buf);
2985 gst_buffer_unref (buf);
2987 /* make sure we have a usable taglist */
2988 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
2990 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2992 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2994 const gunichar2 *s_utf16;
2997 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2998 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2999 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3000 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3004 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3005 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3007 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3008 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3010 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3011 GST_READ_UINT32_LE (buffer + offset),
3012 GST_READ_UINT32_LE (buffer + offset + 4),
3013 GST_READ_UINT32_LE (buffer + offset + 8),
3014 GST_READ_UINT32_LE (buffer + offset + 12));
3019 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3021 GstSidxParser sidx_parser;
3022 GstIsoffParserResult res;
3025 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3028 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3030 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3031 if (res == GST_ISOFF_QT_PARSER_DONE) {
3032 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3034 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3037 /* caller verifies at least 8 bytes in buf */
3039 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3040 guint64 * plength, guint32 * pfourcc)
3045 length = QT_UINT32 (data);
3046 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3047 fourcc = QT_FOURCC (data + 4);
3048 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3051 length = G_MAXUINT64;
3052 } else if (length == 1 && size >= 16) {
3053 /* this means we have an extended size, which is the 64 bit value of
3054 * the next 8 bytes */
3055 length = QT_UINT64 (data + 8);
3056 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3066 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3068 guint32 version = 0;
3069 GstClockTime duration = 0;
3071 if (!gst_byte_reader_get_uint32_be (br, &version))
3076 if (!gst_byte_reader_get_uint64_be (br, &duration))
3081 if (!gst_byte_reader_get_uint32_be (br, &dur))
3086 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3087 qtdemux->duration = duration;
3093 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3099 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3100 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3102 if (!stream->parsed_trex && qtdemux->moov_node) {
3104 GstByteReader trex_data;
3106 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3108 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3111 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3113 /* skip version/flags */
3114 if (!gst_byte_reader_skip (&trex_data, 4))
3116 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3118 if (id != stream->track_id)
3120 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3122 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3124 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3126 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3129 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3130 "duration %d, size %d, flags 0x%x", stream->track_id,
3133 stream->parsed_trex = TRUE;
3134 stream->def_sample_description_index = sdi;
3135 stream->def_sample_duration = dur;
3136 stream->def_sample_size = size;
3137 stream->def_sample_flags = flags;
3140 /* iterate all siblings */
3141 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3147 *ds_duration = stream->def_sample_duration;
3148 *ds_size = stream->def_sample_size;
3149 *ds_flags = stream->def_sample_flags;
3151 /* even then, above values are better than random ... */
3152 if (G_UNLIKELY (!stream->parsed_trex)) {
3153 GST_WARNING_OBJECT (qtdemux,
3154 "failed to find fragment defaults for stream %d", stream->track_id);
3161 /* This method should be called whenever a more accurate duration might
3162 * have been found. It will update all relevant variables if/where needed
3165 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3169 GstClockTime prevdur;
3172 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3174 if (movdur > qtdemux->duration) {
3175 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3176 GST_DEBUG_OBJECT (qtdemux,
3177 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3178 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3179 qtdemux->duration = movdur;
3180 GST_DEBUG_OBJECT (qtdemux,
3181 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3182 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3183 GST_TIME_ARGS (qtdemux->segment.stop));
3184 if (qtdemux->segment.duration == prevdur) {
3185 /* If the current segment has duration/stop identical to previous duration
3186 * update them also (because they were set at that point in time with
3187 * the wrong duration */
3188 /* We convert the value *from* the timescale version to avoid rounding errors */
3189 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3190 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3191 qtdemux->segment.duration = fixeddur;
3192 qtdemux->segment.stop = fixeddur;
3195 for (iter = qtdemux->active_streams, i = 0; iter;
3196 iter = g_list_next (iter), i++) {
3197 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3199 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3200 if (movdur > stream->duration) {
3201 GST_DEBUG_OBJECT (qtdemux,
3202 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3203 GST_TIME_ARGS (duration));
3204 stream->duration = movdur;
3205 /* internal duration tracking state has been updated above, so */
3206 /* preserve an open-ended dummy segment rather than repeatedly updating
3207 * it and spamming downstream accordingly with segment events */
3208 if (stream->dummy_segment &&
3209 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3210 /* Update all dummy values to new duration */
3211 stream->segments[0].stop_time = duration;
3212 stream->segments[0].duration = duration;
3213 stream->segments[0].media_stop = duration;
3215 /* let downstream know we possibly have a new stop time */
3216 if (stream->segment_index != -1) {
3219 if (qtdemux->segment.rate >= 0) {
3220 pos = stream->segment.start;
3222 pos = stream->segment.stop;
3225 gst_qtdemux_stream_update_segment (qtdemux, stream,
3226 stream->segment_index, pos, NULL, NULL);
3234 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3235 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3236 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3237 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3240 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3242 gint32 data_offset = 0;
3243 guint32 flags = 0, first_flags = 0, samples_count = 0;
3246 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3247 QtDemuxSample *sample;
3248 gboolean ismv = FALSE;
3249 gint64 initial_offset;
3251 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3252 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3253 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3254 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3256 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3257 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3261 /* presence of stss or not can't really tell us much,
3262 * and flags and so on tend to be marginally reliable in these files */
3263 if (stream->subtype == FOURCC_soun) {
3264 GST_DEBUG_OBJECT (qtdemux,
3265 "sound track in fragmented file; marking all keyframes");
3266 stream->all_keyframe = TRUE;
3269 if (!gst_byte_reader_skip (trun, 1) ||
3270 !gst_byte_reader_get_uint24_be (trun, &flags))
3273 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3276 if (flags & TR_DATA_OFFSET) {
3277 /* note this is really signed */
3278 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3280 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3281 /* default base offset = first byte of moof */
3282 if (*base_offset == -1) {
3283 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3284 *base_offset = moof_offset;
3286 *running_offset = *base_offset + data_offset;
3288 /* if no offset at all, that would mean data starts at moof start,
3289 * which is a bit wrong and is ismv crappy way, so compensate
3290 * assuming data is in mdat following moof */
3291 if (*base_offset == -1) {
3292 *base_offset = moof_offset + moof_length + 8;
3293 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3296 if (*running_offset == -1)
3297 *running_offset = *base_offset;
3300 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3302 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3303 data_offset, flags, samples_count);
3305 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3306 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3307 GST_DEBUG_OBJECT (qtdemux,
3308 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3309 flags ^= TR_FIRST_SAMPLE_FLAGS;
3311 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3313 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3317 /* FIXME ? spec says other bits should also be checked to determine
3318 * entry size (and prefix size for that matter) */
3320 dur_offset = size_offset = 0;
3321 if (flags & TR_SAMPLE_DURATION) {
3322 GST_LOG_OBJECT (qtdemux, "entry duration present");
3323 dur_offset = entry_size;
3326 if (flags & TR_SAMPLE_SIZE) {
3327 GST_LOG_OBJECT (qtdemux, "entry size present");
3328 size_offset = entry_size;
3331 if (flags & TR_SAMPLE_FLAGS) {
3332 GST_LOG_OBJECT (qtdemux, "entry flags present");
3333 flags_offset = entry_size;
3336 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3337 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3338 ct_offset = entry_size;
3342 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3344 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3346 if (stream->n_samples + samples_count >=
3347 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3350 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3351 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3352 (stream->n_samples + samples_count) *
3353 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3355 /* create a new array of samples if it's the first sample parsed */
3356 if (stream->n_samples == 0) {
3357 g_assert (stream->samples == NULL);
3358 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3359 /* or try to reallocate it with space enough to insert the new samples */
3361 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3362 stream->n_samples + samples_count);
3363 if (stream->samples == NULL)
3366 if (qtdemux->fragment_start != -1) {
3367 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3368 qtdemux->fragment_start = -1;
3370 if (stream->n_samples == 0) {
3371 if (decode_ts > 0) {
3372 timestamp = decode_ts;
3373 } else if (stream->pending_seek != NULL) {
3374 /* if we don't have a timestamp from a tfdt box, we'll use the one
3375 * from the mfra seek table */
3376 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3377 GST_TIME_ARGS (stream->pending_seek->ts));
3379 /* FIXME: this is not fully correct, the timestamp refers to the random
3380 * access sample refered to in the tfra entry, which may not necessarily
3381 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3382 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3387 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3388 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3389 GST_TIME_ARGS (gst_ts));
3391 /* subsequent fragments extend stream */
3393 stream->samples[stream->n_samples - 1].timestamp +
3394 stream->samples[stream->n_samples - 1].duration;
3396 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3397 * difference (1 sec.) between decode_ts and timestamp, prefer the
3399 if (has_tfdt && !qtdemux->upstream_format_is_time
3400 && ABSDIFF (decode_ts, timestamp) >
3401 MAX (stream->duration_last_moof / 2,
3402 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3403 GST_INFO_OBJECT (qtdemux,
3404 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3405 ") are significantly different (more than %" GST_TIME_FORMAT
3406 "), using decode_ts",
3407 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3408 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3409 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3410 MAX (stream->duration_last_moof / 2,
3411 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3412 timestamp = decode_ts;
3415 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3416 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3417 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3421 initial_offset = *running_offset;
3423 sample = stream->samples + stream->n_samples;
3424 for (i = 0; i < samples_count; i++) {
3425 guint32 dur, size, sflags, ct;
3427 /* first read sample data */
3428 if (flags & TR_SAMPLE_DURATION) {
3429 dur = QT_UINT32 (data + dur_offset);
3431 dur = d_sample_duration;
3433 if (flags & TR_SAMPLE_SIZE) {
3434 size = QT_UINT32 (data + size_offset);
3436 size = d_sample_size;
3438 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3440 sflags = first_flags;
3442 sflags = d_sample_flags;
3444 } else if (flags & TR_SAMPLE_FLAGS) {
3445 sflags = QT_UINT32 (data + flags_offset);
3447 sflags = d_sample_flags;
3449 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3450 ct = QT_UINT32 (data + ct_offset);
3456 /* fill the sample information */
3457 sample->offset = *running_offset;
3458 sample->pts_offset = ct;
3459 sample->size = size;
3460 sample->timestamp = timestamp;
3461 sample->duration = dur;
3462 /* sample-is-difference-sample */
3463 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3464 * now idea how it relates to bitfield other than massive LE/BE confusion */
3465 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3466 *running_offset += size;
3468 stream->duration_moof += dur;
3472 /* Update total duration if needed */
3473 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3475 /* Pre-emptively figure out size of mdat based on trun information.
3476 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3477 * size, else we will still be able to use this when dealing with gap'ed
3479 qtdemux->mdatleft = *running_offset - initial_offset;
3480 qtdemux->mdatoffset = initial_offset;
3481 qtdemux->mdatsize = qtdemux->mdatleft;
3483 stream->n_samples += samples_count;
3484 stream->n_samples_moof += samples_count;
3486 if (stream->pending_seek != NULL)
3487 stream->pending_seek = NULL;
3493 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3498 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3504 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3505 "be larger than %uMB (broken file?)", stream->n_samples,
3506 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3511 /* find stream with @id */
3512 static inline QtDemuxStream *
3513 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3515 QtDemuxStream *stream;
3519 if (G_UNLIKELY (!id)) {
3520 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3524 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3525 stream = QTDEMUX_STREAM (iter->data);
3526 if (stream->track_id == id)
3529 if (qtdemux->mss_mode) {
3530 /* mss should have only 1 stream anyway */
3531 return QTDEMUX_FIRST_STREAM (qtdemux);
3538 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3539 guint32 * fragment_number)
3541 if (!gst_byte_reader_skip (mfhd, 4))
3543 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3548 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3554 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3555 QtDemuxStream ** stream, guint32 * default_sample_duration,
3556 guint32 * default_sample_size, guint32 * default_sample_flags,
3557 gint64 * base_offset)
3560 guint32 track_id = 0;
3562 if (!gst_byte_reader_skip (tfhd, 1) ||
3563 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3566 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3569 *stream = qtdemux_find_stream (qtdemux, track_id);
3570 if (G_UNLIKELY (!*stream))
3571 goto unknown_stream;
3573 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3574 *base_offset = qtdemux->moof_offset;
3576 if (flags & TF_BASE_DATA_OFFSET)
3577 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3580 /* obtain stream defaults */
3581 qtdemux_parse_trex (qtdemux, *stream,
3582 default_sample_duration, default_sample_size, default_sample_flags);
3584 (*stream)->stsd_sample_description_id =
3585 (*stream)->def_sample_description_index - 1;
3587 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3588 guint32 sample_description_index;
3589 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3591 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3594 if (qtdemux->mss_mode) {
3595 /* mss has no stsd entry */
3596 (*stream)->stsd_sample_description_id = 0;
3599 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3600 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3603 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3604 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3607 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3608 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3615 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3620 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3626 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3627 guint64 * decode_time)
3629 guint32 version = 0;
3631 if (!gst_byte_reader_get_uint32_be (br, &version))
3636 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3639 guint32 dec_time = 0;
3640 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3642 *decode_time = dec_time;
3645 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3652 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3657 /* Returns a pointer to a GstStructure containing the properties of
3658 * the stream sample identified by @sample_index. The caller must unref
3659 * the returned object after use. Returns NULL if unsuccessful. */
3660 static GstStructure *
3661 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3662 QtDemuxStream * stream, guint sample_index)
3664 QtDemuxCencSampleSetInfo *info = NULL;
3666 g_return_val_if_fail (stream != NULL, NULL);
3667 g_return_val_if_fail (stream->protected, NULL);
3668 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3670 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3672 /* Currently, cenc properties for groups of samples are not supported, so
3673 * simply return a copy of the default sample properties */
3674 return gst_structure_copy (info->default_properties);
3677 /* Parses the sizes of sample auxiliary information contained within a stream,
3678 * as given in a saiz box. Returns array of sample_count guint8 size values,
3679 * or NULL on failure */
3681 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3682 GstByteReader * br, guint32 * sample_count)
3686 guint8 default_info_size;
3688 g_return_val_if_fail (qtdemux != NULL, NULL);
3689 g_return_val_if_fail (stream != NULL, NULL);
3690 g_return_val_if_fail (br != NULL, NULL);
3691 g_return_val_if_fail (sample_count != NULL, NULL);
3693 if (!gst_byte_reader_get_uint32_be (br, &flags))
3697 /* aux_info_type and aux_info_type_parameter are ignored */
3698 if (!gst_byte_reader_skip (br, 8))
3702 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3704 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3706 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3708 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3711 if (default_info_size == 0) {
3712 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3716 info_sizes = g_new (guint8, *sample_count);
3717 memset (info_sizes, default_info_size, *sample_count);
3723 /* Parses the offset of sample auxiliary information contained within a stream,
3724 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3726 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3727 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3732 guint32 aux_info_type = 0;
3733 guint32 aux_info_type_parameter = 0;
3734 guint32 entry_count;
3737 const guint8 *aux_info_type_data = NULL;
3739 g_return_val_if_fail (qtdemux != NULL, FALSE);
3740 g_return_val_if_fail (stream != NULL, FALSE);
3741 g_return_val_if_fail (br != NULL, FALSE);
3742 g_return_val_if_fail (offset != NULL, FALSE);
3744 if (!gst_byte_reader_get_uint8 (br, &version))
3747 if (!gst_byte_reader_get_uint24_be (br, &flags))
3752 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3754 aux_info_type = QT_FOURCC (aux_info_type_data);
3756 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3758 } else if (stream->protected) {
3759 aux_info_type = stream->protection_scheme_type;
3761 aux_info_type = CUR_STREAM (stream)->fourcc;
3765 *info_type = aux_info_type;
3766 if (info_type_parameter)
3767 *info_type_parameter = aux_info_type_parameter;
3769 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3770 "aux_info_type_parameter: %#06x",
3771 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3773 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3776 if (entry_count != 1) {
3777 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3782 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3784 *offset = (guint64) off_32;
3786 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3791 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3796 qtdemux_gst_structure_free (GstStructure * gststructure)
3799 gst_structure_free (gststructure);
3803 /* Parses auxiliary information relating to samples protected using Common
3804 * Encryption (cenc); the format of this information is defined in
3805 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3807 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3808 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3810 QtDemuxCencSampleSetInfo *ss_info = NULL;
3813 GPtrArray *old_crypto_info = NULL;
3814 guint old_entries = 0;
3816 g_return_val_if_fail (qtdemux != NULL, FALSE);
3817 g_return_val_if_fail (stream != NULL, FALSE);
3818 g_return_val_if_fail (br != NULL, FALSE);
3819 g_return_val_if_fail (stream->protected, FALSE);
3820 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3822 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3824 if (ss_info->crypto_info) {
3825 old_crypto_info = ss_info->crypto_info;
3826 /* Count number of non-null entries remaining at the tail end */
3827 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3828 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3834 ss_info->crypto_info =
3835 g_ptr_array_new_full (sample_count + old_entries,
3836 (GDestroyNotify) qtdemux_gst_structure_free);
3838 /* We preserve old entries because we parse the next moof in advance
3839 * of consuming all samples from the previous moof, and otherwise
3840 * we'd discard the corresponding crypto info for the samples
3841 * from the previous fragment. */
3843 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3845 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3846 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3848 g_ptr_array_index (old_crypto_info, i) = NULL;
3852 if (old_crypto_info) {
3853 /* Everything now belongs to the new array */
3854 g_ptr_array_free (old_crypto_info, TRUE);
3857 for (i = 0; i < sample_count; ++i) {
3858 GstStructure *properties;
3859 guint16 n_subsamples = 0;
3864 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3865 if (properties == NULL) {
3866 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3869 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3870 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3871 gst_structure_free (properties);
3874 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3875 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3876 gst_structure_free (properties);
3879 buf = gst_buffer_new_wrapped (data, iv_size);
3880 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3881 gst_buffer_unref (buf);
3882 size = info_sizes[i];
3883 if (size > iv_size) {
3884 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3885 || !(n_subsamples > 0)) {
3886 gst_structure_free (properties);
3887 GST_ERROR_OBJECT (qtdemux,
3888 "failed to get subsample count for sample %u", i);
3891 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3892 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3893 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3895 gst_structure_free (properties);
3898 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3900 gst_structure_free (properties);
3903 gst_structure_set (properties,
3904 "subsample_count", G_TYPE_UINT, n_subsamples,
3905 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3906 gst_buffer_unref (buf);
3908 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3910 g_ptr_array_add (ss_info->crypto_info, properties);
3915 /* Converts a UUID in raw byte form to a string representation, as defined in
3916 * RFC 4122. The caller takes ownership of the returned string and is
3917 * responsible for freeing it after use. */
3919 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3921 const guint8 *uuid = (const guint8 *) uuid_bytes;
3923 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3924 "%02x%02x-%02x%02x%02x%02x%02x%02x",
3925 uuid[0], uuid[1], uuid[2], uuid[3],
3926 uuid[4], uuid[5], uuid[6], uuid[7],
3927 uuid[8], uuid[9], uuid[10], uuid[11],
3928 uuid[12], uuid[13], uuid[14], uuid[15]);
3931 /* Parses a Protection System Specific Header box (pssh), as defined in the
3932 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3933 * information needed by a specific content protection system in order to
3934 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3937 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3939 gchar *sysid_string;
3940 guint32 pssh_size = QT_UINT32 (node->data);
3941 GstBuffer *pssh = NULL;
3942 GstEvent *event = NULL;
3943 guint32 parent_box_type;
3946 if (G_UNLIKELY (pssh_size < 32U)) {
3947 GST_ERROR_OBJECT (qtdemux, "invalid box size");
3952 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3954 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3956 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3957 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3958 gst_buffer_get_size (pssh));
3960 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3962 /* Push an event containing the pssh box onto the queues of all streams. */
3963 event = gst_event_new_protection (sysid_string, pssh,
3964 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3965 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
3966 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
3967 GST_TRACE_OBJECT (qtdemux,
3968 "adding protection event for stream %s and system %s",
3969 stream->stream_id, sysid_string);
3970 g_queue_push_tail (&stream->protection_scheme_event_queue,
3971 gst_event_ref (event));
3973 g_free (sysid_string);
3974 gst_event_unref (event);
3975 gst_buffer_unref (pssh);
3980 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3981 guint64 moof_offset, QtDemuxStream * stream)
3983 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3985 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3986 GNode *saiz_node, *saio_node, *pssh_node;
3987 GstByteReader saiz_data, saio_data;
3988 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3989 gint64 base_offset, running_offset;
3992 /* NOTE @stream ignored */
3994 moof_node = g_node_new ((guint8 *) buffer);
3995 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3996 qtdemux_node_dump (qtdemux, moof_node);
3998 /* Get fragment number from mfhd and check it's valid */
4000 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4001 if (mfhd_node == NULL)
4003 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4005 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4007 /* unknown base_offset to start with */
4008 base_offset = running_offset = -1;
4009 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4011 guint64 decode_time = 0;
4013 /* Fragment Header node */
4015 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4019 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4020 &ds_size, &ds_flags, &base_offset))
4023 /* The following code assumes at most a single set of sample auxiliary
4024 * data in the fragment (consisting of a saiz box and a corresponding saio
4025 * box); in theory, however, there could be multiple sets of sample
4026 * auxiliary data in a fragment. */
4028 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4031 guint32 info_type = 0;
4033 guint32 info_type_parameter = 0;
4035 g_free (qtdemux->cenc_aux_info_sizes);
4037 qtdemux->cenc_aux_info_sizes =
4038 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4039 &qtdemux->cenc_aux_sample_count);
4040 if (qtdemux->cenc_aux_info_sizes == NULL) {
4041 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4045 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4048 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4049 g_free (qtdemux->cenc_aux_info_sizes);
4050 qtdemux->cenc_aux_info_sizes = NULL;
4054 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4055 &info_type, &info_type_parameter, &offset))) {
4056 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4057 g_free (qtdemux->cenc_aux_info_sizes);
4058 qtdemux->cenc_aux_info_sizes = NULL;
4061 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4062 offset += (guint64) (base_offset - qtdemux->moof_offset);
4063 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4065 if (offset > length) {
4066 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4067 qtdemux->cenc_aux_info_offset = offset;
4069 gst_byte_reader_init (&br, buffer + offset, length - offset);
4070 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4071 qtdemux->cenc_aux_info_sizes,
4072 qtdemux->cenc_aux_sample_count)) {
4073 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4074 g_free (qtdemux->cenc_aux_info_sizes);
4075 qtdemux->cenc_aux_info_sizes = NULL;
4083 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4086 /* We'll use decode_time to interpolate timestamps
4087 * in case the input timestamps are missing */
4088 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4090 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4091 " (%" GST_TIME_FORMAT ")", decode_time,
4092 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4093 decode_time) : GST_CLOCK_TIME_NONE));
4095 /* Discard the fragment buffer timestamp info to avoid using it.
4096 * Rely on tfdt instead as it is more accurate than the timestamp
4097 * that is fetched from a manifest/playlist and is usually
4099 qtdemux->fragment_start = -1;
4102 if (G_UNLIKELY (!stream)) {
4103 /* we lost track of offset, we'll need to regain it,
4104 * but can delay complaining until later or avoid doing so altogether */
4108 if (G_UNLIKELY (base_offset < -1))
4111 if (qtdemux->upstream_format_is_time)
4112 gst_qtdemux_stream_flush_samples_data (stream);
4114 /* initialise moof sample data */
4115 stream->n_samples_moof = 0;
4116 stream->duration_last_moof = stream->duration_moof;
4117 stream->duration_moof = 0;
4119 /* Track Run node */
4121 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4124 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4125 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4126 &running_offset, decode_time, (tfdt_node != NULL));
4127 /* iterate all siblings */
4128 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4132 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4134 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4135 guint32 box_length = QT_UINT32 (uuid_buffer);
4137 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4140 /* if no new base_offset provided for next traf,
4141 * base is end of current traf */
4142 base_offset = running_offset;
4143 running_offset = -1;
4145 if (stream->n_samples_moof && stream->duration_moof)
4146 stream->new_caps = TRUE;
4149 /* iterate all siblings */
4150 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4153 /* parse any protection system info */
4154 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4156 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4157 qtdemux_parse_pssh (qtdemux, pssh_node);
4158 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4161 g_node_destroy (moof_node);
4166 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4171 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4176 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4181 g_node_destroy (moof_node);
4182 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4183 (_("This file is corrupt and cannot be played.")), (NULL));
4189 /* might be used if some day we actually use mfra & co
4190 * for random access to fragments,
4191 * but that will require quite some modifications and much less relying
4192 * on a sample array */
4196 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4198 QtDemuxStream *stream;
4199 guint32 ver_flags, track_id, len, num_entries, i;
4200 guint value_size, traf_size, trun_size, sample_size;
4201 guint64 time = 0, moof_offset = 0;
4203 GstBuffer *buf = NULL;
4208 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4210 if (!gst_byte_reader_skip (&tfra, 8))
4213 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4216 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4217 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4218 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4221 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4223 stream = qtdemux_find_stream (qtdemux, track_id);
4225 goto unknown_trackid;
4227 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4228 sample_size = (len & 3) + 1;
4229 trun_size = ((len & 12) >> 2) + 1;
4230 traf_size = ((len & 48) >> 4) + 1;
4232 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4233 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4235 if (num_entries == 0)
4238 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4239 value_size + value_size + traf_size + trun_size + sample_size))
4242 g_free (stream->ra_entries);
4243 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4244 stream->n_ra_entries = num_entries;
4246 for (i = 0; i < num_entries; i++) {
4247 qt_atom_parser_get_offset (&tfra, value_size, &time);
4248 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4249 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4250 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4251 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4253 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4255 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4256 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4258 stream->ra_entries[i].ts = time;
4259 stream->ra_entries[i].moof_offset = moof_offset;
4261 /* don't want to go through the entire file and read all moofs at startup */
4263 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4264 if (ret != GST_FLOW_OK)
4266 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4267 moof_offset, stream);
4268 gst_buffer_unref (buf);
4272 check_update_duration (qtdemux, time);
4279 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4284 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4289 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4295 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4297 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4298 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4299 GstBuffer *mfro = NULL, *mfra = NULL;
4301 gboolean ret = FALSE;
4302 GNode *mfra_node, *tfra_node;
4303 guint64 mfra_offset = 0;
4304 guint32 fourcc, mfra_size;
4307 /* query upstream size in bytes */
4308 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4309 goto size_query_failed;
4311 /* mfro box should be at the very end of the file */
4312 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4313 if (flow != GST_FLOW_OK)
4316 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4318 fourcc = QT_FOURCC (mfro_map.data + 4);
4319 if (fourcc != FOURCC_mfro)
4322 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4323 if (mfro_map.size < 16)
4324 goto invalid_mfro_size;
4326 mfra_size = QT_UINT32 (mfro_map.data + 12);
4327 if (mfra_size >= len)
4328 goto invalid_mfra_size;
4330 mfra_offset = len - mfra_size;
4332 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4333 mfra_offset, mfra_size);
4335 /* now get and parse mfra box */
4336 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4337 if (flow != GST_FLOW_OK)
4340 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4342 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4343 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4345 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4348 qtdemux_parse_tfra (qtdemux, tfra_node);
4349 /* iterate all siblings */
4350 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4352 g_node_destroy (mfra_node);
4354 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4360 if (mfro_map.memory != NULL)
4361 gst_buffer_unmap (mfro, &mfro_map);
4362 gst_buffer_unref (mfro);
4365 if (mfra_map.memory != NULL)
4366 gst_buffer_unmap (mfra, &mfra_map);
4367 gst_buffer_unref (mfra);
4374 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4379 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4384 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4389 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4395 add_offset (guint64 offset, guint64 advance)
4397 /* Avoid 64-bit overflow by clamping */
4398 if (offset > G_MAXUINT64 - advance)
4400 return offset + advance;
4403 static GstFlowReturn
4404 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4408 GstBuffer *buf = NULL;
4409 GstFlowReturn ret = GST_FLOW_OK;
4410 guint64 cur_offset = qtdemux->offset;
4413 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4414 if (G_UNLIKELY (ret != GST_FLOW_OK))
4416 gst_buffer_map (buf, &map, GST_MAP_READ);
4417 if (G_LIKELY (map.size >= 8))
4418 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4419 gst_buffer_unmap (buf, &map);
4420 gst_buffer_unref (buf);
4422 /* maybe we already got most we needed, so only consider this eof */
4423 if (G_UNLIKELY (length == 0)) {
4424 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4425 (_("Invalid atom size.")),
4426 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4427 GST_FOURCC_ARGS (fourcc)));
4434 /* record for later parsing when needed */
4435 if (!qtdemux->moof_offset) {
4436 qtdemux->moof_offset = qtdemux->offset;
4438 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4441 qtdemux->offset += length; /* skip moof and keep going */
4443 if (qtdemux->got_moov) {
4444 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4456 GST_LOG_OBJECT (qtdemux,
4457 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4458 GST_FOURCC_ARGS (fourcc), cur_offset);
4459 qtdemux->offset = add_offset (qtdemux->offset, length);
4464 GstBuffer *moov = NULL;
4466 if (qtdemux->got_moov) {
4467 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4468 qtdemux->offset = add_offset (qtdemux->offset, length);
4472 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4473 if (ret != GST_FLOW_OK)
4475 gst_buffer_map (moov, &map, GST_MAP_READ);
4477 if (length != map.size) {
4478 /* Some files have a 'moov' atom at the end of the file which contains
4479 * a terminal 'free' atom where the body of the atom is missing.
4480 * Check for, and permit, this special case.
4482 if (map.size >= 8) {
4483 guint8 *final_data = map.data + (map.size - 8);
4484 guint32 final_length = QT_UINT32 (final_data);
4485 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4487 if (final_fourcc == FOURCC_free
4488 && map.size + final_length - 8 == length) {
4489 /* Ok, we've found that special case. Allocate a new buffer with
4490 * that free atom actually present. */
4491 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4492 gst_buffer_fill (newmoov, 0, map.data, map.size);
4493 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4494 gst_buffer_unmap (moov, &map);
4495 gst_buffer_unref (moov);
4497 gst_buffer_map (moov, &map, GST_MAP_READ);
4502 if (length != map.size) {
4503 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4504 (_("This file is incomplete and cannot be played.")),
4505 ("We got less than expected (received %" G_GSIZE_FORMAT
4506 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4507 (guint) length, cur_offset));
4508 gst_buffer_unmap (moov, &map);
4509 gst_buffer_unref (moov);
4510 ret = GST_FLOW_ERROR;
4513 qtdemux->offset += length;
4515 qtdemux_parse_moov (qtdemux, map.data, length);
4516 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4518 qtdemux_parse_tree (qtdemux);
4519 if (qtdemux->moov_node_compressed) {
4520 g_node_destroy (qtdemux->moov_node_compressed);
4521 g_free (qtdemux->moov_node->data);
4523 qtdemux->moov_node_compressed = NULL;
4524 g_node_destroy (qtdemux->moov_node);
4525 qtdemux->moov_node = NULL;
4526 gst_buffer_unmap (moov, &map);
4527 gst_buffer_unref (moov);
4528 qtdemux->got_moov = TRUE;
4529 if (!qtdemux->fragmented && !qtdemux->upstream_format_is_time) {
4530 /* in this case, parsing the edts entries will give us segments
4532 qtdemux->need_segment = FALSE;
4539 GstBuffer *ftyp = NULL;
4541 /* extract major brand; might come in handy for ISO vs QT issues */
4542 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4543 if (ret != GST_FLOW_OK)
4545 qtdemux->offset += length;
4546 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4547 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4548 gst_buffer_unmap (ftyp, &map);
4549 gst_buffer_unref (ftyp);
4554 GstBuffer *uuid = NULL;
4556 /* uuid are extension atoms */
4557 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4558 if (ret != GST_FLOW_OK)
4560 qtdemux->offset += length;
4561 gst_buffer_map (uuid, &map, GST_MAP_READ);
4562 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4563 gst_buffer_unmap (uuid, &map);
4564 gst_buffer_unref (uuid);
4569 GstBuffer *sidx = NULL;
4570 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4571 if (ret != GST_FLOW_OK)
4573 qtdemux->offset += length;
4574 gst_buffer_map (sidx, &map, GST_MAP_READ);
4575 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4576 gst_buffer_unmap (sidx, &map);
4577 gst_buffer_unref (sidx);
4582 GstBuffer *unknown = NULL;
4584 GST_LOG_OBJECT (qtdemux,
4585 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4586 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4588 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4589 if (ret != GST_FLOW_OK)
4591 gst_buffer_map (unknown, &map, GST_MAP_READ);
4592 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4593 gst_buffer_unmap (unknown, &map);
4594 gst_buffer_unref (unknown);
4595 qtdemux->offset += length;
4601 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4602 /* digested all data, show what we have */
4603 qtdemux_prepare_streams (qtdemux);
4604 QTDEMUX_EXPOSE_LOCK (qtdemux);
4605 ret = qtdemux_expose_streams (qtdemux);
4606 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4608 qtdemux->state = QTDEMUX_STATE_MOVIE;
4609 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4616 /* Seeks to the previous keyframe of the indexed stream and
4617 * aligns other streams with respect to the keyframe timestamp
4618 * of indexed stream. Only called in case of Reverse Playback
4620 static GstFlowReturn
4621 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4623 guint32 seg_idx = 0, k_index = 0;
4624 guint32 ref_seg_idx, ref_k_index;
4625 GstClockTime k_pos = 0, last_stop = 0;
4626 QtDemuxSegment *seg = NULL;
4627 QtDemuxStream *ref_str = NULL;
4628 guint64 seg_media_start_mov; /* segment media start time in mov format */
4632 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4633 * and finally align all the other streams on that timestamp with their
4634 * respective keyframes */
4635 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4636 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4638 /* No candidate yet, take the first stream */
4644 /* So that stream has a segment, we prefer video streams */
4645 if (str->subtype == FOURCC_vide) {
4651 if (G_UNLIKELY (!ref_str)) {
4652 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4656 if (G_UNLIKELY (!ref_str->from_sample)) {
4657 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4661 /* So that stream has been playing from from_sample to to_sample. We will
4662 * get the timestamp of the previous sample and search for a keyframe before
4663 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4664 if (ref_str->subtype == FOURCC_vide) {
4665 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4666 ref_str->from_sample - 1, FALSE);
4668 if (ref_str->from_sample >= 10)
4669 k_index = ref_str->from_sample - 10;
4675 ref_str->samples[k_index].timestamp +
4676 ref_str->samples[k_index].pts_offset;
4678 /* get current segment for that stream */
4679 seg = &ref_str->segments[ref_str->segment_index];
4680 /* Use segment start in original timescale for comparisons */
4681 seg_media_start_mov = seg->trak_media_start;
4683 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4684 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4685 k_index, target_ts, seg_media_start_mov,
4686 GST_TIME_ARGS (seg->media_start));
4688 /* Crawl back through segments to find the one containing this I frame */
4689 while (target_ts < seg_media_start_mov) {
4690 GST_DEBUG_OBJECT (qtdemux,
4691 "keyframe position (sample %u) is out of segment %u " " target %"
4692 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4693 ref_str->segment_index, target_ts, seg_media_start_mov);
4695 if (G_UNLIKELY (!ref_str->segment_index)) {
4696 /* Reached first segment, let's consider it's EOS */
4699 ref_str->segment_index--;
4700 seg = &ref_str->segments[ref_str->segment_index];
4701 /* Use segment start in original timescale for comparisons */
4702 seg_media_start_mov = seg->trak_media_start;
4704 /* Calculate time position of the keyframe and where we should stop */
4706 QTSTREAMTIME_TO_GSTTIME (ref_str,
4707 target_ts - seg->trak_media_start) + seg->time;
4709 QTSTREAMTIME_TO_GSTTIME (ref_str,
4710 ref_str->samples[ref_str->from_sample].timestamp -
4711 seg->trak_media_start) + seg->time;
4713 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4714 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4715 k_index, GST_TIME_ARGS (k_pos));
4717 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4718 qtdemux->segment.position = last_stop;
4719 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4720 GST_TIME_ARGS (last_stop));
4722 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4723 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4727 ref_seg_idx = ref_str->segment_index;
4728 ref_k_index = k_index;
4730 /* Align them all on this */
4731 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
4733 GstClockTime seg_time = 0;
4734 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
4736 /* aligning reference stream again might lead to backing up to yet another
4737 * keyframe (due to timestamp rounding issues),
4738 * potentially putting more load on downstream; so let's try to avoid */
4739 if (str == ref_str) {
4740 seg_idx = ref_seg_idx;
4741 seg = &str->segments[seg_idx];
4742 k_index = ref_k_index;
4743 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4744 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4746 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4747 GST_DEBUG_OBJECT (qtdemux,
4748 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4749 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4751 /* get segment and time in the segment */
4752 seg = &str->segments[seg_idx];
4753 seg_time = k_pos - seg->time;
4755 /* get the media time in the segment.
4756 * No adjustment for empty "filler" segments */
4757 if (seg->media_start != GST_CLOCK_TIME_NONE)
4758 seg_time += seg->media_start;
4760 /* get the index of the sample with media time */
4761 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4762 GST_DEBUG_OBJECT (qtdemux,
4763 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4764 GST_TIME_ARGS (seg_time), index);
4766 /* find previous keyframe */
4767 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4770 /* Remember until where we want to go */
4771 str->to_sample = str->from_sample - 1;
4772 /* Define our time position */
4774 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4775 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4776 if (seg->media_start != GST_CLOCK_TIME_NONE)
4777 str->time_position -= seg->media_start;
4779 /* Now seek back in time */
4780 gst_qtdemux_move_stream (qtdemux, str, k_index);
4781 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4782 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4783 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4789 return GST_FLOW_EOS;
4793 * Gets the current qt segment start, stop and position for the
4794 * given time offset. This is used in update_segment()
4797 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4798 QtDemuxStream * stream, GstClockTime offset,
4799 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4801 GstClockTime seg_time;
4802 GstClockTime start, stop, time;
4803 QtDemuxSegment *segment;
4805 segment = &stream->segments[stream->segment_index];
4807 /* get time in this segment */
4808 seg_time = (offset - segment->time) * segment->rate;
4810 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4811 GST_TIME_ARGS (seg_time));
4813 if (G_UNLIKELY (seg_time > segment->duration)) {
4814 GST_LOG_OBJECT (stream->pad,
4815 "seg_time > segment->duration %" GST_TIME_FORMAT,
4816 GST_TIME_ARGS (segment->duration));
4817 seg_time = segment->duration;
4820 /* qtdemux->segment.stop is in outside-time-realm, whereas
4821 * segment->media_stop is in track-time-realm.
4823 * In order to compare the two, we need to bring segment.stop
4824 * into the track-time-realm
4826 * FIXME - does this comment still hold? Don't see any conversion here */
4828 stop = qtdemux->segment.stop;
4829 if (stop == GST_CLOCK_TIME_NONE)
4830 stop = qtdemux->segment.duration;
4831 if (stop == GST_CLOCK_TIME_NONE)
4832 stop = segment->media_stop;
4835 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4837 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4838 start = segment->time + seg_time;
4840 stop = start - seg_time + segment->duration;
4841 } else if (qtdemux->segment.rate >= 0) {
4842 start = MIN (segment->media_start + seg_time, stop);
4845 if (segment->media_start >= qtdemux->segment.start) {
4846 time = segment->time;
4848 time = segment->time + (qtdemux->segment.start - segment->media_start);
4851 start = MAX (segment->media_start, qtdemux->segment.start);
4852 stop = MIN (segment->media_start + seg_time, stop);
4861 * Updates the qt segment used for the stream and pushes a new segment event
4862 * downstream on this stream's pad.
4865 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4866 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4867 GstClockTime * _stop)
4869 QtDemuxSegment *segment;
4870 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4874 /* update the current segment */
4875 stream->segment_index = seg_idx;
4877 /* get the segment */
4878 segment = &stream->segments[seg_idx];
4880 if (G_UNLIKELY (offset < segment->time)) {
4881 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4882 GST_TIME_ARGS (segment->time));
4886 /* segment lies beyond total indicated duration */
4887 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4888 segment->time > qtdemux->segment.duration)) {
4889 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4890 " < segment->time %" GST_TIME_FORMAT,
4891 GST_TIME_ARGS (qtdemux->segment.duration),
4892 GST_TIME_ARGS (segment->time));
4896 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
4897 &start, &stop, &time);
4899 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4900 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4901 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4903 /* combine global rate with that of the segment */
4904 rate = segment->rate * qtdemux->segment.rate;
4906 /* Copy flags from main segment */
4907 stream->segment.flags = qtdemux->segment.flags;
4909 /* update the segment values used for clipping */
4910 stream->segment.offset = qtdemux->segment.offset;
4911 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4912 stream->segment.applied_rate = qtdemux->segment.applied_rate;
4913 stream->segment.rate = rate;
4914 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4915 stream->cslg_shift);
4916 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4917 stream->cslg_shift);
4918 stream->segment.time = time;
4919 stream->segment.position = stream->segment.start;
4921 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4924 /* now prepare and send the segment */
4926 event = gst_event_new_segment (&stream->segment);
4927 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
4928 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
4930 gst_pad_push_event (stream->pad, event);
4931 /* assume we can send more data now */
4932 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4933 /* clear to send tags on this pad now */
4934 gst_qtdemux_push_tags (qtdemux, stream);
4945 /* activate the given segment number @seg_idx of @stream at time @offset.
4946 * @offset is an absolute global position over all the segments.
4948 * This will push out a NEWSEGMENT event with the right values and
4949 * position the stream index to the first decodable sample before
4953 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4954 guint32 seg_idx, GstClockTime offset)
4956 QtDemuxSegment *segment;
4957 guint32 index, kf_index;
4958 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
4960 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4961 seg_idx, GST_TIME_ARGS (offset));
4963 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
4967 segment = &stream->segments[stream->segment_index];
4969 /* in the fragmented case, we pick a fragment that starts before our
4970 * desired position and rely on downstream to wait for a keyframe
4971 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4972 * tfra entries tells us which trun/sample the key unit is in, but we don't
4973 * make use of this additional information at the moment) */
4974 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
4975 stream->to_sample = G_MAXUINT32;
4978 /* well, it will be taken care of below */
4979 qtdemux->fragmented_seek_pending = FALSE;
4980 /* FIXME ideally the do_fragmented_seek can be done right here,
4981 * rather than at loop level
4982 * (which might even allow handling edit lists in a fragmented file) */
4985 /* We don't need to look for a sample in push-based */
4986 if (!qtdemux->pullbased)
4989 /* and move to the keyframe before the indicated media time of the
4991 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4992 if (qtdemux->segment.rate >= 0) {
4993 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4994 stream->to_sample = G_MAXUINT32;
4995 GST_DEBUG_OBJECT (stream->pad,
4996 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4997 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4998 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5000 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5001 stream->to_sample = index;
5002 GST_DEBUG_OBJECT (stream->pad,
5003 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5004 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5005 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5008 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5009 "this is an empty segment");
5013 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5014 * encountered an error and printed a message so we return appropriately */
5018 /* we're at the right spot */
5019 if (index == stream->sample_index) {
5020 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5024 /* find keyframe of the target index */
5025 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5028 /* indent does stupid stuff with stream->samples[].timestamp */
5030 /* if we move forwards, we don't have to go back to the previous
5031 * keyframe since we already sent that. We can also just jump to
5032 * the keyframe right before the target index if there is one. */
5033 if (index > stream->sample_index) {
5034 /* moving forwards check if we move past a keyframe */
5035 if (kf_index > stream->sample_index) {
5036 GST_DEBUG_OBJECT (stream->pad,
5037 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5038 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5039 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5040 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5042 GST_DEBUG_OBJECT (stream->pad,
5043 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5044 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5045 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5048 GST_DEBUG_OBJECT (stream->pad,
5049 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5050 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5051 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5052 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5060 /* prepare to get the current sample of @stream, getting essential values.
5062 * This function will also prepare and send the segment when needed.
5064 * Return FALSE if the stream is EOS.
5069 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5070 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5071 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5072 gboolean * keyframe)
5074 QtDemuxSample *sample;
5075 GstClockTime time_position;
5078 g_return_val_if_fail (stream != NULL, FALSE);
5080 time_position = stream->time_position;
5081 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5084 seg_idx = stream->segment_index;
5085 if (G_UNLIKELY (seg_idx == -1)) {
5086 /* find segment corresponding to time_position if we are looking
5088 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5091 /* different segment, activate it, sample_index will be set. */
5092 if (G_UNLIKELY (stream->segment_index != seg_idx))
5093 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5095 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5097 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5099 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5100 " prepare empty sample");
5103 *pts = *dts = time_position;
5104 *duration = seg->duration - (time_position - seg->time);
5111 if (stream->sample_index == -1)
5112 stream->sample_index = 0;
5114 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5115 stream->sample_index, stream->n_samples);
5117 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5118 if (!qtdemux->fragmented)
5121 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5125 GST_OBJECT_LOCK (qtdemux);
5126 flow = qtdemux_add_fragmented_samples (qtdemux);
5127 GST_OBJECT_UNLOCK (qtdemux);
5129 if (flow != GST_FLOW_OK)
5132 while (stream->sample_index >= stream->n_samples);
5135 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5136 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5137 stream->sample_index);
5141 /* now get the info for the sample we're at */
5142 sample = &stream->samples[stream->sample_index];
5144 *dts = QTSAMPLE_DTS (stream, sample);
5145 *pts = QTSAMPLE_PTS (stream, sample);
5146 *offset = sample->offset;
5147 *size = sample->size;
5148 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5149 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5156 stream->time_position = GST_CLOCK_TIME_NONE;
5161 /* move to the next sample in @stream.
5163 * Moves to the next segment when needed.
5166 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5168 QtDemuxSample *sample;
5169 QtDemuxSegment *segment;
5171 /* get current segment */
5172 segment = &stream->segments[stream->segment_index];
5174 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5175 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5179 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5180 /* Mark the stream as EOS */
5181 GST_DEBUG_OBJECT (qtdemux,
5182 "reached max allowed sample %u, mark EOS", stream->to_sample);
5183 stream->time_position = GST_CLOCK_TIME_NONE;
5187 /* move to next sample */
5188 stream->sample_index++;
5189 stream->offset_in_sample = 0;
5191 /* reached the last sample, we need the next segment */
5192 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5195 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5196 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5197 stream->sample_index);
5201 /* get next sample */
5202 sample = &stream->samples[stream->sample_index];
5204 /* see if we are past the segment */
5205 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5208 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5209 /* inside the segment, update time_position, looks very familiar to
5210 * GStreamer segments, doesn't it? */
5211 stream->time_position =
5212 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5214 /* not yet in segment, time does not yet increment. This means
5215 * that we are still prerolling keyframes to the decoder so it can
5216 * decode the first sample of the segment. */
5217 stream->time_position = segment->time;
5221 /* move to the next segment */
5224 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5226 if (stream->segment_index == stream->n_segments - 1) {
5227 /* are we at the end of the last segment, we're EOS */
5228 stream->time_position = GST_CLOCK_TIME_NONE;
5230 /* else we're only at the end of the current segment */
5231 stream->time_position = segment->stop_time;
5233 /* make sure we select a new segment */
5235 /* accumulate previous segments */
5236 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5237 stream->accumulated_base +=
5238 (stream->segment.stop -
5239 stream->segment.start) / ABS (stream->segment.rate);
5241 stream->segment_index = -1;
5246 gst_qtdemux_sync_streams (GstQTDemux * demux)
5250 if (demux->n_streams <= 1)
5253 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
5254 QtDemuxStream *stream;
5255 GstClockTime end_time;
5257 stream = QTDEMUX_STREAM (iter->data);
5262 /* TODO advance time on subtitle streams here, if any some day */
5264 /* some clips/trailers may have unbalanced streams at the end,
5265 * so send EOS on shorter stream to prevent stalling others */
5267 /* do not mess with EOS if SEGMENT seeking */
5268 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5271 if (demux->pullbased) {
5272 /* loop mode is sample time based */
5273 if (!STREAM_IS_EOS (stream))
5276 /* push mode is byte position based */
5277 if (stream->n_samples &&
5278 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5282 if (stream->sent_eos)
5285 /* only act if some gap */
5286 end_time = stream->segments[stream->n_segments - 1].stop_time;
5287 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5288 ", stream end: %" GST_TIME_FORMAT,
5289 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5290 if (GST_CLOCK_TIME_IS_VALID (end_time)
5291 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5294 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5295 GST_PAD_NAME (stream->pad));
5296 stream->sent_eos = TRUE;
5297 event = gst_event_new_eos ();
5298 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5299 gst_event_set_seqnum (event, demux->segment_seqnum);
5300 gst_pad_push_event (stream->pad, event);
5305 /* EOS and NOT_LINKED need to be combined. This means that we return:
5307 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5308 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5310 static GstFlowReturn
5311 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5314 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5317 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5320 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5322 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5326 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5327 * completely clipped
5329 * Should be used only with raw buffers */
5331 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5334 guint64 start, stop, cstart, cstop, diff;
5335 GstClockTime pts, duration;
5337 gint num_rate, denom_rate;
5342 osize = size = gst_buffer_get_size (buf);
5345 /* depending on the type, setup the clip parameters */
5346 if (stream->subtype == FOURCC_soun) {
5347 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5348 num_rate = GST_SECOND;
5349 denom_rate = (gint) CUR_STREAM (stream)->rate;
5351 } else if (stream->subtype == FOURCC_vide) {
5353 num_rate = CUR_STREAM (stream)->fps_n;
5354 denom_rate = CUR_STREAM (stream)->fps_d;
5359 if (frame_size <= 0)
5360 goto bad_frame_size;
5362 /* we can only clip if we have a valid pts */
5363 pts = GST_BUFFER_PTS (buf);
5364 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5367 duration = GST_BUFFER_DURATION (buf);
5369 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5371 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5375 stop = start + duration;
5377 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5378 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5381 /* see if some clipping happened */
5382 diff = cstart - start;
5388 /* bring clipped time to samples and to bytes */
5389 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5392 GST_DEBUG_OBJECT (qtdemux,
5393 "clipping start to %" GST_TIME_FORMAT " %"
5394 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5400 diff = stop - cstop;
5405 /* bring clipped time to samples and then to bytes */
5406 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5408 GST_DEBUG_OBJECT (qtdemux,
5409 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5410 " bytes", GST_TIME_ARGS (cstop), diff);
5415 if (offset != 0 || size != osize)
5416 gst_buffer_resize (buf, offset, size);
5418 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5419 GST_BUFFER_PTS (buf) = pts;
5420 GST_BUFFER_DURATION (buf) = duration;
5424 /* dropped buffer */
5427 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5432 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5437 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5442 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5443 gst_buffer_unref (buf);
5449 gst_qtdemux_align_buffer (GstQTDemux * demux,
5450 GstBuffer * buffer, gsize alignment)
5454 gst_buffer_map (buffer, &map, GST_MAP_READ);
5456 if (map.size < sizeof (guintptr)) {
5457 gst_buffer_unmap (buffer, &map);
5461 if (((guintptr) map.data) & (alignment - 1)) {
5462 GstBuffer *new_buffer;
5463 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5465 new_buffer = gst_buffer_new_allocate (NULL,
5466 gst_buffer_get_size (buffer), ¶ms);
5468 /* Copy data "by hand", so ensure alignment is kept: */
5469 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5471 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5472 GST_DEBUG_OBJECT (demux,
5473 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5476 gst_buffer_unmap (buffer, &map);
5477 gst_buffer_unref (buffer);
5482 gst_buffer_unmap (buffer, &map);
5487 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5493 /* We are converting from pairs to triplets */
5494 *res = ccpair_size / 2 * 3;
5495 storage = g_malloc (*res);
5496 for (i = 0; i * 2 < ccpair_size; i += 1) {
5498 storage[i * 3] = 0xfc;
5500 storage[i * 3] = 0xfd;
5501 storage[i * 3 + 1] = ccpair[i * 2];
5502 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5509 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5513 guint32 atom_length, fourcc;
5514 QtDemuxStreamStsdEntry *stsd_entry;
5516 GST_MEMDUMP ("caption atom", data, size);
5518 /* There might be multiple atoms */
5523 atom_length = QT_UINT32 (data);
5524 fourcc = QT_FOURCC (data + 4);
5525 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5528 GST_DEBUG_OBJECT (stream->pad, "here");
5530 /* Check if we have somethig compatible */
5531 stsd_entry = CUR_STREAM (stream);
5532 switch (stsd_entry->fourcc) {
5534 guint8 *cdat = NULL, *cdt2 = NULL;
5535 gsize cdat_size = 0, cdt2_size = 0;
5536 /* Should be cdat or cdt2 */
5537 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5538 GST_WARNING_OBJECT (stream->pad,
5539 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5540 GST_FOURCC_ARGS (fourcc));
5544 /* Convert to cc_data triplet */
5545 if (fourcc == FOURCC_cdat)
5546 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5548 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5549 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5552 /* Check for another atom ? */
5553 if (size > atom_length + 8) {
5554 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5555 if (size >= atom_length + new_atom_length) {
5556 fourcc = QT_FOURCC (data + atom_length + 4);
5557 if (fourcc == FOURCC_cdat) {
5560 convert_to_ccdata (data + atom_length + 8,
5561 new_atom_length - 8, 1, &cdat_size);
5563 GST_WARNING_OBJECT (stream->pad,
5564 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5568 convert_to_ccdata (data + atom_length + 8,
5569 new_atom_length - 8, 2, &cdt2_size);
5571 GST_WARNING_OBJECT (stream->pad,
5572 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5577 *cclen = cdat_size + cdt2_size;
5578 res = g_malloc (*cclen);
5580 memcpy (res, cdat, cdat_size);
5582 memcpy (res + cdat_size, cdt2, cdt2_size);
5588 if (fourcc != FOURCC_ccdp) {
5589 GST_WARNING_OBJECT (stream->pad,
5590 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5591 GST_FOURCC_ARGS (fourcc));
5594 *cclen = atom_length - 8;
5595 res = g_memdup (data + 8, *cclen);
5598 /* Keep this here in case other closed caption formats are added */
5599 g_assert_not_reached ();
5603 GST_MEMDUMP ("Output", res, *cclen);
5608 GST_WARNING ("[cdat] atom is too small or invalid");
5612 /* the input buffer metadata must be writable,
5613 * but time/duration etc not yet set and need not be preserved */
5615 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5622 /* not many cases for now */
5623 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5624 /* send a one time dvd clut event */
5625 if (stream->pending_event && stream->pad)
5626 gst_pad_push_event (stream->pad, stream->pending_event);
5627 stream->pending_event = NULL;
5630 if (G_UNLIKELY (stream->subtype != FOURCC_text
5631 && stream->subtype != FOURCC_sbtl &&
5632 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5636 gst_buffer_map (buf, &map, GST_MAP_READ);
5638 /* empty buffer is sent to terminate previous subtitle */
5639 if (map.size <= 2) {
5640 gst_buffer_unmap (buf, &map);
5641 gst_buffer_unref (buf);
5644 if (stream->subtype == FOURCC_subp) {
5645 /* That's all the processing needed for subpictures */
5646 gst_buffer_unmap (buf, &map);
5650 if (stream->subtype == FOURCC_clcp) {
5653 /* For closed caption, we need to extract the information from the
5654 * [cdat],[cdt2] or [ccdp] atom */
5655 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5656 gst_buffer_unmap (buf, &map);
5657 gst_buffer_unref (buf);
5659 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5661 /* Conversion failed or there's nothing */
5667 nsize = GST_READ_UINT16_BE (map.data);
5668 nsize = MIN (nsize, map.size - 2);
5670 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5673 /* takes care of UTF-8 validation or UTF-16 recognition,
5674 * no other encoding expected */
5675 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5676 gst_buffer_unmap (buf, &map);
5678 gst_buffer_unref (buf);
5679 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5681 /* this should not really happen unless the subtitle is corrupted */
5682 gst_buffer_unref (buf);
5686 /* FIXME ? convert optional subsequent style info to markup */
5691 /* Sets a buffer's attributes properly and pushes it downstream.
5692 * Also checks for additional actions and custom processing that may
5693 * need to be done first.
5695 static GstFlowReturn
5696 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5697 QtDemuxStream * stream, GstBuffer * buf,
5698 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5699 gboolean keyframe, GstClockTime position, guint64 byte_position)
5701 GstFlowReturn ret = GST_FLOW_OK;
5703 /* offset the timestamps according to the edit list */
5705 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5709 gst_buffer_map (buf, &map, GST_MAP_READ);
5710 url = g_strndup ((gchar *) map.data, map.size);
5711 gst_buffer_unmap (buf, &map);
5712 if (url != NULL && strlen (url) != 0) {
5713 /* we have RTSP redirect now */
5714 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5715 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5716 gst_structure_new ("redirect",
5717 "new-location", G_TYPE_STRING, url, NULL)));
5718 qtdemux->posted_redirect = TRUE;
5720 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5726 /* position reporting */
5727 if (qtdemux->segment.rate >= 0) {
5728 qtdemux->segment.position = position;
5729 gst_qtdemux_sync_streams (qtdemux);
5732 if (G_UNLIKELY (!stream->pad)) {
5733 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5734 gst_buffer_unref (buf);
5738 /* send out pending buffers */
5739 while (stream->buffers) {
5740 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5742 if (G_UNLIKELY (stream->discont)) {
5743 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5744 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5745 stream->discont = FALSE;
5747 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5750 if (stream->alignment > 1)
5751 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5752 gst_pad_push (stream->pad, buffer);
5754 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5757 /* we're going to modify the metadata */
5758 buf = gst_buffer_make_writable (buf);
5760 if (G_UNLIKELY (stream->need_process))
5761 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5767 GST_BUFFER_DTS (buf) = dts;
5768 GST_BUFFER_PTS (buf) = pts;
5769 GST_BUFFER_DURATION (buf) = duration;
5770 GST_BUFFER_OFFSET (buf) = -1;
5771 GST_BUFFER_OFFSET_END (buf) = -1;
5773 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5774 gst_buffer_append_memory (buf,
5775 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5777 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5778 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5781 if (G_UNLIKELY (qtdemux->element_index)) {
5782 GstClockTime stream_time;
5785 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5787 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5788 GST_LOG_OBJECT (qtdemux,
5789 "adding association %" GST_TIME_FORMAT "-> %"
5790 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5791 gst_index_add_association (qtdemux->element_index,
5793 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5794 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5795 GST_FORMAT_BYTES, byte_position, NULL);
5800 if (stream->need_clip)
5801 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5803 if (G_UNLIKELY (buf == NULL))
5806 if (G_UNLIKELY (stream->discont)) {
5807 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5808 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5809 stream->discont = FALSE;
5811 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5815 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5816 stream->on_keyframe = FALSE;
5818 stream->on_keyframe = TRUE;
5822 GST_LOG_OBJECT (qtdemux,
5823 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5824 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5825 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5826 GST_PAD_NAME (stream->pad));
5828 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5829 GstStructure *crypto_info;
5830 QtDemuxCencSampleSetInfo *info =
5831 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5835 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5836 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5837 GST_PTR_FORMAT, event);
5838 gst_pad_push_event (stream->pad, event);
5841 if (info->crypto_info == NULL) {
5842 GST_DEBUG_OBJECT (qtdemux,
5843 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5845 /* The end of the crypto_info array matches our n_samples position,
5846 * so count backward from there */
5847 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5848 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5849 /* steal structure from array */
5850 crypto_info = g_ptr_array_index (info->crypto_info, index);
5851 g_ptr_array_index (info->crypto_info, index) = NULL;
5852 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5853 info->crypto_info->len);
5854 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5855 GST_ERROR_OBJECT (qtdemux,
5856 "failed to attach cenc metadata to buffer");
5858 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5859 index, stream->sample_index);
5864 if (stream->alignment > 1)
5865 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5867 ret = gst_pad_push (stream->pad, buf);
5869 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5870 /* mark position in stream, we'll need this to know when to send GAP event */
5871 stream->segment.position = pts + duration;
5878 static const QtDemuxRandomAccessEntry *
5879 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5880 GstClockTime pos, gboolean after)
5882 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5883 guint n_entries = stream->n_ra_entries;
5886 /* we assume the table is sorted */
5887 for (i = 0; i < n_entries; ++i) {
5888 if (entries[i].ts > pos)
5892 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5893 * probably okay to assume that the index lists the very first fragment */
5900 return &entries[i - 1];
5904 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5906 const QtDemuxRandomAccessEntry *best_entry = NULL;
5909 GST_OBJECT_LOCK (qtdemux);
5911 g_assert (qtdemux->n_streams > 0);
5913 /* first see if we can determine where to go to using mfra,
5914 * before we start clearing things */
5915 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5916 const QtDemuxRandomAccessEntry *entry;
5917 QtDemuxStream *stream;
5918 gboolean is_audio_or_video;
5920 stream = QTDEMUX_STREAM (iter->data);
5922 if (stream->ra_entries == NULL)
5925 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5926 is_audio_or_video = TRUE;
5928 is_audio_or_video = FALSE;
5931 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5932 stream->time_position, !is_audio_or_video);
5934 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5935 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5937 stream->pending_seek = entry;
5939 /* decide position to jump to just based on audio/video tracks, not subs */
5940 if (!is_audio_or_video)
5943 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5947 /* no luck, will handle seek otherwise */
5948 if (best_entry == NULL) {
5949 GST_OBJECT_UNLOCK (qtdemux);
5953 /* ok, now we can prepare for processing as of located moof */
5954 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
5955 QtDemuxStream *stream;
5957 stream = QTDEMUX_STREAM (iter->data);
5959 g_free (stream->samples);
5960 stream->samples = NULL;
5961 stream->n_samples = 0;
5962 stream->stbl_index = -1; /* no samples have yet been parsed */
5963 stream->sample_index = -1;
5965 if (stream->protection_scheme_info) {
5966 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
5967 if (stream->protection_scheme_type == FOURCC_cenc) {
5968 QtDemuxCencSampleSetInfo *info =
5969 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5970 if (info->crypto_info) {
5971 g_ptr_array_free (info->crypto_info, TRUE);
5972 info->crypto_info = NULL;
5978 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5979 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5980 GST_TIME_ARGS (QTDEMUX_FIRST_STREAM (qtdemux)->time_position),
5981 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5983 qtdemux->moof_offset = best_entry->moof_offset;
5985 qtdemux_add_fragmented_samples (qtdemux);
5987 GST_OBJECT_UNLOCK (qtdemux);
5991 static GstFlowReturn
5992 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5994 GstFlowReturn ret = GST_FLOW_OK;
5995 GstBuffer *buf = NULL;
5996 QtDemuxStream *stream, *target_stream = NULL;
5997 GstClockTime min_time;
5999 GstClockTime dts = GST_CLOCK_TIME_NONE;
6000 GstClockTime pts = GST_CLOCK_TIME_NONE;
6001 GstClockTime duration = 0;
6002 gboolean keyframe = FALSE;
6003 guint sample_size = 0;
6008 gst_qtdemux_push_pending_newsegment (qtdemux);
6010 if (qtdemux->fragmented_seek_pending) {
6011 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6012 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6013 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6014 qtdemux->fragmented_seek_pending = FALSE;
6016 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6020 /* Figure out the next stream sample to output, min_time is expressed in
6021 * global time and runs over the edit list segments. */
6022 min_time = G_MAXUINT64;
6023 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6024 GstClockTime position;
6026 stream = QTDEMUX_STREAM (iter->data);
6027 position = stream->time_position;
6029 /* position of -1 is EOS */
6030 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6031 min_time = position;
6032 target_stream = stream;
6036 if (G_UNLIKELY (target_stream == NULL)) {
6037 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6041 /* check for segment end */
6042 if (G_UNLIKELY (qtdemux->segment.stop != -1
6043 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6044 || (qtdemux->segment.rate < 0
6045 && qtdemux->segment.start > min_time))
6046 && target_stream->on_keyframe)) {
6047 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6048 target_stream->time_position = GST_CLOCK_TIME_NONE;
6052 /* gap events for subtitle streams */
6053 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
6054 stream = QTDEMUX_STREAM (iter->data);
6055 if (stream->pad && (stream->subtype == FOURCC_subp
6056 || stream->subtype == FOURCC_text
6057 || stream->subtype == FOURCC_sbtl)) {
6058 /* send one second gap events until the stream catches up */
6059 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6060 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6061 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6062 stream->segment.position + GST_SECOND < min_time) {
6064 gst_event_new_gap (stream->segment.position, GST_SECOND);
6065 gst_pad_push_event (stream->pad, gap);
6066 stream->segment.position += GST_SECOND;
6071 stream = target_stream;
6072 /* fetch info for the current sample of this stream */
6073 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6074 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6077 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6078 if (stream->new_caps) {
6079 gst_qtdemux_configure_stream (qtdemux, stream);
6080 qtdemux_do_allocation (qtdemux, stream);
6083 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6084 if (G_UNLIKELY (qtdemux->
6085 segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6086 if (stream->subtype == FOURCC_vide && !keyframe) {
6087 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6093 GST_DEBUG_OBJECT (qtdemux,
6094 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6095 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6096 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6097 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6098 GST_TIME_ARGS (duration));
6100 if (G_UNLIKELY (empty)) {
6101 /* empty segment, push a gap if there's a second or more
6102 * difference and move to the next one */
6103 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6104 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6105 stream->segment.position = pts + duration;
6109 /* hmm, empty sample, skip and move to next sample */
6110 if (G_UNLIKELY (sample_size <= 0))
6113 /* last pushed sample was out of boundary, goto next sample */
6114 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6117 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6120 GST_DEBUG_OBJECT (qtdemux,
6121 "size %d larger than stream max_buffer_size %d, trimming",
6122 sample_size, stream->max_buffer_size);
6124 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6127 if (qtdemux->cenc_aux_info_offset > 0) {
6130 GstBuffer *aux_info = NULL;
6132 /* pull the data stored before the sample */
6134 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6135 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6136 if (G_UNLIKELY (ret != GST_FLOW_OK))
6138 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6139 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6140 gst_byte_reader_init (&br, map.data + 8, map.size);
6141 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6142 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6143 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6144 gst_buffer_unmap (aux_info, &map);
6145 gst_buffer_unref (aux_info);
6146 ret = GST_FLOW_ERROR;
6149 gst_buffer_unmap (aux_info, &map);
6150 gst_buffer_unref (aux_info);
6153 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6156 if (stream->use_allocator) {
6157 /* if we have a per-stream allocator, use it */
6158 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6161 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6163 if (G_UNLIKELY (ret != GST_FLOW_OK))
6166 if (size != sample_size) {
6167 pts += gst_util_uint64_scale_int (GST_SECOND,
6168 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6171 gst_util_uint64_scale_int (GST_SECOND,
6172 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6175 gst_util_uint64_scale_int (GST_SECOND,
6176 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6179 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6180 dts, pts, duration, keyframe, min_time, offset);
6182 if (size != sample_size) {
6183 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6184 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6186 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6188 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6189 if (time_position >= segment->media_start) {
6190 /* inside the segment, update time_position, looks very familiar to
6191 * GStreamer segments, doesn't it? */
6192 stream->time_position = (time_position - segment->media_start) +
6195 /* not yet in segment, time does not yet increment. This means
6196 * that we are still prerolling keyframes to the decoder so it can
6197 * decode the first sample of the segment. */
6198 stream->time_position = segment->time;
6203 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6204 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6205 * we have no more data for the pad to push */
6206 if (ret == GST_FLOW_EOS)
6209 stream->offset_in_sample += size;
6210 if (stream->offset_in_sample >= sample_size) {
6211 gst_qtdemux_advance_sample (qtdemux, stream);
6216 gst_qtdemux_advance_sample (qtdemux, stream);
6224 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6230 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6231 /* EOS will be raised if all are EOS */
6238 gst_qtdemux_loop (GstPad * pad)
6240 GstQTDemux *qtdemux;
6244 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6246 cur_offset = qtdemux->offset;
6247 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6248 cur_offset, qt_demux_state_string (qtdemux->state));
6250 switch (qtdemux->state) {
6251 case QTDEMUX_STATE_INITIAL:
6252 case QTDEMUX_STATE_HEADER:
6253 ret = gst_qtdemux_loop_state_header (qtdemux);
6255 case QTDEMUX_STATE_MOVIE:
6256 ret = gst_qtdemux_loop_state_movie (qtdemux);
6257 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6258 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6266 /* if something went wrong, pause */
6267 if (ret != GST_FLOW_OK)
6271 gst_object_unref (qtdemux);
6277 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6278 (NULL), ("streaming stopped, invalid state"));
6279 gst_pad_pause_task (pad);
6280 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6285 const gchar *reason = gst_flow_get_name (ret);
6287 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6289 gst_pad_pause_task (pad);
6291 /* fatal errors need special actions */
6293 if (ret == GST_FLOW_EOS) {
6294 if (qtdemux->n_streams == 0) {
6295 /* we have no streams, post an error */
6296 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6298 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6301 if ((stop = qtdemux->segment.stop) == -1)
6302 stop = qtdemux->segment.duration;
6304 if (qtdemux->segment.rate >= 0) {
6305 GstMessage *message;
6308 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6309 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6310 GST_FORMAT_TIME, stop);
6311 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6312 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6313 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6314 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6316 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6317 gst_qtdemux_push_event (qtdemux, event);
6319 GstMessage *message;
6322 /* For Reverse Playback */
6323 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6324 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6325 GST_FORMAT_TIME, qtdemux->segment.start);
6326 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6327 qtdemux->segment.start);
6328 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6329 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6330 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6332 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6333 gst_qtdemux_push_event (qtdemux, event);
6338 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6339 event = gst_event_new_eos ();
6340 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6341 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6342 gst_qtdemux_push_event (qtdemux, event);
6344 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6345 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6346 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6355 * Returns if there are samples to be played.
6358 has_next_entry (GstQTDemux * demux)
6360 QtDemuxStream *stream;
6363 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6365 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6366 stream = QTDEMUX_STREAM (iter->data);
6368 if (stream->sample_index == -1) {
6369 stream->sample_index = 0;
6370 stream->offset_in_sample = 0;
6373 if (stream->sample_index >= stream->n_samples) {
6374 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6377 GST_DEBUG_OBJECT (demux, "Found a sample");
6381 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6388 * Returns the size of the first entry at the current offset.
6389 * If -1, there are none (which means EOS or empty file).
6392 next_entry_size (GstQTDemux * demux)
6394 QtDemuxStream *stream, *target_stream = NULL;
6395 guint64 smalloffs = (guint64) - 1;
6396 QtDemuxSample *sample;
6399 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6402 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6403 stream = QTDEMUX_STREAM (iter->data);
6405 if (stream->sample_index == -1) {
6406 stream->sample_index = 0;
6407 stream->offset_in_sample = 0;
6410 if (stream->sample_index >= stream->n_samples) {
6411 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6415 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6416 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6417 stream->sample_index);
6421 sample = &stream->samples[stream->sample_index];
6423 GST_LOG_OBJECT (demux,
6424 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6425 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6426 stream->sample_index, sample->offset, sample->size);
6428 if (((smalloffs == -1)
6429 || (sample->offset < smalloffs)) && (sample->size)) {
6430 smalloffs = sample->offset;
6431 target_stream = stream;
6438 GST_LOG_OBJECT (demux,
6439 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6440 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6442 stream = target_stream;
6443 sample = &stream->samples[stream->sample_index];
6445 if (sample->offset >= demux->offset) {
6446 demux->todrop = sample->offset - demux->offset;
6447 return sample->size + demux->todrop;
6450 GST_DEBUG_OBJECT (demux,
6451 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6456 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6458 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6460 gst_element_post_message (GST_ELEMENT_CAST (demux),
6461 gst_message_new_element (GST_OBJECT_CAST (demux),
6462 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6466 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6471 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6474 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6475 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6476 GST_SEEK_TYPE_NONE, -1);
6478 /* store seqnum to drop flush events, they don't need to reach downstream */
6479 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6480 res = gst_pad_push_event (demux->sinkpad, event);
6481 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6486 /* check for seekable upstream, above and beyond a mere query */
6488 gst_qtdemux_check_seekability (GstQTDemux * demux)
6491 gboolean seekable = FALSE;
6492 gint64 start = -1, stop = -1;
6494 if (demux->upstream_size)
6497 if (demux->upstream_format_is_time)
6500 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6501 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6502 GST_DEBUG_OBJECT (demux, "seeking query failed");
6506 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6508 /* try harder to query upstream size if we didn't get it the first time */
6509 if (seekable && stop == -1) {
6510 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6511 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6514 /* if upstream doesn't know the size, it's likely that it's not seekable in
6515 * practice even if it technically may be seekable */
6516 if (seekable && (start != 0 || stop <= start)) {
6517 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6522 gst_query_unref (query);
6524 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6525 G_GUINT64_FORMAT ")", seekable, start, stop);
6526 demux->upstream_seekable = seekable;
6527 demux->upstream_size = seekable ? stop : -1;
6531 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6533 g_return_if_fail (bytes <= demux->todrop);
6535 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6536 gst_adapter_flush (demux->adapter, bytes);
6537 demux->neededbytes -= bytes;
6538 demux->offset += bytes;
6539 demux->todrop -= bytes;
6543 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6545 if (G_UNLIKELY (demux->need_segment)) {
6549 gst_qtdemux_push_pending_newsegment (demux);
6550 /* clear to send tags on all streams */
6551 for (iter = demux->active_streams, i = 0; iter;
6552 iter = g_list_next (iter), i++) {
6553 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6554 gst_qtdemux_push_tags (demux, stream);
6555 if (CUR_STREAM (stream)->sparse) {
6556 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6557 gst_pad_push_event (stream->pad,
6558 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6564 /* Used for push mode only. */
6566 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6567 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6569 GstClockTime ts, dur;
6573 stream->segments[segment_index].duration - (pos -
6574 stream->segments[segment_index].time);
6575 stream->time_position += dur;
6577 /* Only gaps with a duration of at least one second are propagated.
6578 * Same workaround as in pull mode.
6579 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6580 if (dur >= GST_SECOND) {
6582 gap = gst_event_new_gap (ts, dur);
6584 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6585 "segment: %" GST_PTR_FORMAT, gap);
6586 gst_pad_push_event (stream->pad, gap);
6591 gst_qtdemux_streams_get_first_sample_ts (GstQTDemux * demux)
6593 GstClockTime res = GST_CLOCK_TIME_NONE;
6596 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6597 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6598 if (stream->n_samples) {
6599 res = MIN (QTSAMPLE_PTS (stream, &stream->samples[0]), res);
6600 res = MIN (QTSAMPLE_DTS (stream, &stream->samples[0]), res);
6607 gst_qtdemux_streams_have_samples (GstQTDemux * demux)
6611 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6612 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6613 if (stream->n_samples)
6619 static GstFlowReturn
6620 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6624 demux = GST_QTDEMUX (parent);
6626 GST_DEBUG_OBJECT (demux,
6627 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6628 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6629 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6630 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6631 gst_buffer_get_size (inbuf), demux->offset);
6633 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6634 gboolean is_gap_input = FALSE;
6637 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6639 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6640 QTDEMUX_STREAM (iter->data)->discont = TRUE;
6643 /* Check if we can land back on our feet in the case where upstream is
6644 * handling the seeking/pushing of samples with gaps in between (like
6645 * in the case of trick-mode DASH for example) */
6646 if (demux->upstream_format_is_time
6647 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6648 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
6650 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
6651 GST_LOG_OBJECT (demux,
6652 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6653 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6655 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6656 stream, GST_BUFFER_OFFSET (inbuf));
6658 QtDemuxSample *sample = &stream->samples[res];
6659 GST_LOG_OBJECT (demux,
6660 "Checking if sample %d from track-id %u is valid (offset:%"
6661 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6662 stream->track_id, sample->offset, sample->size);
6663 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6664 GST_LOG_OBJECT (demux,
6665 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6667 is_gap_input = TRUE;
6668 /* We can go back to standard playback mode */
6669 demux->state = QTDEMUX_STATE_MOVIE;
6670 /* Remember which sample this stream is at */
6671 stream->sample_index = res;
6672 /* Finally update all push-based values to the expected values */
6673 demux->neededbytes = stream->samples[res].size;
6674 demux->offset = GST_BUFFER_OFFSET (inbuf);
6676 demux->mdatsize - demux->offset + demux->mdatoffset;
6681 if (!is_gap_input) {
6682 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6683 /* Reset state if it's a real discont */
6684 demux->neededbytes = 16;
6685 demux->state = QTDEMUX_STATE_INITIAL;
6686 demux->offset = GST_BUFFER_OFFSET (inbuf);
6687 gst_adapter_clear (demux->adapter);
6690 /* Reverse fragmented playback, need to flush all we have before
6691 * consuming a new fragment.
6692 * The samples array have the timestamps calculated by accumulating the
6693 * durations but this won't work for reverse playback of fragments as
6694 * the timestamps of a subsequent fragment should be smaller than the
6695 * previously received one. */
6696 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6697 gst_qtdemux_process_adapter (demux, TRUE);
6698 g_list_foreach (demux->active_streams,
6699 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6703 gst_adapter_push (demux->adapter, inbuf);
6705 GST_DEBUG_OBJECT (demux,
6706 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6707 demux->neededbytes, gst_adapter_available (demux->adapter));
6709 return gst_qtdemux_process_adapter (demux, FALSE);
6712 static GstFlowReturn
6713 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6715 GstFlowReturn ret = GST_FLOW_OK;
6717 /* we never really mean to buffer that much */
6718 if (demux->neededbytes == -1) {
6722 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6723 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6725 #ifndef GST_DISABLE_GST_DEBUG
6727 guint64 discont_offset, distance_from_discont;
6729 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6730 distance_from_discont =
6731 gst_adapter_distance_from_discont (demux->adapter);
6733 GST_DEBUG_OBJECT (demux,
6734 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6735 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6736 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6737 demux->offset, discont_offset, distance_from_discont);
6741 switch (demux->state) {
6742 case QTDEMUX_STATE_INITIAL:{
6747 gst_qtdemux_check_seekability (demux);
6749 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6751 /* get fourcc/length, set neededbytes */
6752 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6754 gst_adapter_unmap (demux->adapter);
6756 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6757 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6759 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6760 (_("This file is invalid and cannot be played.")),
6761 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6762 GST_FOURCC_ARGS (fourcc)));
6763 ret = GST_FLOW_ERROR;
6766 if (fourcc == FOURCC_mdat) {
6767 gint next_entry = next_entry_size (demux);
6768 if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6769 /* we have the headers, start playback */
6770 demux->state = QTDEMUX_STATE_MOVIE;
6771 demux->neededbytes = next_entry;
6772 demux->mdatleft = size;
6773 demux->mdatsize = demux->mdatleft;
6775 /* no headers yet, try to get them */
6778 guint64 old, target;
6781 old = demux->offset;
6782 target = old + size;
6784 /* try to jump over the atom with a seek */
6785 /* only bother if it seems worth doing so,
6786 * and avoids possible upstream/server problems */
6787 if (demux->upstream_seekable &&
6788 demux->upstream_size > 4 * (1 << 20)) {
6789 res = qtdemux_seek_offset (demux, target);
6791 GST_DEBUG_OBJECT (demux, "skipping seek");
6796 GST_DEBUG_OBJECT (demux, "seek success");
6797 /* remember the offset fo the first mdat so we can seek back to it
6798 * after we have the headers */
6799 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6800 demux->first_mdat = old;
6801 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6804 /* seek worked, continue reading */
6805 demux->offset = target;
6806 demux->neededbytes = 16;
6807 demux->state = QTDEMUX_STATE_INITIAL;
6809 /* seek failed, need to buffer */
6810 demux->offset = old;
6811 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6812 /* there may be multiple mdat (or alike) buffers */
6814 if (demux->mdatbuffer)
6815 bs = gst_buffer_get_size (demux->mdatbuffer);
6818 if (size + bs > 10 * (1 << 20))
6820 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6821 demux->neededbytes = size;
6822 if (!demux->mdatbuffer)
6823 demux->mdatoffset = demux->offset;
6826 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6827 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6828 (_("This file is invalid and cannot be played.")),
6829 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6830 GST_FOURCC_ARGS (fourcc), size));
6831 ret = GST_FLOW_ERROR;
6834 /* this means we already started buffering and still no moov header,
6835 * let's continue buffering everything till we get moov */
6836 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6837 || fourcc == FOURCC_moof))
6839 demux->neededbytes = size;
6840 demux->state = QTDEMUX_STATE_HEADER;
6844 case QTDEMUX_STATE_HEADER:{
6848 GST_DEBUG_OBJECT (demux, "In header");
6850 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6852 /* parse the header */
6853 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6855 if (fourcc == FOURCC_moov) {
6856 /* in usual fragmented setup we could try to scan for more
6857 * and end up at the the moov (after mdat) again */
6858 if (demux->got_moov && demux->n_streams > 0 &&
6860 || demux->last_moov_offset == demux->offset)) {
6861 GST_DEBUG_OBJECT (demux,
6862 "Skipping moov atom as we have (this) one already");
6864 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6866 if (demux->got_moov && demux->fragmented) {
6867 GST_DEBUG_OBJECT (demux,
6868 "Got a second moov, clean up data from old one");
6869 if (demux->moov_node_compressed) {
6870 g_node_destroy (demux->moov_node_compressed);
6871 if (demux->moov_node)
6872 g_free (demux->moov_node->data);
6874 demux->moov_node_compressed = NULL;
6875 if (demux->moov_node)
6876 g_node_destroy (demux->moov_node);
6877 demux->moov_node = NULL;
6880 demux->last_moov_offset = demux->offset;
6882 /* Update streams with new moov */
6883 demux->old_streams =
6884 g_list_concat (demux->old_streams, demux->active_streams);
6885 demux->active_streams = NULL;
6887 qtdemux_parse_moov (demux, data, demux->neededbytes);
6888 qtdemux_node_dump (demux, demux->moov_node);
6889 qtdemux_parse_tree (demux);
6890 qtdemux_prepare_streams (demux);
6891 QTDEMUX_EXPOSE_LOCK (demux);
6892 qtdemux_expose_streams (demux);
6893 QTDEMUX_EXPOSE_UNLOCK (demux);
6895 demux->got_moov = TRUE;
6896 demux->need_segment = TRUE;
6897 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6899 if (demux->moov_node_compressed) {
6900 g_node_destroy (demux->moov_node_compressed);
6901 g_free (demux->moov_node->data);
6903 demux->moov_node_compressed = NULL;
6904 g_node_destroy (demux->moov_node);
6905 demux->moov_node = NULL;
6906 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6908 } else if (fourcc == FOURCC_moof) {
6909 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6911 GstClockTime prev_pts;
6912 guint64 prev_offset;
6913 guint64 adapter_discont_offset, adapter_discont_dist;
6915 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6918 * The timestamp of the moof buffer is relevant as some scenarios
6919 * won't have the initial timestamp in the atoms. Whenever a new
6920 * buffer has started, we get that buffer's PTS and use it as a base
6921 * timestamp for the trun entries.
6923 * To keep track of the current buffer timestamp and starting point
6924 * we use gst_adapter_prev_pts that gives us the PTS and the distance
6925 * from the beggining of the buffer, with the distance and demux->offset
6926 * we know if it is still the same buffer or not.
6928 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6929 prev_offset = demux->offset - dist;
6930 if (demux->fragment_start_offset == -1
6931 || prev_offset > demux->fragment_start_offset) {
6932 demux->fragment_start_offset = prev_offset;
6933 demux->fragment_start = prev_pts;
6934 GST_DEBUG_OBJECT (demux,
6935 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6936 GST_TIME_FORMAT, demux->fragment_start_offset,
6937 GST_TIME_ARGS (demux->fragment_start));
6940 /* We can't use prev_offset() here because this would require
6941 * upstream to set consistent and correct offsets on all buffers
6942 * since the discont. Nothing ever did that in the past and we
6943 * would break backwards compatibility here then.
6944 * Instead take the offset we had at the last discont and count
6945 * the bytes from there. This works with old code as there would
6946 * be no discont between moov and moof, and also works with
6947 * adaptivedemux which correctly sets offset and will set the
6948 * DISCONT flag accordingly when needed.
6950 * We also only do this for upstream TIME segments as otherwise
6951 * there are potential backwards compatibility problems with
6952 * seeking in PUSH mode and upstream providing inconsistent
6954 adapter_discont_offset =
6955 gst_adapter_offset_at_discont (demux->adapter);
6956 adapter_discont_dist =
6957 gst_adapter_distance_from_discont (demux->adapter);
6959 GST_DEBUG_OBJECT (demux,
6960 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
6961 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
6962 demux->offset, adapter_discont_offset, adapter_discont_dist);
6964 if (demux->upstream_format_is_time) {
6965 demux->moof_offset = adapter_discont_offset;
6966 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
6967 demux->moof_offset += adapter_discont_dist;
6968 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
6969 demux->moof_offset = demux->offset;
6971 demux->moof_offset = demux->offset;
6974 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6975 demux->moof_offset, NULL)) {
6976 gst_adapter_unmap (demux->adapter);
6977 ret = GST_FLOW_ERROR;
6981 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6982 if (demux->mss_mode && !demux->exposed) {
6983 QTDEMUX_EXPOSE_LOCK (demux);
6984 qtdemux_expose_streams (demux);
6985 QTDEMUX_EXPOSE_UNLOCK (demux);
6988 gst_qtdemux_check_send_pending_segment (demux);
6990 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6992 } else if (fourcc == FOURCC_ftyp) {
6993 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6994 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6995 } else if (fourcc == FOURCC_uuid) {
6996 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6997 qtdemux_parse_uuid (demux, data, demux->neededbytes);
6998 } else if (fourcc == FOURCC_sidx) {
6999 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7000 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7004 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7008 /* [free] and [skip] are padding atoms */
7009 GST_DEBUG_OBJECT (demux,
7010 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7011 GST_FOURCC_ARGS (fourcc));
7014 GST_WARNING_OBJECT (demux,
7015 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7016 GST_FOURCC_ARGS (fourcc));
7017 /* Let's jump that one and go back to initial state */
7021 gst_adapter_unmap (demux->adapter);
7024 if (demux->mdatbuffer && demux->n_streams) {
7025 gsize remaining_data_size = 0;
7027 /* the mdat was before the header */
7028 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7029 demux->n_streams, demux->mdatbuffer);
7030 /* restore our adapter/offset view of things with upstream;
7031 * put preceding buffered data ahead of current moov data.
7032 * This should also handle evil mdat, moov, mdat cases and alike */
7033 gst_adapter_flush (demux->adapter, demux->neededbytes);
7035 /* Store any remaining data after the mdat for later usage */
7036 remaining_data_size = gst_adapter_available (demux->adapter);
7037 if (remaining_data_size > 0) {
7038 g_assert (demux->restoredata_buffer == NULL);
7039 demux->restoredata_buffer =
7040 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7041 demux->restoredata_offset = demux->offset + demux->neededbytes;
7042 GST_DEBUG_OBJECT (demux,
7043 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7044 G_GUINT64_FORMAT, remaining_data_size,
7045 demux->restoredata_offset);
7048 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7049 demux->mdatbuffer = NULL;
7050 demux->offset = demux->mdatoffset;
7051 demux->neededbytes = next_entry_size (demux);
7052 demux->state = QTDEMUX_STATE_MOVIE;
7053 demux->mdatleft = gst_adapter_available (demux->adapter);
7054 demux->mdatsize = demux->mdatleft;
7056 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7057 gst_adapter_flush (demux->adapter, demux->neededbytes);
7059 /* only go back to the mdat if there are samples to play */
7060 if (demux->got_moov && demux->first_mdat != -1
7061 && has_next_entry (demux)) {
7064 /* we need to seek back */
7065 res = qtdemux_seek_offset (demux, demux->first_mdat);
7067 demux->offset = demux->first_mdat;
7069 GST_DEBUG_OBJECT (demux, "Seek back failed");
7072 demux->offset += demux->neededbytes;
7074 demux->neededbytes = 16;
7075 demux->state = QTDEMUX_STATE_INITIAL;
7080 case QTDEMUX_STATE_BUFFER_MDAT:{
7084 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7086 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7087 gst_buffer_extract (buf, 0, fourcc, 4);
7088 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7089 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7090 if (demux->mdatbuffer)
7091 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7093 demux->mdatbuffer = buf;
7094 demux->offset += demux->neededbytes;
7095 demux->neededbytes = 16;
7096 demux->state = QTDEMUX_STATE_INITIAL;
7097 gst_qtdemux_post_progress (demux, 1, 1);
7101 case QTDEMUX_STATE_MOVIE:{
7102 QtDemuxStream *stream = NULL;
7103 QtDemuxSample *sample;
7104 GstClockTime dts, pts, duration;
7108 GST_DEBUG_OBJECT (demux,
7109 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7111 if (demux->fragmented) {
7112 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7114 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7115 /* if needed data starts within this atom,
7116 * then it should not exceed this atom */
7117 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7118 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7119 (_("This file is invalid and cannot be played.")),
7120 ("sample data crosses atom boundary"));
7121 ret = GST_FLOW_ERROR;
7124 demux->mdatleft -= demux->neededbytes;
7126 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7127 /* so we are dropping more than left in this atom */
7128 gst_qtdemux_drop_data (demux, demux->mdatleft);
7129 demux->mdatleft = 0;
7131 /* need to resume atom parsing so we do not miss any other pieces */
7132 demux->state = QTDEMUX_STATE_INITIAL;
7133 demux->neededbytes = 16;
7135 /* check if there was any stored post mdat data from previous buffers */
7136 if (demux->restoredata_buffer) {
7137 g_assert (gst_adapter_available (demux->adapter) == 0);
7139 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7140 demux->restoredata_buffer = NULL;
7141 demux->offset = demux->restoredata_offset;
7148 if (demux->todrop) {
7149 if (demux->cenc_aux_info_offset > 0) {
7153 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7154 data = gst_adapter_map (demux->adapter, demux->todrop);
7155 gst_byte_reader_init (&br, data + 8, demux->todrop);
7156 if (!qtdemux_parse_cenc_aux_info (demux,
7157 QTDEMUX_FIRST_STREAM (demux), &br,
7158 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7159 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7160 ret = GST_FLOW_ERROR;
7161 gst_adapter_unmap (demux->adapter);
7162 g_free (demux->cenc_aux_info_sizes);
7163 demux->cenc_aux_info_sizes = NULL;
7166 demux->cenc_aux_info_offset = 0;
7167 g_free (demux->cenc_aux_info_sizes);
7168 demux->cenc_aux_info_sizes = NULL;
7169 gst_adapter_unmap (demux->adapter);
7171 gst_qtdemux_drop_data (demux, demux->todrop);
7175 /* initial newsegment sent here after having added pads,
7176 * possible others in sink_event */
7177 gst_qtdemux_check_send_pending_segment (demux);
7179 /* Figure out which stream this packet belongs to */
7180 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7181 stream = QTDEMUX_STREAM (iter->data);
7182 if (stream->sample_index >= stream->n_samples) {
7183 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7187 GST_LOG_OBJECT (demux,
7188 "Checking track-id %u (sample_index:%d / offset:%"
7189 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7190 stream->sample_index,
7191 stream->samples[stream->sample_index].offset,
7192 stream->samples[stream->sample_index].size);
7194 if (stream->samples[stream->sample_index].offset == demux->offset)
7198 if (G_UNLIKELY (stream == NULL))
7199 goto unknown_stream;
7201 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7203 if (stream->new_caps) {
7204 gst_qtdemux_configure_stream (demux, stream);
7207 /* Put data in a buffer, set timestamps, caps, ... */
7208 sample = &stream->samples[stream->sample_index];
7210 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7211 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7212 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7214 dts = QTSAMPLE_DTS (stream, sample);
7215 pts = QTSAMPLE_PTS (stream, sample);
7216 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7217 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7219 /* check for segment end */
7220 if (G_UNLIKELY (demux->segment.stop != -1
7221 && demux->segment.stop <= pts && stream->on_keyframe)) {
7222 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7223 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7225 /* skip this data, stream is EOS */
7226 gst_adapter_flush (demux->adapter, demux->neededbytes);
7227 demux->offset += demux->neededbytes;
7229 /* check if all streams are eos */
7231 for (iter = demux->active_streams; iter; iter = g_list_next (iter)) {
7232 if (!STREAM_IS_EOS (QTDEMUX_STREAM (iter->data))) {
7241 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7243 /* FIXME: should either be an assert or a plain check */
7244 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7246 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7247 dts, pts, duration, keyframe, dts, demux->offset);
7251 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7253 /* skip this data, stream is EOS */
7254 gst_adapter_flush (demux->adapter, demux->neededbytes);
7257 stream->sample_index++;
7258 stream->offset_in_sample = 0;
7260 /* update current offset and figure out size of next buffer */
7261 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7262 demux->offset, demux->neededbytes);
7263 demux->offset += demux->neededbytes;
7264 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7268 if (ret == GST_FLOW_EOS) {
7269 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7270 demux->neededbytes = -1;
7274 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7275 if (demux->fragmented) {
7276 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7277 /* there may be more to follow, only finish this atom */
7278 demux->todrop = demux->mdatleft;
7279 demux->neededbytes = demux->todrop;
7284 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7285 goto non_ok_unlinked_flow;
7294 /* when buffering movie data, at least show user something is happening */
7295 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7296 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7297 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7298 demux->neededbytes);
7305 non_ok_unlinked_flow:
7307 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7308 gst_flow_get_name (ret));
7313 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7314 ret = GST_FLOW_ERROR;
7319 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7325 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7326 (NULL), ("qtdemuxer invalid state %d", demux->state));
7327 ret = GST_FLOW_ERROR;
7332 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7333 (NULL), ("no 'moov' atom within the first 10 MB"));
7334 ret = GST_FLOW_ERROR;
7340 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7345 query = gst_query_new_scheduling ();
7347 if (!gst_pad_peer_query (sinkpad, query)) {
7348 gst_query_unref (query);
7352 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7353 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7354 gst_query_unref (query);
7359 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7360 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7364 GST_DEBUG_OBJECT (sinkpad, "activating push");
7365 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7370 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7371 GstPadMode mode, gboolean active)
7374 GstQTDemux *demux = GST_QTDEMUX (parent);
7377 case GST_PAD_MODE_PUSH:
7378 demux->pullbased = FALSE;
7381 case GST_PAD_MODE_PULL:
7383 demux->pullbased = TRUE;
7384 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7387 res = gst_pad_stop_task (sinkpad);
7399 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7405 memset (&z, 0, sizeof (z));
7410 if ((ret = inflateInit (&z)) != Z_OK) {
7411 GST_ERROR ("inflateInit() returned %d", ret);
7415 z.next_in = z_buffer;
7416 z.avail_in = z_length;
7418 buffer = (guint8 *) g_malloc (*length);
7419 z.avail_out = *length;
7420 z.next_out = (Bytef *) buffer;
7422 ret = inflate (&z, Z_NO_FLUSH);
7423 if (ret == Z_STREAM_END) {
7425 } else if (ret != Z_OK) {
7426 GST_WARNING ("inflate() returned %d", ret);
7431 buffer = (guint8 *) g_realloc (buffer, *length);
7432 z.next_out = (Bytef *) (buffer + z.total_out);
7433 z.avail_out += 4096;
7434 } while (z.avail_in > 0);
7436 if (ret != Z_STREAM_END) {
7441 *length = z.total_out;
7448 #endif /* HAVE_ZLIB */
7451 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7455 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7457 /* counts as header data */
7458 qtdemux->header_size += length;
7460 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7461 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7463 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7470 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7471 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7472 if (dcom == NULL || cmvd == NULL)
7473 goto invalid_compression;
7475 dcom_len = QT_UINT32 (dcom->data);
7477 goto invalid_compression;
7479 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7483 guint uncompressed_length;
7484 guint compressed_length;
7488 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7490 goto invalid_compression;
7492 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7493 compressed_length = cmvd_len - 12;
7494 GST_LOG ("length = %u", uncompressed_length);
7497 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7498 compressed_length, &uncompressed_length);
7501 qtdemux->moov_node_compressed = qtdemux->moov_node;
7502 qtdemux->moov_node = g_node_new (buf);
7504 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7505 uncompressed_length);
7509 #endif /* HAVE_ZLIB */
7511 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7512 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7519 invalid_compression:
7521 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7527 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7530 while (G_UNLIKELY (buf < end)) {
7534 if (G_UNLIKELY (buf + 4 > end)) {
7535 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7538 len = QT_UINT32 (buf);
7539 if (G_UNLIKELY (len == 0)) {
7540 GST_LOG_OBJECT (qtdemux, "empty container");
7543 if (G_UNLIKELY (len < 8)) {
7544 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7547 if (G_UNLIKELY (len > (end - buf))) {
7548 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7549 (gint) (end - buf));
7553 child = g_node_new ((guint8 *) buf);
7554 g_node_append (node, child);
7555 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7556 qtdemux_parse_node (qtdemux, child, buf, len);
7564 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7567 int len = QT_UINT32 (xdxt->data);
7568 guint8 *buf = xdxt->data;
7569 guint8 *end = buf + len;
7572 /* skip size and type */
7580 size = QT_UINT32 (buf);
7581 type = QT_FOURCC (buf + 4);
7583 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7585 if (buf + size > end || size <= 0)
7591 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7592 GST_FOURCC_ARGS (type));
7596 buffer = gst_buffer_new_and_alloc (size);
7597 gst_buffer_fill (buffer, 0, buf, size);
7598 stream->buffers = g_slist_append (stream->buffers, buffer);
7599 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7602 buffer = gst_buffer_new_and_alloc (size);
7603 gst_buffer_fill (buffer, 0, buf, size);
7604 stream->buffers = g_slist_append (stream->buffers, buffer);
7605 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7608 buffer = gst_buffer_new_and_alloc (size);
7609 gst_buffer_fill (buffer, 0, buf, size);
7610 stream->buffers = g_slist_append (stream->buffers, buffer);
7611 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7614 GST_WARNING_OBJECT (qtdemux,
7615 "unknown theora cookie %" GST_FOURCC_FORMAT,
7616 GST_FOURCC_ARGS (type));
7625 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7629 guint32 node_length = 0;
7630 const QtNodeType *type;
7633 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7635 if (G_UNLIKELY (length < 8))
7636 goto not_enough_data;
7638 node_length = QT_UINT32 (buffer);
7639 fourcc = QT_FOURCC (buffer + 4);
7641 /* ignore empty nodes */
7642 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7645 type = qtdemux_type_get (fourcc);
7647 end = buffer + length;
7649 GST_LOG_OBJECT (qtdemux,
7650 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7651 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7653 if (node_length > length)
7654 goto broken_atom_size;
7656 if (type->flags & QT_FLAG_CONTAINER) {
7657 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7662 if (node_length < 20) {
7663 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7666 GST_DEBUG_OBJECT (qtdemux,
7667 "parsing stsd (sample table, sample description) atom");
7668 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7669 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7680 /* also read alac (or whatever) in stead of mp4a in the following,
7681 * since a similar layout is used in other cases as well */
7682 if (fourcc == FOURCC_mp4a)
7684 else if (fourcc == FOURCC_fLaC)
7689 /* There are two things we might encounter here: a true mp4a atom, and
7690 an mp4a entry in an stsd atom. The latter is what we're interested
7691 in, and it looks like an atom, but isn't really one. The true mp4a
7692 atom is short, so we detect it based on length here. */
7693 if (length < min_size) {
7694 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7695 GST_FOURCC_ARGS (fourcc));
7699 /* 'version' here is the sound sample description version. Types 0 and
7700 1 are documented in the QTFF reference, but type 2 is not: it's
7701 described in Apple header files instead (struct SoundDescriptionV2
7703 version = QT_UINT16 (buffer + 16);
7705 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7706 GST_FOURCC_ARGS (fourcc), version);
7708 /* parse any esds descriptors */
7720 GST_WARNING_OBJECT (qtdemux,
7721 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7722 GST_FOURCC_ARGS (fourcc), version);
7727 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7753 /* codec_data is contained inside these atoms, which all have
7754 * the same format. */
7755 /* video sample description size is 86 bytes without extension.
7756 * node_length have to be bigger than 86 bytes because video sample
7757 * description can include extenstions such as esds, fiel, glbl, etc. */
7758 if (node_length < 86) {
7759 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7760 " sample description length too short (%u < 86)",
7761 GST_FOURCC_ARGS (fourcc), node_length);
7765 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7766 GST_FOURCC_ARGS (fourcc));
7768 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7770 * revision level (2 bytes) : must be set to 0. */
7771 version = QT_UINT32 (buffer + 16);
7772 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7774 /* compressor name : PASCAL string and informative purposes
7775 * first byte : the number of bytes to be displayed.
7776 * it has to be less than 32 because it is reserved
7777 * space of 32 bytes total including itself. */
7778 str_len = QT_UINT8 (buffer + 50);
7780 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7781 (char *) buffer + 51);
7783 GST_WARNING_OBJECT (qtdemux,
7784 "compressorname length too big (%u > 31)", str_len);
7786 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7788 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7793 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7795 /* You are reading this correctly. QTFF specifies that the
7796 * metadata atom is a short atom, whereas ISO BMFF specifies
7797 * it's a full atom. But since so many people are doing things
7798 * differently, we actually peek into the atom to see which
7801 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7802 GST_FOURCC_ARGS (fourcc));
7805 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7806 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7807 * starts with a 'hdlr' atom */
7808 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7809 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7810 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7811 * with version/flags both set to zero */
7812 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7814 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7819 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7820 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7821 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7830 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7831 GST_FOURCC_ARGS (fourcc));
7835 version = QT_UINT32 (buffer + 12);
7836 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7843 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7848 if (length < offset) {
7849 GST_WARNING_OBJECT (qtdemux,
7850 "skipping too small %" GST_FOURCC_FORMAT " box",
7851 GST_FOURCC_ARGS (fourcc));
7854 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7860 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7865 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7870 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7874 if (!strcmp (type->name, "unknown"))
7875 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7879 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7880 GST_FOURCC_ARGS (fourcc));
7886 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7887 (_("This file is corrupt and cannot be played.")),
7888 ("Not enough data for an atom header, got only %u bytes", length));
7893 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7894 (_("This file is corrupt and cannot be played.")),
7895 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7896 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7903 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7907 guint32 child_fourcc;
7909 for (child = g_node_first_child (node); child;
7910 child = g_node_next_sibling (child)) {
7911 buffer = (guint8 *) child->data;
7913 child_fourcc = QT_FOURCC (buffer + 4);
7915 if (G_UNLIKELY (child_fourcc == fourcc)) {
7923 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7924 GstByteReader * parser)
7928 guint32 child_fourcc, child_len;
7930 for (child = g_node_first_child (node); child;
7931 child = g_node_next_sibling (child)) {
7932 buffer = (guint8 *) child->data;
7934 child_len = QT_UINT32 (buffer);
7935 child_fourcc = QT_FOURCC (buffer + 4);
7937 if (G_UNLIKELY (child_fourcc == fourcc)) {
7938 if (G_UNLIKELY (child_len < (4 + 4)))
7940 /* FIXME: must verify if atom length < parent atom length */
7941 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7949 qtdemux_tree_get_child_by_index (GNode * node, guint index)
7951 return g_node_nth_child (node, index);
7955 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7956 GstByteReader * parser)
7960 guint32 child_fourcc, child_len;
7962 for (child = g_node_next_sibling (node); child;
7963 child = g_node_next_sibling (child)) {
7964 buffer = (guint8 *) child->data;
7966 child_fourcc = QT_FOURCC (buffer + 4);
7968 if (child_fourcc == fourcc) {
7970 child_len = QT_UINT32 (buffer);
7971 if (G_UNLIKELY (child_len < (4 + 4)))
7973 /* FIXME: must verify if atom length < parent atom length */
7974 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7983 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7985 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7989 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7991 /* FIXME: This can only reliably work if demuxers have a
7992 * separate streaming thread per srcpad. This should be
7993 * done in a demuxer base class, which integrates parts
7996 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8001 query = gst_query_new_allocation (stream->caps, FALSE);
8003 if (!gst_pad_peer_query (stream->pad, query)) {
8004 /* not a problem, just debug a little */
8005 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8008 if (stream->allocator)
8009 gst_object_unref (stream->allocator);
8011 if (gst_query_get_n_allocation_params (query) > 0) {
8012 /* try the allocator */
8013 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8015 stream->use_allocator = TRUE;
8017 stream->allocator = NULL;
8018 gst_allocation_params_init (&stream->params);
8019 stream->use_allocator = FALSE;
8021 gst_query_unref (query);
8026 pad_query (const GValue * item, GValue * value, gpointer user_data)
8028 GstPad *pad = g_value_get_object (item);
8029 GstQuery *query = user_data;
8032 res = gst_pad_peer_query (pad, query);
8035 g_value_set_boolean (value, TRUE);
8039 GST_INFO_OBJECT (pad, "pad peer query failed");
8044 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8045 GstPadDirection direction)
8048 GstIteratorFoldFunction func = pad_query;
8049 GValue res = { 0, };
8051 g_value_init (&res, G_TYPE_BOOLEAN);
8052 g_value_set_boolean (&res, FALSE);
8055 if (direction == GST_PAD_SRC)
8056 it = gst_element_iterate_src_pads (element);
8058 it = gst_element_iterate_sink_pads (element);
8060 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8061 gst_iterator_resync (it);
8063 gst_iterator_free (it);
8065 return g_value_get_boolean (&res);
8069 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8070 QtDemuxStream * stream)
8074 GstElement *element = GST_ELEMENT (qtdemux);
8076 gchar **filtered_sys_ids;
8077 GValue event_list = G_VALUE_INIT;
8080 /* 1. Check if we already have the context. */
8081 if (qtdemux->preferred_protection_system_id != NULL) {
8082 GST_LOG_OBJECT (element,
8083 "already have the protection context, no need to request it again");
8087 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8088 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8089 (const gchar **) qtdemux->protection_system_ids->pdata);
8091 if (!filtered_sys_ids) {
8092 GST_INFO_OBJECT (element,
8093 "No avalaible decryptor, not worth asking the user to choose.");
8097 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8098 qtdemux->protection_system_ids->len - 1);
8099 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8100 "decryptors for %u of them, running context request",
8101 qtdemux->protection_system_ids->len, g_strv_length (filtered_sys_ids));
8103 if (stream->protection_scheme_event_queue.length) {
8104 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8105 stream->protection_scheme_event_queue.length);
8106 walk = stream->protection_scheme_event_queue.tail;
8108 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8109 qtdemux->protection_event_queue.length);
8110 walk = qtdemux->protection_event_queue.tail;
8113 g_value_init (&event_list, GST_TYPE_LIST);
8114 for (; walk; walk = g_list_previous (walk)) {
8115 GValue *event_value = g_new0 (GValue, 1);
8116 g_value_init (event_value, GST_TYPE_EVENT);
8117 g_value_set_boxed (event_value, walk->data);
8118 gst_value_list_append_and_take_value (&event_list, event_value);
8121 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8122 * check if downstream already has a context of the specific type
8123 * 2b) Query upstream as above.
8125 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8126 st = gst_query_writable_structure (query);
8127 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8128 "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
8129 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8130 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8131 gst_query_parse_context (query, &ctxt);
8132 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8133 gst_element_set_context (element, ctxt);
8134 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8135 gst_query_parse_context (query, &ctxt);
8136 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8137 gst_element_set_context (element, ctxt);
8139 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8140 * the required context type and afterwards check if a
8141 * usable context was set now as in 1). The message could
8142 * be handled by the parent bins of the element and the
8147 GST_INFO_OBJECT (element, "posting need context message");
8148 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8149 "drm-preferred-decryption-system-id");
8150 st = (GstStructure *) gst_message_get_structure (msg);
8151 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8152 "stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids, NULL);
8153 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8154 gst_element_post_message (element, msg);
8157 g_strfreev (filtered_sys_ids);
8158 g_value_unset (&event_list);
8159 gst_query_unref (query);
8163 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8164 QtDemuxStream * stream)
8167 const gchar *selected_system = NULL;
8169 g_return_val_if_fail (qtdemux != NULL, FALSE);
8170 g_return_val_if_fail (stream != NULL, FALSE);
8171 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8174 if (stream->protection_scheme_type != FOURCC_cenc) {
8175 GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
8178 if (qtdemux->protection_system_ids == NULL) {
8179 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8180 "cenc protection system information has been found");
8184 gst_qtdemux_request_protection_context (qtdemux, stream);
8185 if (qtdemux->preferred_protection_system_id != NULL) {
8186 const gchar *preferred_system_array[] =
8187 { qtdemux->preferred_protection_system_id, NULL };
8189 selected_system = gst_protection_select_system (preferred_system_array);
8191 if (selected_system) {
8192 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8193 qtdemux->preferred_protection_system_id);
8195 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8196 "because there is no available decryptor",
8197 qtdemux->preferred_protection_system_id);
8201 if (!selected_system) {
8202 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8203 selected_system = gst_protection_select_system ((const gchar **)
8204 qtdemux->protection_system_ids->pdata);
8205 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8206 qtdemux->protection_system_ids->len - 1);
8209 if (!selected_system) {
8210 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8211 "suitable decryptor element has been found");
8215 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8218 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8219 if (!gst_structure_has_name (s, "application/x-cenc")) {
8220 gst_structure_set (s,
8221 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8222 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8224 gst_structure_set_name (s, "application/x-cenc");
8230 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8232 if (stream->subtype == FOURCC_vide) {
8233 /* fps is calculated base on the duration of the average framerate since
8234 * qt does not have a fixed framerate. */
8235 gboolean fps_available = TRUE;
8236 guint32 first_duration = 0;
8238 if (stream->n_samples > 0)
8239 first_duration = stream->samples[0].duration;
8241 if ((stream->n_samples == 1 && first_duration == 0)
8242 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8244 CUR_STREAM (stream)->fps_n = 0;
8245 CUR_STREAM (stream)->fps_d = 1;
8247 if (stream->duration == 0 || stream->n_samples < 2) {
8248 CUR_STREAM (stream)->fps_n = stream->timescale;
8249 CUR_STREAM (stream)->fps_d = 1;
8250 fps_available = FALSE;
8252 GstClockTime avg_duration;
8256 /* duration and n_samples can be updated for fragmented format
8257 * so, framerate of fragmented format is calculated using data in a moof */
8258 if (qtdemux->fragmented && stream->n_samples_moof > 0
8259 && stream->duration_moof > 0) {
8260 n_samples = stream->n_samples_moof;
8261 duration = stream->duration_moof;
8263 n_samples = stream->n_samples;
8264 duration = stream->duration;
8267 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8268 /* stream->duration is guint64, timescale, n_samples are guint32 */
8270 gst_util_uint64_scale_round (duration -
8271 first_duration, GST_SECOND,
8272 (guint64) (stream->timescale) * (n_samples - 1));
8274 GST_LOG_OBJECT (qtdemux,
8275 "Calculating avg sample duration based on stream (or moof) duration %"
8277 " minus first sample %u, leaving %d samples gives %"
8278 GST_TIME_FORMAT, duration, first_duration,
8279 n_samples - 1, GST_TIME_ARGS (avg_duration));
8281 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8282 &CUR_STREAM (stream)->fps_d);
8284 GST_DEBUG_OBJECT (qtdemux,
8285 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8286 stream->timescale, CUR_STREAM (stream)->fps_n,
8287 CUR_STREAM (stream)->fps_d);
8291 if (CUR_STREAM (stream)->caps) {
8292 CUR_STREAM (stream)->caps =
8293 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8295 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8296 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8297 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8299 /* set framerate if calculated framerate is reliable */
8300 if (fps_available) {
8301 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8302 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8303 CUR_STREAM (stream)->fps_d, NULL);
8306 /* calculate pixel-aspect-ratio using display width and height */
8307 GST_DEBUG_OBJECT (qtdemux,
8308 "video size %dx%d, target display size %dx%d",
8309 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8310 stream->display_width, stream->display_height);
8311 /* qt file might have pasp atom */
8312 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8313 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8314 CUR_STREAM (stream)->par_h);
8315 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8316 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8317 CUR_STREAM (stream)->par_h, NULL);
8318 } else if (stream->display_width > 0 && stream->display_height > 0
8319 && CUR_STREAM (stream)->width > 0
8320 && CUR_STREAM (stream)->height > 0) {
8323 /* calculate the pixel aspect ratio using the display and pixel w/h */
8324 n = stream->display_width * CUR_STREAM (stream)->height;
8325 d = stream->display_height * CUR_STREAM (stream)->width;
8328 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8329 CUR_STREAM (stream)->par_w = n;
8330 CUR_STREAM (stream)->par_h = d;
8331 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8332 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8333 CUR_STREAM (stream)->par_h, NULL);
8336 if (CUR_STREAM (stream)->interlace_mode > 0) {
8337 if (CUR_STREAM (stream)->interlace_mode == 1) {
8338 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8339 G_TYPE_STRING, "progressive", NULL);
8340 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8341 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8342 G_TYPE_STRING, "interleaved", NULL);
8343 if (CUR_STREAM (stream)->field_order == 9) {
8344 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8345 G_TYPE_STRING, "top-field-first", NULL);
8346 } else if (CUR_STREAM (stream)->field_order == 14) {
8347 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8348 G_TYPE_STRING, "bottom-field-first", NULL);
8353 /* Create incomplete colorimetry here if needed */
8354 if (CUR_STREAM (stream)->colorimetry.range ||
8355 CUR_STREAM (stream)->colorimetry.matrix ||
8356 CUR_STREAM (stream)->colorimetry.transfer
8357 || CUR_STREAM (stream)->colorimetry.primaries) {
8358 gchar *colorimetry =
8359 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8360 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8361 G_TYPE_STRING, colorimetry, NULL);
8362 g_free (colorimetry);
8365 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8366 guint par_w = 1, par_h = 1;
8368 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8369 par_w = CUR_STREAM (stream)->par_w;
8370 par_h = CUR_STREAM (stream)->par_h;
8373 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8374 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8376 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8379 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8380 "multiview-mode", G_TYPE_STRING,
8381 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8382 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8383 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8388 else if (stream->subtype == FOURCC_soun) {
8389 if (CUR_STREAM (stream)->caps) {
8390 CUR_STREAM (stream)->caps =
8391 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8392 if (CUR_STREAM (stream)->rate > 0)
8393 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8394 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8395 if (CUR_STREAM (stream)->n_channels > 0)
8396 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8397 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8398 if (CUR_STREAM (stream)->n_channels > 2) {
8399 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8400 * correctly; this is just the minimum we can do - assume
8401 * we don't actually have any channel positions. */
8402 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8403 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8409 GstCaps *prev_caps = NULL;
8411 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8412 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8413 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8414 gst_pad_set_active (stream->pad, TRUE);
8416 gst_pad_use_fixed_caps (stream->pad);
8418 if (stream->protected) {
8419 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8420 GST_ERROR_OBJECT (qtdemux,
8421 "Failed to configure protected stream caps.");
8426 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8427 CUR_STREAM (stream)->caps);
8428 if (stream->new_stream) {
8430 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8433 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8436 gst_event_parse_stream_flags (event, &stream_flags);
8437 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8438 qtdemux->have_group_id = TRUE;
8440 qtdemux->have_group_id = FALSE;
8441 gst_event_unref (event);
8442 } else if (!qtdemux->have_group_id) {
8443 qtdemux->have_group_id = TRUE;
8444 qtdemux->group_id = gst_util_group_id_next ();
8447 stream->new_stream = FALSE;
8448 event = gst_event_new_stream_start (stream->stream_id);
8449 if (qtdemux->have_group_id)
8450 gst_event_set_group_id (event, qtdemux->group_id);
8451 if (stream->disabled)
8452 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8453 if (CUR_STREAM (stream)->sparse) {
8454 stream_flags |= GST_STREAM_FLAG_SPARSE;
8456 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8458 gst_event_set_stream_flags (event, stream_flags);
8459 gst_pad_push_event (stream->pad, event);
8462 prev_caps = gst_pad_get_current_caps (stream->pad);
8464 if (CUR_STREAM (stream)->caps) {
8466 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8467 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8468 CUR_STREAM (stream)->caps);
8469 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8471 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8474 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8478 gst_caps_unref (prev_caps);
8479 stream->new_caps = FALSE;
8485 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8486 QtDemuxStream * stream)
8488 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8491 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8492 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8493 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8494 stream->stsd_entries_length)) {
8495 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8496 (_("This file is invalid and cannot be played.")),
8497 ("New sample description id is out of bounds (%d >= %d)",
8498 stream->stsd_sample_description_id, stream->stsd_entries_length));
8500 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8501 stream->new_caps = TRUE;
8506 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8507 QtDemuxStream * stream, GstTagList * list)
8509 gboolean ret = TRUE;
8510 /* consistent default for push based mode */
8511 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8513 if (stream->subtype == FOURCC_vide) {
8514 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8517 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8520 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8521 gst_object_unref (stream->pad);
8527 qtdemux->n_video_streams++;
8528 } else if (stream->subtype == FOURCC_soun) {
8529 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8532 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8534 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8535 gst_object_unref (stream->pad);
8540 qtdemux->n_audio_streams++;
8541 } else if (stream->subtype == FOURCC_strm) {
8542 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8543 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8544 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8545 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8548 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8550 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8551 gst_object_unref (stream->pad);
8556 qtdemux->n_sub_streams++;
8557 } else if (CUR_STREAM (stream)->caps) {
8558 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8561 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8563 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8564 gst_object_unref (stream->pad);
8569 qtdemux->n_video_streams++;
8571 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8578 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8579 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8580 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8581 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8583 if (stream->stream_tags)
8584 gst_tag_list_unref (stream->stream_tags);
8585 stream->stream_tags = list;
8587 /* global tags go on each pad anyway */
8588 stream->send_global_tags = TRUE;
8589 /* send upstream GST_EVENT_PROTECTION events that were received before
8590 this source pad was created */
8591 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8592 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8596 gst_tag_list_unref (list);
8600 /* find next atom with @fourcc starting at @offset */
8601 static GstFlowReturn
8602 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8603 guint64 * length, guint32 fourcc)
8609 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8610 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8616 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8617 if (G_UNLIKELY (ret != GST_FLOW_OK))
8619 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8622 gst_buffer_unref (buf);
8625 gst_buffer_map (buf, &map, GST_MAP_READ);
8626 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8627 gst_buffer_unmap (buf, &map);
8628 gst_buffer_unref (buf);
8630 if (G_UNLIKELY (*length == 0)) {
8631 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8632 ret = GST_FLOW_ERROR;
8636 if (lfourcc == fourcc) {
8637 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8641 GST_LOG_OBJECT (qtdemux,
8642 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8643 GST_FOURCC_ARGS (fourcc), *offset);
8652 /* might simply have had last one */
8653 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8658 /* should only do something in pull mode */
8659 /* call with OBJECT lock */
8660 static GstFlowReturn
8661 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8663 guint64 length, offset;
8664 GstBuffer *buf = NULL;
8665 GstFlowReturn ret = GST_FLOW_OK;
8666 GstFlowReturn res = GST_FLOW_OK;
8669 offset = qtdemux->moof_offset;
8670 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8673 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8674 return GST_FLOW_EOS;
8677 /* best not do pull etc with lock held */
8678 GST_OBJECT_UNLOCK (qtdemux);
8680 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8681 if (ret != GST_FLOW_OK)
8684 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8685 if (G_UNLIKELY (ret != GST_FLOW_OK))
8687 gst_buffer_map (buf, &map, GST_MAP_READ);
8688 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8689 gst_buffer_unmap (buf, &map);
8690 gst_buffer_unref (buf);
8695 gst_buffer_unmap (buf, &map);
8696 gst_buffer_unref (buf);
8700 /* look for next moof */
8701 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8702 if (G_UNLIKELY (ret != GST_FLOW_OK))
8706 GST_OBJECT_LOCK (qtdemux);
8708 qtdemux->moof_offset = offset;
8714 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8716 res = GST_FLOW_ERROR;
8721 /* maybe upstream temporarily flushing */
8722 if (ret != GST_FLOW_FLUSHING) {
8723 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8726 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8727 /* resume at current position next time */
8734 /* initialise bytereaders for stbl sub-atoms */
8736 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8738 stream->stbl_index = -1; /* no samples have yet been parsed */
8739 stream->sample_index = -1;
8741 /* time-to-sample atom */
8742 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8745 /* copy atom data into a new buffer for later use */
8746 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8748 /* skip version + flags */
8749 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8750 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8752 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8754 /* make sure there's enough data */
8755 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8756 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8757 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8758 stream->n_sample_times);
8759 if (!stream->n_sample_times)
8763 /* sync sample atom */
8764 stream->stps_present = FALSE;
8765 if ((stream->stss_present =
8766 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8767 &stream->stss) ? TRUE : FALSE) == TRUE) {
8768 /* copy atom data into a new buffer for later use */
8769 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8771 /* skip version + flags */
8772 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8773 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8776 if (stream->n_sample_syncs) {
8777 /* make sure there's enough data */
8778 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8782 /* partial sync sample atom */
8783 if ((stream->stps_present =
8784 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8785 &stream->stps) ? TRUE : FALSE) == TRUE) {
8786 /* copy atom data into a new buffer for later use */
8787 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8789 /* skip version + flags */
8790 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8791 !gst_byte_reader_get_uint32_be (&stream->stps,
8792 &stream->n_sample_partial_syncs))
8795 /* if there are no entries, the stss table contains the real
8797 if (stream->n_sample_partial_syncs) {
8798 /* make sure there's enough data */
8799 if (!qt_atom_parser_has_chunks (&stream->stps,
8800 stream->n_sample_partial_syncs, 4))
8807 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8810 /* copy atom data into a new buffer for later use */
8811 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8813 /* skip version + flags */
8814 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8815 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8818 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8821 if (!stream->n_samples)
8824 /* sample-to-chunk atom */
8825 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8828 /* copy atom data into a new buffer for later use */
8829 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8831 /* skip version + flags */
8832 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8833 !gst_byte_reader_get_uint32_be (&stream->stsc,
8834 &stream->n_samples_per_chunk))
8837 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8838 stream->n_samples_per_chunk);
8840 /* make sure there's enough data */
8841 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8847 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8848 stream->co_size = sizeof (guint32);
8849 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8851 stream->co_size = sizeof (guint64);
8855 /* copy atom data into a new buffer for later use */
8856 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8858 /* skip version + flags */
8859 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8862 /* chunks_are_samples == TRUE means treat chunks as samples */
8863 stream->chunks_are_samples = stream->sample_size
8864 && !CUR_STREAM (stream)->sampled;
8865 if (stream->chunks_are_samples) {
8866 /* treat chunks as samples */
8867 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8870 /* skip number of entries */
8871 if (!gst_byte_reader_skip (&stream->stco, 4))
8874 /* make sure there are enough data in the stsz atom */
8875 if (!stream->sample_size) {
8876 /* different sizes for each sample */
8877 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8882 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8883 stream->n_samples, (guint) sizeof (QtDemuxSample),
8884 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8886 if (stream->n_samples >=
8887 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8888 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8889 "be larger than %uMB (broken file?)", stream->n_samples,
8890 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8894 g_assert (stream->samples == NULL);
8895 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8896 if (!stream->samples) {
8897 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8902 /* composition time-to-sample */
8903 if ((stream->ctts_present =
8904 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8905 &stream->ctts) ? TRUE : FALSE) == TRUE) {
8906 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8908 /* copy atom data into a new buffer for later use */
8909 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8911 /* skip version + flags */
8912 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
8913 || !gst_byte_reader_get_uint32_be (&stream->ctts,
8914 &stream->n_composition_times))
8917 /* make sure there's enough data */
8918 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
8922 /* This is optional, if missing we iterate the ctts */
8923 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
8924 if (!gst_byte_reader_skip (&cslg, 1 + 3)
8925 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
8926 g_free ((gpointer) cslg.data);
8930 gint32 cslg_least = 0;
8931 guint num_entries, pos;
8934 pos = gst_byte_reader_get_pos (&stream->ctts);
8935 num_entries = stream->n_composition_times;
8937 stream->cslg_shift = 0;
8939 for (i = 0; i < num_entries; i++) {
8942 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
8943 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8945 if (offset < cslg_least)
8946 cslg_least = offset;
8950 stream->cslg_shift = ABS (cslg_least);
8952 stream->cslg_shift = 0;
8954 /* reset the reader so we can generate sample table */
8955 gst_byte_reader_set_pos (&stream->ctts, pos);
8958 /* Ensure the cslg_shift value is consistent so we can use it
8959 * unconditionnally to produce TS and Segment */
8960 stream->cslg_shift = 0;
8967 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8968 (_("This file is corrupt and cannot be played.")), (NULL));
8973 gst_qtdemux_stbl_free (stream);
8974 if (!qtdemux->fragmented) {
8975 /* not quite good */
8976 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
8979 /* may pick up samples elsewhere */
8985 /* collect samples from the next sample to be parsed up to sample @n for @stream
8986 * by reading the info from @stbl
8988 * This code can be executed from both the streaming thread and the seeking
8989 * thread so it takes the object lock to protect itself
8992 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
8995 QtDemuxSample *samples, *first, *cur, *last;
8996 guint32 n_samples_per_chunk;
8999 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9000 GST_FOURCC_FORMAT ", pad %s",
9001 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9002 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9004 n_samples = stream->n_samples;
9007 goto out_of_samples;
9009 GST_OBJECT_LOCK (qtdemux);
9010 if (n <= stream->stbl_index)
9011 goto already_parsed;
9013 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9015 if (!stream->stsz.data) {
9016 /* so we already parsed and passed all the moov samples;
9017 * onto fragmented ones */
9018 g_assert (qtdemux->fragmented);
9022 /* pointer to the sample table */
9023 samples = stream->samples;
9025 /* starts from -1, moves to the next sample index to parse */
9026 stream->stbl_index++;
9028 /* keep track of the first and last sample to fill */
9029 first = &samples[stream->stbl_index];
9032 if (!stream->chunks_are_samples) {
9033 /* set the sample sizes */
9034 if (stream->sample_size == 0) {
9035 /* different sizes for each sample */
9036 for (cur = first; cur <= last; cur++) {
9037 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9038 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9039 (guint) (cur - samples), cur->size);
9042 /* samples have the same size */
9043 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9044 for (cur = first; cur <= last; cur++)
9045 cur->size = stream->sample_size;
9049 n_samples_per_chunk = stream->n_samples_per_chunk;
9052 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9055 if (stream->stsc_chunk_index >= stream->last_chunk
9056 || stream->stsc_chunk_index < stream->first_chunk) {
9057 stream->first_chunk =
9058 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9059 stream->samples_per_chunk =
9060 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9062 stream->stsd_sample_description_id =
9063 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9065 /* chunk numbers are counted from 1 it seems */
9066 if (G_UNLIKELY (stream->first_chunk == 0))
9069 --stream->first_chunk;
9071 /* the last chunk of each entry is calculated by taking the first chunk
9072 * of the next entry; except if there is no next, where we fake it with
9074 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9075 stream->last_chunk = G_MAXUINT32;
9077 stream->last_chunk =
9078 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9079 if (G_UNLIKELY (stream->last_chunk == 0))
9082 --stream->last_chunk;
9085 GST_LOG_OBJECT (qtdemux,
9086 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9087 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9088 stream->samples_per_chunk, stream->stsd_sample_description_id);
9090 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9093 if (stream->last_chunk != G_MAXUINT32) {
9094 if (!qt_atom_parser_peek_sub (&stream->stco,
9095 stream->first_chunk * stream->co_size,
9096 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9101 stream->co_chunk = stream->stco;
9102 if (!gst_byte_reader_skip (&stream->co_chunk,
9103 stream->first_chunk * stream->co_size))
9107 stream->stsc_chunk_index = stream->first_chunk;
9110 last_chunk = stream->last_chunk;
9112 if (stream->chunks_are_samples) {
9113 cur = &samples[stream->stsc_chunk_index];
9115 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9118 stream->stsc_chunk_index = j;
9123 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9126 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9127 "%" G_GUINT64_FORMAT, j, cur->offset);
9129 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9130 CUR_STREAM (stream)->bytes_per_frame > 0) {
9132 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9133 CUR_STREAM (stream)->samples_per_frame *
9134 CUR_STREAM (stream)->bytes_per_frame;
9136 cur->size = stream->samples_per_chunk;
9139 GST_DEBUG_OBJECT (qtdemux,
9140 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9141 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9142 stream->stco_sample_index)), cur->size);
9144 cur->timestamp = stream->stco_sample_index;
9145 cur->duration = stream->samples_per_chunk;
9146 cur->keyframe = TRUE;
9149 stream->stco_sample_index += stream->samples_per_chunk;
9151 stream->stsc_chunk_index = j;
9153 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9154 guint32 samples_per_chunk;
9155 guint64 chunk_offset;
9157 if (!stream->stsc_sample_index
9158 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9159 &stream->chunk_offset))
9162 samples_per_chunk = stream->samples_per_chunk;
9163 chunk_offset = stream->chunk_offset;
9165 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9166 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9167 G_GUINT64_FORMAT " and size %d",
9168 (guint) (cur - samples), chunk_offset, cur->size);
9170 cur->offset = chunk_offset;
9171 chunk_offset += cur->size;
9174 if (G_UNLIKELY (cur > last)) {
9176 stream->stsc_sample_index = k + 1;
9177 stream->chunk_offset = chunk_offset;
9178 stream->stsc_chunk_index = j;
9182 stream->stsc_sample_index = 0;
9184 stream->stsc_chunk_index = j;
9186 stream->stsc_index++;
9189 if (stream->chunks_are_samples)
9193 guint32 n_sample_times;
9195 n_sample_times = stream->n_sample_times;
9198 for (i = stream->stts_index; i < n_sample_times; i++) {
9199 guint32 stts_samples;
9200 gint32 stts_duration;
9203 if (stream->stts_sample_index >= stream->stts_samples
9204 || !stream->stts_sample_index) {
9206 stream->stts_samples =
9207 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9208 stream->stts_duration =
9209 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9211 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9212 i, stream->stts_samples, stream->stts_duration);
9214 stream->stts_sample_index = 0;
9217 stts_samples = stream->stts_samples;
9218 stts_duration = stream->stts_duration;
9219 stts_time = stream->stts_time;
9221 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9222 GST_DEBUG_OBJECT (qtdemux,
9223 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9224 (guint) (cur - samples), j,
9225 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9227 cur->timestamp = stts_time;
9228 cur->duration = stts_duration;
9230 /* avoid 32-bit wrap-around,
9231 * but still mind possible 'negative' duration */
9232 stts_time += (gint64) stts_duration;
9235 if (G_UNLIKELY (cur > last)) {
9237 stream->stts_time = stts_time;
9238 stream->stts_sample_index = j + 1;
9239 if (stream->stts_sample_index >= stream->stts_samples)
9240 stream->stts_index++;
9244 stream->stts_sample_index = 0;
9245 stream->stts_time = stts_time;
9246 stream->stts_index++;
9248 /* fill up empty timestamps with the last timestamp, this can happen when
9249 * the last samples do not decode and so we don't have timestamps for them.
9250 * We however look at the last timestamp to estimate the track length so we
9251 * need something in here. */
9252 for (; cur < last; cur++) {
9253 GST_DEBUG_OBJECT (qtdemux,
9254 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9255 (guint) (cur - samples),
9256 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9257 cur->timestamp = stream->stts_time;
9263 /* sample sync, can be NULL */
9264 if (stream->stss_present == TRUE) {
9265 guint32 n_sample_syncs;
9267 n_sample_syncs = stream->n_sample_syncs;
9269 if (!n_sample_syncs) {
9270 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9271 stream->all_keyframe = TRUE;
9273 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9274 /* note that the first sample is index 1, not 0 */
9277 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9279 if (G_LIKELY (index > 0 && index <= n_samples)) {
9281 samples[index].keyframe = TRUE;
9282 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9283 /* and exit if we have enough samples */
9284 if (G_UNLIKELY (index >= n)) {
9291 stream->stss_index = i;
9294 /* stps marks partial sync frames like open GOP I-Frames */
9295 if (stream->stps_present == TRUE) {
9296 guint32 n_sample_partial_syncs;
9298 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9300 /* if there are no entries, the stss table contains the real
9302 if (n_sample_partial_syncs) {
9303 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9304 /* note that the first sample is index 1, not 0 */
9307 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9309 if (G_LIKELY (index > 0 && index <= n_samples)) {
9311 samples[index].keyframe = TRUE;
9312 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9313 /* and exit if we have enough samples */
9314 if (G_UNLIKELY (index >= n)) {
9321 stream->stps_index = i;
9325 /* no stss, all samples are keyframes */
9326 stream->all_keyframe = TRUE;
9327 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9332 /* composition time to sample */
9333 if (stream->ctts_present == TRUE) {
9334 guint32 n_composition_times;
9336 gint32 ctts_soffset;
9338 /* Fill in the pts_offsets */
9340 n_composition_times = stream->n_composition_times;
9342 for (i = stream->ctts_index; i < n_composition_times; i++) {
9343 if (stream->ctts_sample_index >= stream->ctts_count
9344 || !stream->ctts_sample_index) {
9345 stream->ctts_count =
9346 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9347 stream->ctts_soffset =
9348 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9349 stream->ctts_sample_index = 0;
9352 ctts_count = stream->ctts_count;
9353 ctts_soffset = stream->ctts_soffset;
9355 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9356 cur->pts_offset = ctts_soffset;
9359 if (G_UNLIKELY (cur > last)) {
9361 stream->ctts_sample_index = j + 1;
9365 stream->ctts_sample_index = 0;
9366 stream->ctts_index++;
9370 stream->stbl_index = n;
9371 /* if index has been completely parsed, free data that is no-longer needed */
9372 if (n + 1 == stream->n_samples) {
9373 gst_qtdemux_stbl_free (stream);
9374 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9375 if (qtdemux->pullbased) {
9376 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9377 while (n + 1 == stream->n_samples)
9378 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9382 GST_OBJECT_UNLOCK (qtdemux);
9389 GST_LOG_OBJECT (qtdemux,
9390 "Tried to parse up to sample %u but this sample has already been parsed",
9392 /* if fragmented, there may be more */
9393 if (qtdemux->fragmented && n == stream->stbl_index)
9395 GST_OBJECT_UNLOCK (qtdemux);
9401 GST_LOG_OBJECT (qtdemux,
9402 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9404 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9405 (_("This file is corrupt and cannot be played.")), (NULL));
9410 GST_OBJECT_UNLOCK (qtdemux);
9411 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9412 (_("This file is corrupt and cannot be played.")), (NULL));
9417 /* collect all segment info for @stream.
9420 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9424 /* accept edts if they contain gaps at start and there is only
9425 * one media segment */
9426 gboolean allow_pushbased_edts = TRUE;
9427 gint media_segments_count = 0;
9429 /* parse and prepare segment info from the edit list */
9430 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9431 stream->n_segments = 0;
9432 stream->segments = NULL;
9433 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9436 gint segment_number, entry_size;
9439 const guint8 *buffer;
9443 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9444 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9447 buffer = elst->data;
9449 size = QT_UINT32 (buffer);
9450 /* version, flags, n_segments */
9452 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9455 version = QT_UINT8 (buffer + 8);
9456 entry_size = (version == 1) ? 20 : 12;
9458 n_segments = QT_UINT32 (buffer + 12);
9460 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9461 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9465 /* we might allocate a bit too much, at least allocate 1 segment */
9466 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9468 /* segments always start from 0 */
9472 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9475 gboolean empty_edit = FALSE;
9476 QtDemuxSegment *segment;
9478 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9481 media_time = QT_UINT64 (buffer + 8);
9482 duration = QT_UINT64 (buffer);
9483 if (media_time == G_MAXUINT64)
9486 media_time = QT_UINT32 (buffer + 4);
9487 duration = QT_UINT32 (buffer);
9488 if (media_time == G_MAXUINT32)
9493 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9495 segment = &stream->segments[segment_number];
9497 /* time and duration expressed in global timescale */
9498 segment->time = stime;
9499 if (duration != 0 || empty_edit) {
9500 /* edge case: empty edits with duration=zero are treated here.
9501 * (files should not have these anyway). */
9503 /* add non scaled values so we don't cause roundoff errors */
9505 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9506 segment->duration = stime - segment->time;
9508 /* zero duration does not imply media_start == media_stop
9509 * but, only specify media_start. The edit ends with the track. */
9510 stime = segment->duration = GST_CLOCK_TIME_NONE;
9511 /* Don't allow more edits after this one. */
9512 n_segments = segment_number + 1;
9514 segment->stop_time = stime;
9516 segment->trak_media_start = media_time;
9517 /* media_time expressed in stream timescale */
9519 segment->media_start = media_start;
9520 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9521 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9522 media_segments_count++;
9524 segment->media_start = GST_CLOCK_TIME_NONE;
9525 segment->media_stop = GST_CLOCK_TIME_NONE;
9527 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9529 if (rate_int <= 1) {
9530 /* 0 is not allowed, some programs write 1 instead of the floating point
9532 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9536 segment->rate = rate_int / 65536.0;
9539 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9540 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9541 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9542 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9543 segment_number, GST_TIME_ARGS (segment->time),
9544 GST_TIME_ARGS (segment->duration),
9545 GST_TIME_ARGS (segment->media_start), media_time,
9546 GST_TIME_ARGS (segment->media_stop),
9547 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9549 if (segment->stop_time > qtdemux->segment.stop) {
9550 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9551 " extends to %" GST_TIME_FORMAT
9552 " past the end of the file duration %" GST_TIME_FORMAT
9553 " it will be truncated", segment_number,
9554 GST_TIME_ARGS (segment->stop_time),
9555 GST_TIME_ARGS (qtdemux->segment.stop));
9556 qtdemux->segment.stop = segment->stop_time;
9559 buffer += entry_size;
9561 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9562 stream->n_segments = n_segments;
9563 if (media_segments_count != 1)
9564 allow_pushbased_edts = FALSE;
9568 /* push based does not handle segments, so act accordingly here,
9569 * and warn if applicable */
9570 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9571 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9572 /* remove and use default one below, we stream like it anyway */
9573 g_free (stream->segments);
9574 stream->segments = NULL;
9575 stream->n_segments = 0;
9578 /* no segments, create one to play the complete trak */
9579 if (stream->n_segments == 0) {
9580 GstClockTime stream_duration =
9581 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9583 if (stream->segments == NULL)
9584 stream->segments = g_new (QtDemuxSegment, 1);
9586 /* represent unknown our way */
9587 if (stream_duration == 0)
9588 stream_duration = GST_CLOCK_TIME_NONE;
9590 stream->segments[0].time = 0;
9591 stream->segments[0].stop_time = stream_duration;
9592 stream->segments[0].duration = stream_duration;
9593 stream->segments[0].media_start = 0;
9594 stream->segments[0].media_stop = stream_duration;
9595 stream->segments[0].rate = 1.0;
9596 stream->segments[0].trak_media_start = 0;
9598 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9599 GST_TIME_ARGS (stream_duration));
9600 stream->n_segments = 1;
9601 stream->dummy_segment = TRUE;
9603 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9609 * Parses the stsd atom of a svq3 trak looking for
9610 * the SMI and gama atoms.
9613 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9614 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9616 const guint8 *_gamma = NULL;
9617 GstBuffer *_seqh = NULL;
9618 const guint8 *stsd_data = stsd_entry_data;
9619 guint32 length = QT_UINT32 (stsd_data);
9623 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9629 version = QT_UINT16 (stsd_data);
9634 while (length > 8) {
9635 guint32 fourcc, size;
9637 size = QT_UINT32 (stsd_data);
9638 fourcc = QT_FOURCC (stsd_data + 4);
9639 data = stsd_data + 8;
9642 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9643 "svq3 atom parsing");
9652 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9653 " for gama atom, expected 12", size);
9658 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9660 if (_seqh != NULL) {
9661 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9662 " found, ignoring");
9664 seqh_size = QT_UINT32 (data + 4);
9665 if (seqh_size > 0) {
9666 _seqh = gst_buffer_new_and_alloc (seqh_size);
9667 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9674 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9675 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9679 if (size <= length) {
9685 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9688 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9689 G_GUINT16_FORMAT, version);
9700 gst_buffer_unref (_seqh);
9705 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9712 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9713 * atom that might contain a 'data' atom with the rtsp uri.
9714 * This case was reported in bug #597497, some info about
9715 * the hndl atom can be found in TN1195
9717 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9718 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9721 guint32 dref_num_entries = 0;
9722 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9723 gst_byte_reader_skip (&dref, 4) &&
9724 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9727 /* search dref entries for hndl atom */
9728 for (i = 0; i < dref_num_entries; i++) {
9729 guint32 size = 0, type;
9730 guint8 string_len = 0;
9731 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9732 qt_atom_parser_get_fourcc (&dref, &type)) {
9733 if (type == FOURCC_hndl) {
9734 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9736 /* skip data reference handle bytes and the
9737 * following pascal string and some extra 4
9738 * bytes I have no idea what are */
9739 if (!gst_byte_reader_skip (&dref, 4) ||
9740 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9741 !gst_byte_reader_skip (&dref, string_len + 4)) {
9742 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9746 /* iterate over the atoms to find the data atom */
9747 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9751 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9752 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9753 if (atom_type == FOURCC_data) {
9754 const guint8 *uri_aux = NULL;
9756 /* found the data atom that might contain the rtsp uri */
9757 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9758 "hndl atom, interpreting it as an URI");
9759 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9761 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9762 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9764 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9765 "didn't contain a rtsp address");
9767 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9772 /* skipping to the next entry */
9773 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9776 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9783 /* skip to the next entry */
9784 if (!gst_byte_reader_skip (&dref, size - 8))
9787 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9790 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9796 #define AMR_NB_ALL_MODES 0x81ff
9797 #define AMR_WB_ALL_MODES 0x83ff
9799 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9801 /* The 'damr' atom is of the form:
9803 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9804 * 32 b 8 b 16 b 8 b 8 b
9806 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9807 * represents the highest mode used in the stream (and thus the maximum
9808 * bitrate), with a couple of special cases as seen below.
9811 /* Map of frame type ID -> bitrate */
9812 static const guint nb_bitrates[] = {
9813 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9815 static const guint wb_bitrates[] = {
9816 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9822 gst_buffer_map (buf, &map, GST_MAP_READ);
9824 if (map.size != 0x11) {
9825 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9829 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9830 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9831 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9835 mode_set = QT_UINT16 (map.data + 13);
9837 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9838 max_mode = 7 + (wb ? 1 : 0);
9840 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9841 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9843 if (max_mode == -1) {
9844 GST_DEBUG ("No mode indication was found (mode set) = %x",
9849 gst_buffer_unmap (buf, &map);
9850 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9853 gst_buffer_unmap (buf, &map);
9858 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9859 GstByteReader * reader, guint32 * matrix, const gchar * atom)
9862 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9868 if (gst_byte_reader_get_remaining (reader) < 36)
9871 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9872 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9873 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9874 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9875 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9876 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9877 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9878 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9879 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9881 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9882 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9883 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9885 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9886 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9888 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9889 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9896 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9897 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9904 * This macro will only compare value abdegh, it expects cfi to have already
9907 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9908 (m)[3] == (d << 16) && (m)[4] == (e << 16))
9910 /* only handle the cases where the last column has standard values */
9911 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
9912 const gchar *rotation_tag = NULL;
9914 /* no rotation needed */
9915 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
9917 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
9918 rotation_tag = "rotate-90";
9919 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
9920 rotation_tag = "rotate-180";
9921 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
9922 rotation_tag = "rotate-270";
9924 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9927 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
9929 if (rotation_tag != NULL) {
9930 if (*taglist == NULL)
9931 *taglist = gst_tag_list_new_empty ();
9932 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
9933 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
9936 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
9940 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
9941 * protected streams (sinf, frma, schm and schi); if the protection scheme is
9942 * Common Encryption (cenc), the function will also parse the tenc box (defined
9943 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
9944 * (typically an enc[v|a|t|s] sample entry); the function will set
9945 * @original_fmt to the fourcc of the original unencrypted stream format.
9946 * Returns TRUE if successful; FALSE otherwise. */
9948 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
9949 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
9956 g_return_val_if_fail (qtdemux != NULL, FALSE);
9957 g_return_val_if_fail (stream != NULL, FALSE);
9958 g_return_val_if_fail (container != NULL, FALSE);
9959 g_return_val_if_fail (original_fmt != NULL, FALSE);
9961 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
9962 if (G_UNLIKELY (!sinf)) {
9963 if (stream->protection_scheme_type == FOURCC_cenc) {
9964 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
9965 "mandatory for Common Encryption");
9971 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
9972 if (G_UNLIKELY (!frma)) {
9973 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
9977 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
9978 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
9979 GST_FOURCC_ARGS (*original_fmt));
9981 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
9983 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
9986 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
9987 stream->protection_scheme_version =
9988 QT_UINT32 ((const guint8 *) schm->data + 16);
9990 GST_DEBUG_OBJECT (qtdemux,
9991 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
9992 "protection_scheme_version: %#010x",
9993 GST_FOURCC_ARGS (stream->protection_scheme_type),
9994 stream->protection_scheme_version);
9996 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
9998 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10001 if (stream->protection_scheme_type == FOURCC_cenc) {
10002 QtDemuxCencSampleSetInfo *info;
10004 const guint8 *tenc_data;
10005 guint32 isEncrypted;
10007 const guint8 *default_kid;
10008 GstBuffer *kid_buf;
10010 if (G_UNLIKELY (!stream->protection_scheme_info))
10011 stream->protection_scheme_info =
10012 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10014 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10016 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10018 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10019 "which is mandatory for Common Encryption");
10022 tenc_data = (const guint8 *) tenc->data + 12;
10023 isEncrypted = QT_UINT24 (tenc_data);
10024 iv_size = QT_UINT8 (tenc_data + 3);
10025 default_kid = (tenc_data + 4);
10026 kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
10027 gst_buffer_fill (kid_buf, 0, default_kid, 16);
10028 if (info->default_properties)
10029 gst_structure_free (info->default_properties);
10030 info->default_properties =
10031 gst_structure_new ("application/x-cenc",
10032 "iv_size", G_TYPE_UINT, iv_size,
10033 "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
10034 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
10035 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
10036 "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
10037 gst_buffer_unref (kid_buf);
10043 qtdemux_track_id_compare_func (QtDemuxStream * stream1, QtDemuxStream * stream2)
10045 return (gint) stream1->track_id - (gint) stream2->track_id;
10048 /* parse the traks.
10049 * With each track we associate a new QtDemuxStream that contains all the info
10051 * traks that do not decode to something (like strm traks) will not have a pad.
10054 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10056 GstByteReader tkhd;
10071 QtDemuxStream *stream = NULL;
10072 const guint8 *stsd_data;
10073 const guint8 *stsd_entry_data;
10074 guint remaining_stsd_len;
10075 guint stsd_entry_count;
10077 guint16 lang_code; /* quicktime lang code or packed iso code */
10079 guint32 tkhd_flags = 0;
10080 guint8 tkhd_version = 0;
10081 guint32 w = 0, h = 0;
10082 guint value_size, stsd_len, len;
10086 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10088 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10089 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10090 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10093 /* pick between 64 or 32 bits */
10094 value_size = tkhd_version == 1 ? 8 : 4;
10095 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10096 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10099 /* Check if current moov has duplicated track_id */
10100 if (qtdemux_find_stream (qtdemux, track_id))
10101 goto existing_stream;
10103 stream = _create_stream (qtdemux, track_id);
10104 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10106 /* need defaults for fragments */
10107 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10109 if ((tkhd_flags & 1) == 0)
10110 stream->disabled = TRUE;
10112 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10113 tkhd_version, tkhd_flags, stream->track_id);
10115 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10118 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10119 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10120 if (qtdemux->major_brand != FOURCC_mjp2 ||
10121 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10125 len = QT_UINT32 ((guint8 *) mdhd->data);
10126 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10127 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10128 if (version == 0x01000000) {
10131 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10132 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10133 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10137 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10138 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10139 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10142 if (lang_code < 0x400) {
10143 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10144 } else if (lang_code == 0x7fff) {
10145 stream->lang_id[0] = 0; /* unspecified */
10147 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10148 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10149 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10150 stream->lang_id[3] = 0;
10153 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10154 stream->timescale);
10155 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10157 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10158 lang_code, stream->lang_id);
10160 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10163 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10164 /* chapters track reference */
10165 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10167 gsize length = GST_READ_UINT32_BE (chap->data);
10168 if (qtdemux->chapters_track_id)
10169 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10171 if (length >= 12) {
10172 qtdemux->chapters_track_id =
10173 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10178 /* fragmented files may have bogus duration in moov */
10179 if (!qtdemux->fragmented &&
10180 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10181 guint64 tdur1, tdur2;
10183 /* don't overflow */
10184 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10185 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10188 * some of those trailers, nowadays, have prologue images that are
10189 * themselves video tracks as well. I haven't really found a way to
10190 * identify those yet, except for just looking at their duration. */
10191 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10192 GST_WARNING_OBJECT (qtdemux,
10193 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10194 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10195 "found, assuming preview image or something; skipping track",
10196 stream->duration, stream->timescale, qtdemux->duration,
10197 qtdemux->timescale);
10198 gst_qtdemux_stream_free (stream);
10203 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10206 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10207 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10209 len = QT_UINT32 ((guint8 *) hdlr->data);
10211 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10212 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10213 GST_FOURCC_ARGS (stream->subtype));
10215 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10218 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10221 /*parse svmi header if existing */
10222 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10224 len = QT_UINT32 ((guint8 *) svmi->data);
10225 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10227 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10228 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10229 guint8 frame_type, frame_layout;
10231 /* MPEG-A stereo video */
10232 if (qtdemux->major_brand == FOURCC_ss02)
10233 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10235 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10236 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10237 switch (frame_type) {
10239 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10242 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10245 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10248 /* mode 3 is primary/secondary view sequence, ie
10249 * left/right views in separate tracks. See section 7.2
10250 * of ISO/IEC 23000-11:2009 */
10251 GST_FIXME_OBJECT (qtdemux,
10252 "Implement stereo video in separate streams");
10255 if ((frame_layout & 0x1) == 0)
10256 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10258 GST_LOG_OBJECT (qtdemux,
10259 "StereoVideo: composition type: %u, is_left_first: %u",
10260 frame_type, frame_layout);
10261 stream->multiview_mode = mode;
10262 stream->multiview_flags = flags;
10266 /* parse rest of tkhd */
10267 if (stream->subtype == FOURCC_vide) {
10270 /* version 1 uses some 64-bit ints */
10271 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10274 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10277 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10278 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10281 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10282 &stream->stream_tags);
10286 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10288 stsd_data = (const guint8 *) stsd->data;
10290 /* stsd should at least have one entry */
10291 stsd_len = QT_UINT32 (stsd_data);
10292 if (stsd_len < 24) {
10293 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10294 if (stream->subtype == FOURCC_vivo) {
10295 gst_qtdemux_stream_free (stream);
10302 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10303 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10304 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10305 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10307 stsd_entry_data = stsd_data + 16;
10308 remaining_stsd_len = stsd_len - 16;
10309 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10311 gchar *codec = NULL;
10312 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10314 /* and that entry should fit within stsd */
10315 len = QT_UINT32 (stsd_entry_data);
10316 if (len > remaining_stsd_len)
10319 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10320 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10321 GST_FOURCC_ARGS (entry->fourcc));
10322 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10324 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10325 goto error_encrypted;
10327 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10328 /* FIXME this looks wrong, there might be multiple children
10329 * with the same type */
10330 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10331 stream->protected = TRUE;
10332 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10333 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10336 if (stream->subtype == FOURCC_vide) {
10341 gint depth, palette_size, palette_count;
10342 guint32 *palette_data = NULL;
10344 entry->sampled = TRUE;
10346 stream->display_width = w >> 16;
10347 stream->display_height = h >> 16;
10350 if (len < 86) /* TODO verify */
10353 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10354 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10355 entry->fps_n = 0; /* this is filled in later */
10356 entry->fps_d = 0; /* this is filled in later */
10357 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10358 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10360 /* if color_table_id is 0, ctab atom must follow; however some files
10361 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10362 * if color table is not present we'll correct the value */
10363 if (entry->color_table_id == 0 &&
10365 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10366 entry->color_table_id = -1;
10369 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10370 entry->width, entry->height, entry->bits_per_sample,
10371 entry->color_table_id);
10373 depth = entry->bits_per_sample;
10375 /* more than 32 bits means grayscale */
10376 gray = (depth > 32);
10377 /* low 32 bits specify the depth */
10380 /* different number of palette entries is determined by depth. */
10382 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10383 palette_count = (1 << depth);
10384 palette_size = palette_count * 4;
10386 if (entry->color_table_id) {
10387 switch (palette_count) {
10391 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10394 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10399 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10401 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10406 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10408 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10411 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10412 (_("The video in this file might not play correctly.")),
10413 ("unsupported palette depth %d", depth));
10417 gint i, j, start, end;
10423 start = QT_UINT32 (stsd_entry_data + offset + 70);
10424 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10425 end = QT_UINT16 (stsd_entry_data + offset + 76);
10427 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10428 start, end, palette_count);
10435 if (len < 94 + (end - start) * 8)
10438 /* palette is always the same size */
10439 palette_data = g_malloc0 (256 * 4);
10440 palette_size = 256 * 4;
10442 for (j = 0, i = start; i <= end; j++, i++) {
10443 guint32 a, r, g, b;
10445 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10446 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10447 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10448 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10450 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10451 (g & 0xff00) | (b >> 8);
10456 gst_caps_unref (entry->caps);
10459 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10461 if (G_UNLIKELY (!entry->caps)) {
10462 g_free (palette_data);
10463 goto unknown_stream;
10467 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10468 GST_TAG_VIDEO_CODEC, codec, NULL);
10473 if (palette_data) {
10476 if (entry->rgb8_palette)
10477 gst_memory_unref (entry->rgb8_palette);
10478 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10479 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10481 s = gst_caps_get_structure (entry->caps, 0);
10483 /* non-raw video has a palette_data property. raw video has the palette as
10484 * an extra plane that we append to the output buffers before we push
10486 if (!gst_structure_has_name (s, "video/x-raw")) {
10487 GstBuffer *palette;
10489 palette = gst_buffer_new ();
10490 gst_buffer_append_memory (palette, entry->rgb8_palette);
10491 entry->rgb8_palette = NULL;
10493 gst_caps_set_simple (entry->caps, "palette_data",
10494 GST_TYPE_BUFFER, palette, NULL);
10495 gst_buffer_unref (palette);
10497 } else if (palette_count != 0) {
10498 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10499 (NULL), ("Unsupported palette depth %d", depth));
10502 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10503 QT_UINT16 (stsd_entry_data + offset + 32));
10509 /* pick 'the' stsd child */
10510 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10511 if (!stream->protected) {
10512 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10516 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10522 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10523 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10524 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10525 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10529 const guint8 *pasp_data = (const guint8 *) pasp->data;
10530 gint len = QT_UINT32 (pasp_data);
10533 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10534 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10536 CUR_STREAM (stream)->par_w = 0;
10537 CUR_STREAM (stream)->par_h = 0;
10540 CUR_STREAM (stream)->par_w = 0;
10541 CUR_STREAM (stream)->par_h = 0;
10545 const guint8 *fiel_data = (const guint8 *) fiel->data;
10546 gint len = QT_UINT32 (fiel_data);
10549 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10550 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10555 const guint8 *colr_data = (const guint8 *) colr->data;
10556 gint len = QT_UINT32 (colr_data);
10558 if (len == 19 || len == 18) {
10559 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10561 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10562 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10563 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10564 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10565 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10567 switch (primaries) {
10569 CUR_STREAM (stream)->colorimetry.primaries =
10570 GST_VIDEO_COLOR_PRIMARIES_BT709;
10573 CUR_STREAM (stream)->colorimetry.primaries =
10574 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10577 CUR_STREAM (stream)->colorimetry.primaries =
10578 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10581 CUR_STREAM (stream)->colorimetry.primaries =
10582 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10588 switch (transfer_function) {
10590 CUR_STREAM (stream)->colorimetry.transfer =
10591 GST_VIDEO_TRANSFER_BT709;
10594 CUR_STREAM (stream)->colorimetry.transfer =
10595 GST_VIDEO_TRANSFER_SMPTE240M;
10603 CUR_STREAM (stream)->colorimetry.matrix =
10604 GST_VIDEO_COLOR_MATRIX_BT709;
10607 CUR_STREAM (stream)->colorimetry.matrix =
10608 GST_VIDEO_COLOR_MATRIX_BT601;
10611 CUR_STREAM (stream)->colorimetry.matrix =
10612 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10615 CUR_STREAM (stream)->colorimetry.matrix =
10616 GST_VIDEO_COLOR_MATRIX_BT2020;
10622 CUR_STREAM (stream)->colorimetry.range =
10623 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10624 GST_VIDEO_COLOR_RANGE_16_235;
10626 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10629 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10634 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10635 stream->stream_tags);
10642 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10643 const guint8 *avc_data = stsd_entry_data + 0x56;
10646 while (len >= 0x8) {
10649 if (QT_UINT32 (avc_data) <= len)
10650 size = QT_UINT32 (avc_data) - 0x8;
10655 /* No real data, so break out */
10658 switch (QT_FOURCC (avc_data + 0x4)) {
10661 /* parse, if found */
10664 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10666 /* First 4 bytes are the length of the atom, the next 4 bytes
10667 * are the fourcc, the next 1 byte is the version, and the
10668 * subsequent bytes are profile_tier_level structure like data. */
10669 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10670 avc_data + 8 + 1, size - 1);
10671 buf = gst_buffer_new_and_alloc (size);
10672 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10673 gst_caps_set_simple (entry->caps,
10674 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10675 gst_buffer_unref (buf);
10683 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10685 /* First 4 bytes are the length of the atom, the next 4 bytes
10686 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10687 * next 1 byte is the version, and the
10688 * subsequent bytes are sequence parameter set like data. */
10690 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10692 gst_codec_utils_h264_caps_set_level_and_profile
10693 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10695 buf = gst_buffer_new_and_alloc (size);
10696 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10697 gst_caps_set_simple (entry->caps,
10698 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10699 gst_buffer_unref (buf);
10705 guint avg_bitrate, max_bitrate;
10707 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10711 max_bitrate = QT_UINT32 (avc_data + 0xc);
10712 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10714 if (!max_bitrate && !avg_bitrate)
10717 /* Some muxers seem to swap the average and maximum bitrates
10718 * (I'm looking at you, YouTube), so we swap for sanity. */
10719 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10720 guint temp = avg_bitrate;
10722 avg_bitrate = max_bitrate;
10723 max_bitrate = temp;
10726 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10727 gst_tag_list_add (stream->stream_tags,
10728 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10729 max_bitrate, NULL);
10731 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10732 gst_tag_list_add (stream->stream_tags,
10733 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10745 avc_data += size + 8;
10754 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10755 const guint8 *hevc_data = stsd_entry_data + 0x56;
10758 while (len >= 0x8) {
10761 if (QT_UINT32 (hevc_data) <= len)
10762 size = QT_UINT32 (hevc_data) - 0x8;
10767 /* No real data, so break out */
10770 switch (QT_FOURCC (hevc_data + 0x4)) {
10773 /* parse, if found */
10776 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10778 /* First 4 bytes are the length of the atom, the next 4 bytes
10779 * are the fourcc, the next 1 byte is the version, and the
10780 * subsequent bytes are sequence parameter set like data. */
10781 gst_codec_utils_h265_caps_set_level_tier_and_profile
10782 (entry->caps, hevc_data + 8 + 1, size - 1);
10784 buf = gst_buffer_new_and_alloc (size);
10785 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10786 gst_caps_set_simple (entry->caps,
10787 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10788 gst_buffer_unref (buf);
10795 hevc_data += size + 8;
10808 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10809 GST_FOURCC_ARGS (fourcc));
10811 /* codec data might be in glbl extension atom */
10813 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10819 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10821 len = QT_UINT32 (data);
10824 buf = gst_buffer_new_and_alloc (len);
10825 gst_buffer_fill (buf, 0, data + 8, len);
10826 gst_caps_set_simple (entry->caps,
10827 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10828 gst_buffer_unref (buf);
10835 /* see annex I of the jpeg2000 spec */
10836 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10837 const guint8 *data;
10838 const gchar *colorspace = NULL;
10840 guint32 ncomp_map = 0;
10841 gint32 *comp_map = NULL;
10842 guint32 nchan_def = 0;
10843 gint32 *chan_def = NULL;
10845 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10846 /* some required atoms */
10847 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10850 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10854 /* number of components; redundant with info in codestream, but useful
10856 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10857 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10859 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10861 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10864 GST_DEBUG_OBJECT (qtdemux, "found colr");
10865 /* extract colour space info */
10866 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10867 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10869 colorspace = "sRGB";
10872 colorspace = "GRAY";
10875 colorspace = "sYUV";
10883 /* colr is required, and only values 16, 17, and 18 are specified,
10884 so error if we have no colorspace */
10887 /* extract component mapping */
10888 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10890 guint32 cmap_len = 0;
10892 cmap_len = QT_UINT32 (cmap->data);
10893 if (cmap_len >= 8) {
10894 /* normal box, subtract off header */
10896 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10897 if (cmap_len % 4 == 0) {
10898 ncomp_map = (cmap_len / 4);
10899 comp_map = g_new0 (gint32, ncomp_map);
10900 for (i = 0; i < ncomp_map; i++) {
10903 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
10904 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
10905 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
10906 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
10911 /* extract channel definitions */
10912 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
10914 guint32 cdef_len = 0;
10916 cdef_len = QT_UINT32 (cdef->data);
10917 if (cdef_len >= 10) {
10918 /* normal box, subtract off header and len */
10920 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
10921 if (cdef_len % 6 == 0) {
10922 nchan_def = (cdef_len / 6);
10923 chan_def = g_new0 (gint32, nchan_def);
10924 for (i = 0; i < nchan_def; i++)
10926 for (i = 0; i < nchan_def; i++) {
10927 guint16 cn, typ, asoc;
10928 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
10929 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
10930 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
10931 if (cn < nchan_def) {
10934 chan_def[cn] = asoc;
10937 chan_def[cn] = 0; /* alpha */
10940 chan_def[cn] = -typ;
10948 gst_caps_set_simple (entry->caps,
10949 "num-components", G_TYPE_INT, ncomp, NULL);
10950 gst_caps_set_simple (entry->caps,
10951 "colorspace", G_TYPE_STRING, colorspace, NULL);
10954 GValue arr = { 0, };
10955 GValue elt = { 0, };
10957 g_value_init (&arr, GST_TYPE_ARRAY);
10958 g_value_init (&elt, G_TYPE_INT);
10959 for (i = 0; i < ncomp_map; i++) {
10960 g_value_set_int (&elt, comp_map[i]);
10961 gst_value_array_append_value (&arr, &elt);
10963 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10964 "component-map", &arr);
10965 g_value_unset (&elt);
10966 g_value_unset (&arr);
10971 GValue arr = { 0, };
10972 GValue elt = { 0, };
10974 g_value_init (&arr, GST_TYPE_ARRAY);
10975 g_value_init (&elt, G_TYPE_INT);
10976 for (i = 0; i < nchan_def; i++) {
10977 g_value_set_int (&elt, chan_def[i]);
10978 gst_value_array_append_value (&arr, &elt);
10980 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
10981 "channel-definitions", &arr);
10982 g_value_unset (&elt);
10983 g_value_unset (&arr);
10987 /* some optional atoms */
10988 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
10989 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
10991 /* indicate possible fields in caps */
10993 data = (guint8 *) field->data + 8;
10995 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
10996 (gint) * data, NULL);
10998 /* add codec_data if provided */
11003 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11004 data = prefix->data;
11005 len = QT_UINT32 (data);
11008 buf = gst_buffer_new_and_alloc (len);
11009 gst_buffer_fill (buf, 0, data + 8, len);
11010 gst_caps_set_simple (entry->caps,
11011 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11012 gst_buffer_unref (buf);
11021 GstBuffer *seqh = NULL;
11022 const guint8 *gamma_data = NULL;
11023 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11025 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11028 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11029 QT_FP32 (gamma_data), NULL);
11032 /* sorry for the bad name, but we don't know what this is, other
11033 * than its own fourcc */
11034 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11036 gst_buffer_unref (seqh);
11039 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11040 buf = gst_buffer_new_and_alloc (len);
11041 gst_buffer_fill (buf, 0, stsd_data, len);
11042 gst_caps_set_simple (entry->caps,
11043 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11044 gst_buffer_unref (buf);
11049 /* https://developer.apple.com/standards/qtff-2001.pdf,
11050 * page 92, "Video Sample Description", under table 3.1 */
11053 const gint compressor_offset =
11054 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11055 const gint min_size = compressor_offset + 32 + 2 + 2;
11058 guint16 color_table_id = 0;
11061 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11063 /* recover information on interlaced/progressive */
11064 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11068 len = QT_UINT32 (jpeg->data);
11069 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11071 if (len >= min_size) {
11072 gst_byte_reader_init (&br, jpeg->data, len);
11074 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11075 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11076 if (color_table_id != 0) {
11077 /* the spec says there can be concatenated chunks in the data, and we want
11078 * to find one called field. Walk through them. */
11079 gint offset = min_size;
11080 while (offset + 8 < len) {
11081 guint32 size = 0, tag;
11082 ok = gst_byte_reader_get_uint32_le (&br, &size);
11083 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11084 if (!ok || size < 8) {
11085 GST_WARNING_OBJECT (qtdemux,
11086 "Failed to walk optional chunk list");
11089 GST_DEBUG_OBJECT (qtdemux,
11090 "Found optional %4.4s chunk, size %u",
11091 (const char *) &tag, size);
11092 if (tag == FOURCC_fiel) {
11093 guint8 n_fields = 0, ordering = 0;
11094 gst_byte_reader_get_uint8 (&br, &n_fields);
11095 gst_byte_reader_get_uint8 (&br, &ordering);
11096 if (n_fields == 1 || n_fields == 2) {
11097 GST_DEBUG_OBJECT (qtdemux,
11098 "Found fiel tag with %u fields, ordering %u",
11099 n_fields, ordering);
11101 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11102 "interlace-mode", G_TYPE_STRING, "interleaved",
11105 GST_WARNING_OBJECT (qtdemux,
11106 "Found fiel tag with invalid fields (%u)", n_fields);
11112 GST_DEBUG_OBJECT (qtdemux,
11113 "Color table ID is 0, not trying to get interlacedness");
11116 GST_WARNING_OBJECT (qtdemux,
11117 "Length of jpeg chunk is too small, not trying to get interlacedness");
11125 gst_caps_set_simple (entry->caps,
11126 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11132 GNode *xith, *xdxt;
11134 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11135 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11139 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11143 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11144 /* collect the headers and store them in a stream list so that we can
11145 * send them out first */
11146 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11156 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11157 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11160 ovc1_data = ovc1->data;
11161 ovc1_len = QT_UINT32 (ovc1_data);
11162 if (ovc1_len <= 198) {
11163 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11166 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11167 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11168 gst_caps_set_simple (entry->caps,
11169 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11170 gst_buffer_unref (buf);
11175 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11176 const guint8 *vc1_data = stsd_entry_data + 0x56;
11182 if (QT_UINT32 (vc1_data) <= len)
11183 size = QT_UINT32 (vc1_data) - 8;
11188 /* No real data, so break out */
11191 switch (QT_FOURCC (vc1_data + 0x4)) {
11192 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11196 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11197 buf = gst_buffer_new_and_alloc (size);
11198 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11199 gst_caps_set_simple (entry->caps,
11200 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11201 gst_buffer_unref (buf);
11208 vc1_data += size + 8;
11217 GST_INFO_OBJECT (qtdemux,
11218 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11219 GST_FOURCC_ARGS (fourcc), entry->caps);
11221 } else if (stream->subtype == FOURCC_soun) {
11223 int version, samplesize;
11224 guint16 compression_id;
11225 gboolean amrwb = FALSE;
11228 /* sample description entry (16) + sound sample description v0 (20) */
11232 version = QT_UINT32 (stsd_entry_data + offset);
11233 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11234 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11235 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11236 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11238 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11239 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11240 QT_UINT32 (stsd_entry_data + offset + 4));
11241 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11242 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11243 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11244 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11245 QT_UINT16 (stsd_entry_data + offset + 14));
11246 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11248 if (compression_id == 0xfffe)
11249 entry->sampled = TRUE;
11251 /* first assume uncompressed audio */
11252 entry->bytes_per_sample = samplesize / 8;
11253 entry->samples_per_frame = entry->n_channels;
11254 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11255 entry->samples_per_packet = entry->samples_per_frame;
11256 entry->bytes_per_packet = entry->bytes_per_sample;
11260 /* Yes, these have to be hard-coded */
11263 entry->samples_per_packet = 6;
11264 entry->bytes_per_packet = 1;
11265 entry->bytes_per_frame = 1 * entry->n_channels;
11266 entry->bytes_per_sample = 1;
11267 entry->samples_per_frame = 6 * entry->n_channels;
11272 entry->samples_per_packet = 3;
11273 entry->bytes_per_packet = 1;
11274 entry->bytes_per_frame = 1 * entry->n_channels;
11275 entry->bytes_per_sample = 1;
11276 entry->samples_per_frame = 3 * entry->n_channels;
11281 entry->samples_per_packet = 64;
11282 entry->bytes_per_packet = 34;
11283 entry->bytes_per_frame = 34 * entry->n_channels;
11284 entry->bytes_per_sample = 2;
11285 entry->samples_per_frame = 64 * entry->n_channels;
11291 entry->samples_per_packet = 1;
11292 entry->bytes_per_packet = 1;
11293 entry->bytes_per_frame = 1 * entry->n_channels;
11294 entry->bytes_per_sample = 1;
11295 entry->samples_per_frame = 1 * entry->n_channels;
11300 entry->samples_per_packet = 160;
11301 entry->bytes_per_packet = 33;
11302 entry->bytes_per_frame = 33 * entry->n_channels;
11303 entry->bytes_per_sample = 2;
11304 entry->samples_per_frame = 160 * entry->n_channels;
11311 if (version == 0x00010000) {
11312 /* sample description entry (16) + sound sample description v1 (20+16) */
11324 /* only parse extra decoding config for non-pcm audio */
11325 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11326 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11327 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11328 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11330 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11331 entry->samples_per_packet);
11332 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11333 entry->bytes_per_packet);
11334 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11335 entry->bytes_per_frame);
11336 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11337 entry->bytes_per_sample);
11339 if (!entry->sampled && entry->bytes_per_packet) {
11340 entry->samples_per_frame = (entry->bytes_per_frame /
11341 entry->bytes_per_packet) * entry->samples_per_packet;
11342 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11343 entry->samples_per_frame);
11348 } else if (version == 0x00020000) {
11355 /* sample description entry (16) + sound sample description v2 (56) */
11359 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11360 entry->rate = qtfp.fp;
11361 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11363 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11364 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11365 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11366 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11367 QT_UINT32 (stsd_entry_data + offset + 20));
11368 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11369 QT_UINT32 (stsd_entry_data + offset + 24));
11370 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11371 QT_UINT32 (stsd_entry_data + offset + 28));
11372 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11373 QT_UINT32 (stsd_entry_data + offset + 32));
11374 } else if (version != 0x00000) {
11375 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11380 gst_caps_unref (entry->caps);
11382 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11383 stsd_entry_data + 32, len - 16, &codec);
11391 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11393 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11395 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11397 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11400 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11401 gst_caps_set_simple (entry->caps,
11402 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11409 const guint8 *owma_data;
11410 const gchar *codec_name = NULL;
11414 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11415 /* FIXME this should also be gst_riff_strf_auds,
11416 * but the latter one is actually missing bits-per-sample :( */
11421 gint32 nSamplesPerSec;
11422 gint32 nAvgBytesPerSec;
11423 gint16 nBlockAlign;
11424 gint16 wBitsPerSample;
11427 WAVEFORMATEX *wfex;
11429 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11430 owma_data = stsd_entry_data;
11431 owma_len = QT_UINT32 (owma_data);
11432 if (owma_len <= 54) {
11433 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11436 wfex = (WAVEFORMATEX *) (owma_data + 36);
11437 buf = gst_buffer_new_and_alloc (owma_len - 54);
11438 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11439 if (wfex->wFormatTag == 0x0161) {
11440 codec_name = "Windows Media Audio";
11442 } else if (wfex->wFormatTag == 0x0162) {
11443 codec_name = "Windows Media Audio 9 Pro";
11445 } else if (wfex->wFormatTag == 0x0163) {
11446 codec_name = "Windows Media Audio 9 Lossless";
11447 /* is that correct? gstffmpegcodecmap.c is missing it, but
11448 * fluendo codec seems to support it */
11452 gst_caps_set_simple (entry->caps,
11453 "codec_data", GST_TYPE_BUFFER, buf,
11454 "wmaversion", G_TYPE_INT, version,
11455 "block_align", G_TYPE_INT,
11456 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11457 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11458 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11459 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11460 gst_buffer_unref (buf);
11464 codec = g_strdup (codec_name);
11470 gint len = QT_UINT32 (stsd_entry_data) - offset;
11471 const guint8 *wfex_data = stsd_entry_data + offset;
11472 const gchar *codec_name = NULL;
11474 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11475 /* FIXME this should also be gst_riff_strf_auds,
11476 * but the latter one is actually missing bits-per-sample :( */
11481 gint32 nSamplesPerSec;
11482 gint32 nAvgBytesPerSec;
11483 gint16 nBlockAlign;
11484 gint16 wBitsPerSample;
11489 /* FIXME: unify with similar wavformatex parsing code above */
11490 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11496 if (QT_UINT32 (wfex_data) <= len)
11497 size = QT_UINT32 (wfex_data) - 8;
11502 /* No real data, so break out */
11505 switch (QT_FOURCC (wfex_data + 4)) {
11506 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11508 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11513 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11514 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11515 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11516 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11517 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11518 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11519 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11521 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11522 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11523 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11524 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11525 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11526 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11528 if (wfex.wFormatTag == 0x0161) {
11529 codec_name = "Windows Media Audio";
11531 } else if (wfex.wFormatTag == 0x0162) {
11532 codec_name = "Windows Media Audio 9 Pro";
11534 } else if (wfex.wFormatTag == 0x0163) {
11535 codec_name = "Windows Media Audio 9 Lossless";
11536 /* is that correct? gstffmpegcodecmap.c is missing it, but
11537 * fluendo codec seems to support it */
11541 gst_caps_set_simple (entry->caps,
11542 "wmaversion", G_TYPE_INT, version,
11543 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11544 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11545 "width", G_TYPE_INT, wfex.wBitsPerSample,
11546 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11548 if (size > wfex.cbSize) {
11551 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11552 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11553 size - wfex.cbSize);
11554 gst_caps_set_simple (entry->caps,
11555 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11556 gst_buffer_unref (buf);
11558 GST_WARNING_OBJECT (qtdemux, "no codec data");
11563 codec = g_strdup (codec_name);
11571 wfex_data += size + 8;
11577 const guint8 *opus_data;
11578 guint8 *channel_mapping = NULL;
11581 guint8 channel_mapping_family;
11582 guint8 stream_count;
11583 guint8 coupled_count;
11586 opus_data = stsd_entry_data;
11588 channels = GST_READ_UINT8 (opus_data + 45);
11589 rate = GST_READ_UINT32_LE (opus_data + 48);
11590 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11591 stream_count = GST_READ_UINT8 (opus_data + 55);
11592 coupled_count = GST_READ_UINT8 (opus_data + 56);
11594 if (channels > 0) {
11595 channel_mapping = g_malloc (channels * sizeof (guint8));
11596 for (i = 0; i < channels; i++)
11597 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11600 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11601 channel_mapping_family, stream_count, coupled_count,
11613 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11614 GST_TAG_AUDIO_CODEC, codec, NULL);
11618 /* some bitrate info may have ended up in caps */
11619 s = gst_caps_get_structure (entry->caps, 0);
11620 gst_structure_get_int (s, "bitrate", &bitrate);
11622 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11623 GST_TAG_BITRATE, bitrate, NULL);
11626 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11627 if (!stream->protected) {
11629 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11633 if (stream->protected && fourcc == FOURCC_mp4a) {
11634 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11638 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11646 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11648 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11650 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11654 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11655 16 bits is a byte-swapped wave-style codec identifier,
11656 and we can find a WAVE header internally to a 'wave' atom here.
11657 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11658 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11661 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11662 if (len < offset + 20) {
11663 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11665 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11666 const guint8 *data = stsd_entry_data + offset + 16;
11668 GNode *waveheadernode;
11670 wavenode = g_node_new ((guint8 *) data);
11671 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11672 const guint8 *waveheader;
11675 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11676 if (waveheadernode) {
11677 waveheader = (const guint8 *) waveheadernode->data;
11678 headerlen = QT_UINT32 (waveheader);
11680 if (headerlen > 8) {
11681 gst_riff_strf_auds *header = NULL;
11682 GstBuffer *headerbuf;
11688 headerbuf = gst_buffer_new_and_alloc (headerlen);
11689 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11691 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11692 headerbuf, &header, &extra)) {
11693 gst_caps_unref (entry->caps);
11694 /* FIXME: Need to do something with the channel reorder map */
11696 gst_riff_create_audio_caps (header->format, NULL, header,
11697 extra, NULL, NULL, NULL);
11700 gst_buffer_unref (extra);
11705 GST_DEBUG ("Didn't find waveheadernode for this codec");
11707 g_node_destroy (wavenode);
11710 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11711 stream->stream_tags);
11715 /* FIXME: what is in the chunk? */
11718 gint len = QT_UINT32 (stsd_data);
11720 /* seems to be always = 116 = 0x74 */
11726 gint len = QT_UINT32 (stsd_entry_data);
11729 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11731 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11732 gst_caps_set_simple (entry->caps,
11733 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11734 gst_buffer_unref (buf);
11736 gst_caps_set_simple (entry->caps,
11737 "samplesize", G_TYPE_INT, samplesize, NULL);
11742 GNode *alac, *wave = NULL;
11744 /* apparently, m4a has this atom appended directly in the stsd entry,
11745 * while mov has it in a wave atom */
11746 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11748 /* alac now refers to stsd entry atom */
11749 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11751 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11753 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11756 const guint8 *alac_data = alac->data;
11757 gint len = QT_UINT32 (alac->data);
11761 GST_DEBUG_OBJECT (qtdemux,
11762 "discarding alac atom with unexpected len %d", len);
11764 /* codec-data contains alac atom size and prefix,
11765 * ffmpeg likes it that way, not quite gst-ish though ...*/
11766 buf = gst_buffer_new_and_alloc (len);
11767 gst_buffer_fill (buf, 0, alac->data, len);
11768 gst_caps_set_simple (entry->caps,
11769 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11770 gst_buffer_unref (buf);
11772 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11773 entry->n_channels = QT_UINT8 (alac_data + 21);
11774 entry->rate = QT_UINT32 (alac_data + 32);
11777 gst_caps_set_simple (entry->caps,
11778 "samplesize", G_TYPE_INT, samplesize, NULL);
11783 /* The codingname of the sample entry is 'fLaC' */
11784 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11787 /* The 'dfLa' box is added to the sample entry to convey
11788 initializing information for the decoder. */
11789 const GNode *dfla =
11790 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11793 const guint32 len = QT_UINT32 (dfla->data);
11795 /* Must contain at least dfLa box header (12),
11796 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11798 GST_DEBUG_OBJECT (qtdemux,
11799 "discarding dfla atom with unexpected len %d", len);
11801 /* skip dfLa header to get the METADATA_BLOCKs */
11802 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11803 const guint32 metadata_blocks_len = len - 12;
11805 gchar *stream_marker = g_strdup ("fLaC");
11806 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11807 strlen (stream_marker));
11810 guint32 remainder = 0;
11811 guint32 block_size = 0;
11812 gboolean is_last = FALSE;
11814 GValue array = G_VALUE_INIT;
11815 GValue value = G_VALUE_INIT;
11817 g_value_init (&array, GST_TYPE_ARRAY);
11818 g_value_init (&value, GST_TYPE_BUFFER);
11820 gst_value_set_buffer (&value, block);
11821 gst_value_array_append_value (&array, &value);
11822 g_value_reset (&value);
11824 gst_buffer_unref (block);
11826 /* check there's at least one METADATA_BLOCK_HEADER's worth
11827 * of data, and we haven't already finished parsing */
11828 while (!is_last && ((index + 3) < metadata_blocks_len)) {
11829 remainder = metadata_blocks_len - index;
11831 /* add the METADATA_BLOCK_HEADER size to the signalled size */
11833 (metadata_blocks[index + 1] << 16) +
11834 (metadata_blocks[index + 2] << 8) +
11835 metadata_blocks[index + 3];
11837 /* be careful not to read off end of box */
11838 if (block_size > remainder) {
11842 is_last = metadata_blocks[index] >> 7;
11844 block = gst_buffer_new_and_alloc (block_size);
11846 gst_buffer_fill (block, 0, &metadata_blocks[index],
11849 gst_value_set_buffer (&value, block);
11850 gst_value_array_append_value (&array, &value);
11851 g_value_reset (&value);
11853 gst_buffer_unref (block);
11855 index += block_size;
11858 /* only append the metadata if we successfully read all of it */
11860 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11861 (stream)->caps, 0), "streamheader", &array);
11863 GST_WARNING_OBJECT (qtdemux,
11864 "discarding all METADATA_BLOCKs due to invalid "
11865 "block_size %d at idx %d, rem %d", block_size, index,
11869 g_value_unset (&value);
11870 g_value_unset (&array);
11872 /* The sample rate obtained from the stsd may not be accurate
11873 * since it cannot represent rates greater than 65535Hz, so
11874 * override that value with the sample rate from the
11875 * METADATA_BLOCK_STREAMINFO block */
11876 CUR_STREAM (stream)->rate =
11877 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11888 gint len = QT_UINT32 (stsd_entry_data);
11891 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11894 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11896 /* If we have enough data, let's try to get the 'damr' atom. See
11897 * the 3GPP container spec (26.244) for more details. */
11898 if ((len - 0x34) > 8 &&
11899 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11900 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11901 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11904 gst_caps_set_simple (entry->caps,
11905 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11906 gst_buffer_unref (buf);
11912 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
11913 gint len = QT_UINT32 (stsd_entry_data);
11916 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
11918 if (sound_version == 1) {
11919 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
11920 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
11921 guint8 codec_data[2];
11923 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
11925 gint sample_rate_index =
11926 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
11928 /* build AAC codec data */
11929 codec_data[0] = profile << 3;
11930 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
11931 codec_data[1] = (sample_rate_index & 0x01) << 7;
11932 codec_data[1] |= (channels & 0xF) << 3;
11934 buf = gst_buffer_new_and_alloc (2);
11935 gst_buffer_fill (buf, 0, codec_data, 2);
11936 gst_caps_set_simple (entry->caps,
11937 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11938 gst_buffer_unref (buf);
11944 /* Fully handled elsewhere */
11947 GST_INFO_OBJECT (qtdemux,
11948 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11952 GST_INFO_OBJECT (qtdemux,
11953 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11954 GST_FOURCC_ARGS (fourcc), entry->caps);
11956 } else if (stream->subtype == FOURCC_strm) {
11957 if (fourcc == FOURCC_rtsp) {
11958 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
11960 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
11961 GST_FOURCC_ARGS (fourcc));
11962 goto unknown_stream;
11964 entry->sampled = TRUE;
11965 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
11966 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
11967 || stream->subtype == FOURCC_clcp) {
11969 entry->sampled = TRUE;
11970 entry->sparse = TRUE;
11973 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11976 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11977 GST_TAG_SUBTITLE_CODEC, codec, NULL);
11982 /* hunt for sort-of codec data */
11986 GNode *mp4s = NULL;
11987 GNode *esds = NULL;
11989 /* look for palette in a stsd->mp4s->esds sub-atom */
11990 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
11992 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
11993 if (esds == NULL) {
11995 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
11999 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12000 stream->stream_tags);
12004 GST_INFO_OBJECT (qtdemux,
12005 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12008 GST_INFO_OBJECT (qtdemux,
12009 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12010 GST_FOURCC_ARGS (fourcc), entry->caps);
12012 /* everything in 1 sample */
12013 entry->sampled = TRUE;
12016 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12019 if (entry->caps == NULL)
12020 goto unknown_stream;
12023 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12024 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12030 /* promote to sampled format */
12031 if (entry->fourcc == FOURCC_samr) {
12032 /* force mono 8000 Hz for AMR */
12033 entry->sampled = TRUE;
12034 entry->n_channels = 1;
12035 entry->rate = 8000;
12036 } else if (entry->fourcc == FOURCC_sawb) {
12037 /* force mono 16000 Hz for AMR-WB */
12038 entry->sampled = TRUE;
12039 entry->n_channels = 1;
12040 entry->rate = 16000;
12041 } else if (entry->fourcc == FOURCC_mp4a) {
12042 entry->sampled = TRUE;
12046 stsd_entry_data += len;
12047 remaining_stsd_len -= len;
12051 /* collect sample information */
12052 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12053 goto samples_failed;
12055 if (qtdemux->fragmented) {
12058 /* need all moov samples as basis; probably not many if any at all */
12059 /* prevent moof parsing taking of at this time */
12060 offset = qtdemux->moof_offset;
12061 qtdemux->moof_offset = 0;
12062 if (stream->n_samples &&
12063 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12064 qtdemux->moof_offset = offset;
12065 goto samples_failed;
12067 qtdemux->moof_offset = 0;
12068 /* movie duration more reliable in this case (e.g. mehd) */
12069 if (qtdemux->segment.duration &&
12070 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12072 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12075 /* configure segments */
12076 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12077 goto segments_failed;
12079 /* add some language tag, if useful */
12080 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12081 strcmp (stream->lang_id, "und")) {
12082 const gchar *lang_code;
12084 /* convert ISO 639-2 code to ISO 639-1 */
12085 lang_code = gst_tag_get_language_code (stream->lang_id);
12086 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12087 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12090 /* Check for UDTA tags */
12091 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12092 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12095 /* Insert and sort new stream in track-id order.
12096 * This will help in comparing old/new streams during stream update check */
12097 qtdemux->active_streams =
12098 g_list_insert_sorted (qtdemux->active_streams, stream,
12099 (GCompareFunc) qtdemux_track_id_compare_func);
12100 qtdemux->n_streams++;
12101 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
12108 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12109 (_("This file is corrupt and cannot be played.")), (NULL));
12111 gst_qtdemux_stream_free (stream);
12116 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12117 gst_qtdemux_stream_free (stream);
12123 /* we posted an error already */
12124 /* free stbl sub-atoms */
12125 gst_qtdemux_stbl_free (stream);
12126 gst_qtdemux_stream_free (stream);
12131 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12137 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12138 GST_FOURCC_ARGS (stream->subtype));
12139 gst_qtdemux_stream_free (stream);
12144 /* If we can estimate the overall bitrate, and don't have information about the
12145 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12146 * the overall bitrate minus the sum of the bitrates of all other streams. This
12147 * should be useful for the common case where we have one audio and one video
12148 * stream and can estimate the bitrate of one, but not the other. */
12150 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12152 QtDemuxStream *stream = NULL;
12153 gint64 size, sys_bitrate, sum_bitrate = 0;
12154 GstClockTime duration;
12158 if (qtdemux->fragmented)
12161 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12163 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12165 GST_DEBUG_OBJECT (qtdemux,
12166 "Size in bytes of the stream not known - bailing");
12170 /* Subtract the header size */
12171 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12172 size, qtdemux->header_size);
12174 if (size < qtdemux->header_size)
12177 size = size - qtdemux->header_size;
12179 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12180 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12184 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12185 QtDemuxStream *str = QTDEMUX_STREAM (iter->data);
12186 switch (str->subtype) {
12189 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12190 CUR_STREAM (str)->caps);
12191 /* retrieve bitrate, prefer avg then max */
12193 if (str->stream_tags) {
12194 if (gst_tag_list_get_uint (str->stream_tags,
12195 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12196 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12197 if (gst_tag_list_get_uint (str->stream_tags,
12198 GST_TAG_NOMINAL_BITRATE, &bitrate))
12199 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12200 if (gst_tag_list_get_uint (str->stream_tags,
12201 GST_TAG_BITRATE, &bitrate))
12202 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12205 sum_bitrate += bitrate;
12208 GST_DEBUG_OBJECT (qtdemux,
12209 ">1 stream with unknown bitrate - bailing");
12216 /* For other subtypes, we assume no significant impact on bitrate */
12222 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12226 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12228 if (sys_bitrate < sum_bitrate) {
12229 /* This can happen, since sum_bitrate might be derived from maximum
12230 * bitrates and not average bitrates */
12231 GST_DEBUG_OBJECT (qtdemux,
12232 "System bitrate less than sum bitrate - bailing");
12236 bitrate = sys_bitrate - sum_bitrate;
12237 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12238 ", Stream bitrate = %u", sys_bitrate, bitrate);
12240 if (!stream->stream_tags)
12241 stream->stream_tags = gst_tag_list_new_empty ();
12243 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12245 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12246 GST_TAG_BITRATE, bitrate, NULL);
12249 static GstFlowReturn
12250 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12252 GstFlowReturn ret = GST_FLOW_OK;
12253 GList *iter, *next;
12255 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12257 for (iter = qtdemux->active_streams; ret == GST_FLOW_OK && iter; iter = next) {
12258 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12259 guint32 sample_num = 0;
12263 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12264 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12266 if (qtdemux->fragmented) {
12267 /* need all moov samples first */
12268 GST_OBJECT_LOCK (qtdemux);
12269 while (stream->n_samples == 0)
12270 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12272 GST_OBJECT_UNLOCK (qtdemux);
12274 /* discard any stray moof */
12275 qtdemux->moof_offset = 0;
12278 /* prepare braking */
12279 if (ret != GST_FLOW_ERROR)
12282 /* in pull mode, we should have parsed some sample info by now;
12283 * and quite some code will not handle no samples.
12284 * in push mode, we'll just have to deal with it */
12285 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12286 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12287 gst_qtdemux_remove_stream (qtdemux, stream);
12289 } else if (stream->track_id == qtdemux->chapters_track_id &&
12290 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12291 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12292 so that it doesn't look like a subtitle track */
12293 gst_qtdemux_remove_stream (qtdemux, stream);
12297 /* parse the initial sample for use in setting the frame rate cap */
12298 while (sample_num == 0 && sample_num < stream->n_samples) {
12299 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12309 _stream_in_list (GList * list, QtDemuxStream * stream)
12313 for (iter = list; iter; iter = g_list_next (iter)) {
12314 QtDemuxStream *tmp = QTDEMUX_STREAM (iter->data);
12315 if (!g_strcmp0 (tmp->stream_id, stream->stream_id))
12323 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12327 g_return_val_if_fail (qtdemux->active_streams != NULL, FALSE);
12329 /* streams in list are sorted in track-id order */
12330 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12331 new = g_list_next (new), old = g_list_next (old)) {
12333 /* Different stream-id, updated */
12334 if (g_strcmp0 (QTDEMUX_STREAM (new->data)->stream_id,
12335 QTDEMUX_STREAM (old->data)->stream_id))
12339 /* Different length, updated */
12340 if (new != NULL || old != NULL)
12347 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12348 QtDemuxStream * oldstream, QtDemuxStream * newstream)
12350 /* Connect old stream's srcpad to new stream */
12351 newstream->pad = oldstream->pad;
12352 oldstream->pad = NULL;
12354 /* unset new_stream to prevent stream-start event */
12355 newstream->new_stream = FALSE;
12357 return gst_qtdemux_configure_stream (qtdemux, newstream);
12361 qtdemux_update_streams (GstQTDemux * qtdemux)
12363 GList *iter, *next;
12365 /* At below, figure out which stream in active_streams has identical stream-id
12366 * with that of in old_streams. If there is matching stream-id,
12367 * corresponding newstream will not be exposed again,
12368 * but demux will reuse srcpad of matched old stream
12370 * active_streams : newly created streams from the latest moov
12371 * old_streams : existing streams (belong to previous moov)
12374 /* Count n_streams again */
12375 qtdemux->n_streams = 0;
12377 for (iter = qtdemux->active_streams; iter; iter = next) {
12379 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12383 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12384 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12386 qtdemux->n_streams++;
12388 if (qtdemux->streams_aware
12389 && (tmp = _stream_in_list (qtdemux->old_streams, stream)) != NULL
12390 && QTDEMUX_STREAM (tmp->data)->pad) {
12391 QtDemuxStream *oldstream = QTDEMUX_STREAM (tmp->data);
12393 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12395 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12398 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, oldstream);
12399 gst_qtdemux_stream_free (oldstream);
12403 /* now we have all info and can expose */
12404 list = stream->stream_tags;
12405 stream->stream_tags = NULL;
12406 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12414 /* Must be called with expose lock */
12415 static GstFlowReturn
12416 qtdemux_expose_streams (GstQTDemux * qtdemux)
12418 GList *iter, *next;
12420 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12422 if (!qtdemux_is_streams_update (qtdemux)) {
12425 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12426 for (new = qtdemux->active_streams, old = qtdemux->old_streams; new && old;
12427 new = g_list_next (new), old = g_list_next (old)) {
12428 if (!qtdemux_reuse_and_configure_stream (qtdemux,
12429 QTDEMUX_STREAM (old->data), QTDEMUX_STREAM (new->data)))
12430 return GST_FLOW_ERROR;
12433 g_list_free_full (qtdemux->old_streams,
12434 (GDestroyNotify) gst_qtdemux_stream_free);
12435 qtdemux->old_streams = NULL;
12437 return GST_FLOW_OK;
12440 if (qtdemux->streams_aware) {
12441 if (!qtdemux_update_streams (qtdemux))
12442 return GST_FLOW_ERROR;
12444 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12445 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12448 /* now we have all info and can expose */
12449 list = stream->stream_tags;
12450 stream->stream_tags = NULL;
12451 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12452 return GST_FLOW_ERROR;
12457 gst_qtdemux_guess_bitrate (qtdemux);
12459 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12461 /* If we have still old_streams, it's no more used stream */
12462 for (iter = qtdemux->old_streams; iter; iter = next) {
12463 QtDemuxStream *stream = QTDEMUX_STREAM (iter->data);
12464 next = g_list_next (iter);
12469 event = gst_event_new_eos ();
12470 if (qtdemux->segment_seqnum)
12471 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12473 gst_pad_push_event (stream->pad, event);
12476 qtdemux->old_streams = g_list_remove (qtdemux->old_streams, stream);
12477 gst_qtdemux_stream_free (stream);
12480 /* check if we should post a redirect in case there is a single trak
12481 * and it is a redirecting trak */
12482 if (qtdemux->n_streams == 1 &&
12483 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri != NULL) {
12486 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12487 "an external content");
12488 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12489 gst_structure_new ("redirect",
12490 "new-location", G_TYPE_STRING,
12491 QTDEMUX_FIRST_STREAM (qtdemux)->redirect_uri, NULL));
12492 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12493 qtdemux->posted_redirect = TRUE;
12496 for (iter = qtdemux->active_streams; iter; iter = g_list_next (iter)) {
12497 qtdemux_do_allocation (qtdemux, QTDEMUX_STREAM (iter->data));
12500 qtdemux->exposed = TRUE;
12501 return GST_FLOW_OK;
12504 /* check if major or compatible brand is 3GP */
12505 static inline gboolean
12506 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12509 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12511 } else if (qtdemux->comp_brands != NULL) {
12515 gboolean res = FALSE;
12517 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12520 while (size >= 4) {
12521 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12526 gst_buffer_unmap (qtdemux->comp_brands, &map);
12533 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12534 static inline gboolean
12535 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12537 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12538 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12539 || fourcc == FOURCC_albm;
12543 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12544 const char *tag, const char *dummy, GNode * node)
12546 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12550 gdouble longitude, latitude, altitude;
12553 len = QT_UINT32 (node->data);
12560 /* TODO: language code skipped */
12562 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12565 /* do not alarm in trivial case, but bail out otherwise */
12566 if (*(data + offset) != 0) {
12567 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12571 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12572 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12573 offset += strlen (name);
12577 if (len < offset + 2 + 4 + 4 + 4)
12580 /* +1 +1 = skip null-terminator and location role byte */
12582 /* table in spec says unsigned, semantics say negative has meaning ... */
12583 longitude = QT_SFP32 (data + offset);
12586 latitude = QT_SFP32 (data + offset);
12589 altitude = QT_SFP32 (data + offset);
12591 /* one invalid means all are invalid */
12592 if (longitude >= -180.0 && longitude <= 180.0 &&
12593 latitude >= -90.0 && latitude <= 90.0) {
12594 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12595 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12596 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12597 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12600 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12607 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12614 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12615 const char *tag, const char *dummy, GNode * node)
12621 len = QT_UINT32 (node->data);
12625 y = QT_UINT16 ((guint8 *) node->data + 12);
12627 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12630 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12632 date = g_date_new_dmy (1, 1, y);
12633 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12634 g_date_free (date);
12638 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12639 const char *tag, const char *dummy, GNode * node)
12642 char *tag_str = NULL;
12647 len = QT_UINT32 (node->data);
12652 entity = (guint8 *) node->data + offset;
12653 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12654 GST_DEBUG_OBJECT (qtdemux,
12655 "classification info: %c%c%c%c invalid classification entity",
12656 entity[0], entity[1], entity[2], entity[3]);
12661 table = QT_UINT16 ((guint8 *) node->data + offset);
12663 /* Language code skipped */
12667 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12668 * XXXX: classification entity, fixed length 4 chars.
12669 * Y[YYYY]: classification table, max 5 chars.
12671 tag_str = g_strdup_printf ("----://%u/%s",
12672 table, (char *) node->data + offset);
12674 /* memcpy To be sure we're preserving byte order */
12675 memcpy (tag_str, entity, 4);
12676 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12678 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12687 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12693 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12694 const char *tag, const char *dummy, GNode * node)
12696 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12702 gboolean ret = TRUE;
12703 const gchar *charset = NULL;
12705 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12707 len = QT_UINT32 (data->data);
12708 type = QT_UINT32 ((guint8 *) data->data + 8);
12709 if (type == 0x00000001 && len > 16) {
12710 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12713 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12714 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12717 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12721 len = QT_UINT32 (node->data);
12722 type = QT_UINT32 ((guint8 *) node->data + 4);
12723 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12727 /* Type starts with the (C) symbol, so the next data is a list
12728 * of (string size(16), language code(16), string) */
12730 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12731 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12733 /* the string + fourcc + size + 2 16bit fields,
12734 * means that there are more tags in this atom */
12735 if (len > str_len + 8 + 4) {
12736 /* TODO how to represent the same tag in different languages? */
12737 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12738 "text alternatives, reading only first one");
12742 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12743 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12745 if (lang_code < 0x800) { /* MAC encoded string */
12748 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12749 QT_FOURCC ((guint8 *) node->data + 4))) {
12750 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12752 /* we go for 3GP style encoding if major brands claims so,
12753 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12754 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12755 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12756 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12758 /* 16-bit Language code is ignored here as well */
12759 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12766 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12767 ret = FALSE; /* may have to fallback */
12770 GError *err = NULL;
12772 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12773 charset, NULL, NULL, &err);
12775 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12776 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12778 g_error_free (err);
12781 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12782 len - offset, env_vars);
12785 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12786 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12790 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12797 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12798 const char *tag, const char *dummy, GNode * node)
12800 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12804 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12805 const char *tag, const char *dummy, GNode * node)
12807 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12809 char *s, *t, *k = NULL;
12814 /* first try normal string tag if major brand not 3GP */
12815 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12816 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12817 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12818 * let's try it 3gpp way after minor safety check */
12820 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12826 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12830 len = QT_UINT32 (data);
12834 count = QT_UINT8 (data + 14);
12836 for (; count; count--) {
12839 if (offset + 1 > len)
12841 slen = QT_UINT8 (data + offset);
12843 if (offset + slen > len)
12845 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12848 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12850 t = g_strjoin (",", k, s, NULL);
12858 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12865 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12866 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12875 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12881 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12882 const char *tag1, const char *tag2, GNode * node)
12889 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12891 len = QT_UINT32 (data->data);
12892 type = QT_UINT32 ((guint8 *) data->data + 8);
12893 if (type == 0x00000000 && len >= 22) {
12894 n1 = QT_UINT16 ((guint8 *) data->data + 18);
12895 n2 = QT_UINT16 ((guint8 *) data->data + 20);
12897 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12898 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12901 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12902 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12909 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12910 const char *tag1, const char *dummy, GNode * node)
12917 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12919 len = QT_UINT32 (data->data);
12920 type = QT_UINT32 ((guint8 *) data->data + 8);
12921 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12922 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12923 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12924 n1 = QT_UINT16 ((guint8 *) data->data + 16);
12926 /* do not add bpm=0 */
12927 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12928 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12936 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12937 const char *tag1, const char *dummy, GNode * node)
12944 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12946 len = QT_UINT32 (data->data);
12947 type = QT_UINT32 ((guint8 *) data->data + 8);
12948 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12949 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12950 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12951 num = QT_UINT32 ((guint8 *) data->data + 16);
12953 /* do not add num=0 */
12954 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12955 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12962 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12963 const char *tag1, const char *dummy, GNode * node)
12970 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12972 len = QT_UINT32 (data->data);
12973 type = QT_UINT32 ((guint8 *) data->data + 8);
12974 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12975 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12976 GstTagImageType image_type;
12978 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12979 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12981 image_type = GST_TAG_IMAGE_TYPE_NONE;
12984 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12985 len - 16, image_type))) {
12986 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12987 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12988 gst_sample_unref (sample);
12995 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12996 const char *tag, const char *dummy, GNode * node)
12999 GstDateTime *datetime = NULL;
13004 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13006 len = QT_UINT32 (data->data);
13007 type = QT_UINT32 ((guint8 *) data->data + 8);
13008 if (type == 0x00000001 && len > 16) {
13009 guint y, m = 1, d = 1;
13012 s = g_strndup ((char *) data->data + 16, len - 16);
13013 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13014 datetime = gst_date_time_new_from_iso8601_string (s);
13015 if (datetime != NULL) {
13016 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13018 gst_date_time_unref (datetime);
13021 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13022 if (ret >= 1 && y > 1500 && y < 3000) {
13025 date = g_date_new_dmy (d, m, y);
13026 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13027 g_date_free (date);
13029 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13037 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13038 const char *tag, const char *dummy, GNode * node)
13042 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13044 /* re-route to normal string tag if major brand says so
13045 * or no data atom and compatible brand suggests so */
13046 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13047 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13048 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13053 guint len, type, n;
13055 len = QT_UINT32 (data->data);
13056 type = QT_UINT32 ((guint8 *) data->data + 8);
13057 if (type == 0x00000000 && len >= 18) {
13058 n = QT_UINT16 ((guint8 *) data->data + 16);
13060 const gchar *genre;
13062 genre = gst_tag_id3_genre_get (n - 1);
13063 if (genre != NULL) {
13064 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13065 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13073 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13074 const gchar * tag, guint8 * data, guint32 datasize)
13079 /* make a copy to have \0 at the end */
13080 datacopy = g_strndup ((gchar *) data, datasize);
13082 /* convert the str to double */
13083 if (sscanf (datacopy, "%lf", &value) == 1) {
13084 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13085 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13087 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13095 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13096 const char *tag, const char *tag_bis, GNode * node)
13105 const gchar *meanstr;
13106 const gchar *namestr;
13108 /* checking the whole ---- atom size for consistency */
13109 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13110 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13114 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13116 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13120 meansize = QT_UINT32 (mean->data);
13121 if (meansize <= 12) {
13122 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13125 meanstr = ((gchar *) mean->data) + 12;
13128 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13130 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13134 namesize = QT_UINT32 (name->data);
13135 if (namesize <= 12) {
13136 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13139 namestr = ((gchar *) name->data) + 12;
13147 * uint24 - data type
13151 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13153 GST_WARNING_OBJECT (demux, "No data atom in this tag");
13156 datasize = QT_UINT32 (data->data);
13157 if (datasize <= 16) {
13158 GST_WARNING_OBJECT (demux, "Data atom too small");
13161 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13163 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13164 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13165 static const struct
13167 const gchar name[28];
13168 const gchar tag[28];
13171 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13172 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13173 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13174 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13175 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13176 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13177 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13178 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13182 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13183 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13184 switch (gst_tag_get_type (tags[i].tag)) {
13185 case G_TYPE_DOUBLE:
13186 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13187 ((guint8 *) data->data) + 16, datasize - 16);
13189 case G_TYPE_STRING:
13190 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13199 if (i == G_N_ELEMENTS (tags))
13209 #ifndef GST_DISABLE_GST_DEBUG
13211 gchar *namestr_dbg;
13212 gchar *meanstr_dbg;
13214 meanstr_dbg = g_strndup (meanstr, meansize);
13215 namestr_dbg = g_strndup (namestr, namesize);
13217 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13218 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13220 g_free (namestr_dbg);
13221 g_free (meanstr_dbg);
13228 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13229 const char *tag_bis, GNode * node)
13234 GstTagList *id32_taglist = NULL;
13236 GST_LOG_OBJECT (demux, "parsing ID32");
13239 len = GST_READ_UINT32_BE (data);
13241 /* need at least full box and language tag */
13245 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13246 gst_buffer_fill (buf, 0, data + 14, len - 14);
13248 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13249 if (id32_taglist) {
13250 GST_LOG_OBJECT (demux, "parsing ok");
13251 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13252 gst_tag_list_unref (id32_taglist);
13254 GST_LOG_OBJECT (demux, "parsing failed");
13257 gst_buffer_unref (buf);
13260 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13261 const char *tag, const char *tag_bis, GNode * node);
13264 FOURCC_pcst -> if media is a podcast -> bool
13265 FOURCC_cpil -> if media is part of a compilation -> bool
13266 FOURCC_pgap -> if media is part of a gapless context -> bool
13267 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13270 static const struct
13273 const gchar *gst_tag;
13274 const gchar *gst_tag_bis;
13275 const GstQTDemuxAddTagFunc func;
13278 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13279 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13280 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13281 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13282 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13283 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13284 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13285 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13286 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13287 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13288 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13289 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13290 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13291 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13292 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13293 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13294 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13295 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13296 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13297 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13298 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13299 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13300 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13301 qtdemux_tag_add_num}, {
13302 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13303 qtdemux_tag_add_num}, {
13304 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13305 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13306 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13307 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13308 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13309 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13310 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13311 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13312 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13313 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13314 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13315 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13316 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13317 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13318 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13319 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13320 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13321 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13322 qtdemux_tag_add_classification}, {
13323 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13324 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13325 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13327 /* This is a special case, some tags are stored in this
13328 * 'reverse dns naming', according to:
13329 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13332 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13333 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13334 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13337 struct _GstQtDemuxTagList
13340 GstTagList *taglist;
13342 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13345 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13351 const gchar *style;
13356 GstQTDemux *demux = qtdemuxtaglist->demux;
13357 GstTagList *taglist = qtdemuxtaglist->taglist;
13360 len = QT_UINT32 (data);
13361 buf = gst_buffer_new_and_alloc (len);
13362 gst_buffer_fill (buf, 0, data, len);
13364 /* heuristic to determine style of tag */
13365 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13366 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13368 else if (demux->major_brand == FOURCC_qt__)
13369 style = "quicktime";
13370 /* fall back to assuming iso/3gp tag style */
13374 /* santize the name for the caps. */
13375 for (i = 0; i < 4; i++) {
13376 guint8 d = data[4 + i];
13377 if (g_ascii_isalnum (d))
13378 ndata[i] = g_ascii_tolower (d);
13383 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13384 ndata[0], ndata[1], ndata[2], ndata[3]);
13385 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13387 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13388 sample = gst_sample_new (buf, NULL, NULL, s);
13389 gst_buffer_unref (buf);
13390 g_free (media_type);
13392 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13395 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13396 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13398 gst_sample_unref (sample);
13402 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13409 GstQtDemuxTagList demuxtaglist;
13411 demuxtaglist.demux = qtdemux;
13412 demuxtaglist.taglist = taglist;
13414 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13415 if (meta != NULL) {
13416 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13417 if (ilst == NULL) {
13418 GST_LOG_OBJECT (qtdemux, "no ilst");
13423 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13427 while (i < G_N_ELEMENTS (add_funcs)) {
13428 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13432 len = QT_UINT32 (node->data);
13434 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13435 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13437 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13438 add_funcs[i].gst_tag_bis, node);
13440 g_node_destroy (node);
13446 /* parsed nodes have been removed, pass along remainder as blob */
13447 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13448 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13450 /* parse up XMP_ node if existing */
13451 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13452 if (xmp_ != NULL) {
13454 GstTagList *xmptaglist;
13456 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13457 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13458 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13459 gst_buffer_unref (buf);
13461 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13463 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13469 GstStructure *structure; /* helper for sort function */
13471 guint min_req_bitrate;
13472 guint min_req_qt_version;
13476 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13478 GstQtReference *ref_a = (GstQtReference *) a;
13479 GstQtReference *ref_b = (GstQtReference *) b;
13481 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13482 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13484 /* known bitrates go before unknown; higher bitrates go first */
13485 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13488 /* sort the redirects and post a message for the application.
13491 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13493 GstQtReference *best;
13496 GValue list_val = { 0, };
13499 g_assert (references != NULL);
13501 references = g_list_sort (references, qtdemux_redirects_sort_func);
13503 best = (GstQtReference *) references->data;
13505 g_value_init (&list_val, GST_TYPE_LIST);
13507 for (l = references; l != NULL; l = l->next) {
13508 GstQtReference *ref = (GstQtReference *) l->data;
13509 GValue struct_val = { 0, };
13511 ref->structure = gst_structure_new ("redirect",
13512 "new-location", G_TYPE_STRING, ref->location, NULL);
13514 if (ref->min_req_bitrate > 0) {
13515 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13516 ref->min_req_bitrate, NULL);
13519 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13520 g_value_set_boxed (&struct_val, ref->structure);
13521 gst_value_list_append_value (&list_val, &struct_val);
13522 g_value_unset (&struct_val);
13523 /* don't free anything here yet, since we need best->structure below */
13526 g_assert (best != NULL);
13527 s = gst_structure_copy (best->structure);
13529 if (g_list_length (references) > 1) {
13530 gst_structure_set_value (s, "locations", &list_val);
13533 g_value_unset (&list_val);
13535 for (l = references; l != NULL; l = l->next) {
13536 GstQtReference *ref = (GstQtReference *) l->data;
13538 gst_structure_free (ref->structure);
13539 g_free (ref->location);
13542 g_list_free (references);
13544 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13545 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13546 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13547 qtdemux->posted_redirect = TRUE;
13550 /* look for redirect nodes, collect all redirect information and
13554 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13556 GNode *rmra, *rmda, *rdrf;
13558 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13560 GList *redirects = NULL;
13562 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13564 GstQtReference ref = { NULL, NULL, 0, 0 };
13565 GNode *rmdr, *rmvc;
13567 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13568 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13569 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13570 ref.min_req_bitrate);
13573 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13574 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13575 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13577 #ifndef GST_DISABLE_GST_DEBUG
13578 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13580 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13582 GST_LOG_OBJECT (qtdemux,
13583 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13584 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13585 bitmask, check_type);
13586 if (package == FOURCC_qtim && check_type == 0) {
13587 ref.min_req_qt_version = version;
13591 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13597 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13598 if (ref_len > 20) {
13599 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13600 ref_data = (guint8 *) rdrf->data + 20;
13601 if (ref_type == FOURCC_alis) {
13602 guint record_len, record_version, fn_len;
13604 if (ref_len > 70) {
13605 /* MacOSX alias record, google for alias-layout.txt */
13606 record_len = QT_UINT16 (ref_data + 4);
13607 record_version = QT_UINT16 (ref_data + 4 + 2);
13608 fn_len = QT_UINT8 (ref_data + 50);
13609 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13610 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13613 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13616 } else if (ref_type == FOURCC_url_) {
13617 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13619 GST_DEBUG_OBJECT (qtdemux,
13620 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13621 GST_FOURCC_ARGS (ref_type));
13623 if (ref.location != NULL) {
13624 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13626 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13628 GST_WARNING_OBJECT (qtdemux,
13629 "Failed to extract redirect location from rdrf atom");
13632 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13636 /* look for others */
13637 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13640 if (redirects != NULL) {
13641 qtdemux_process_redirects (qtdemux, redirects);
13647 static GstTagList *
13648 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13652 if (tags == NULL) {
13653 tags = gst_tag_list_new_empty ();
13654 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13657 if (qtdemux->major_brand == FOURCC_mjp2)
13658 fmt = "Motion JPEG 2000";
13659 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13661 else if (qtdemux->major_brand == FOURCC_qt__)
13663 else if (qtdemux->fragmented)
13666 fmt = "ISO MP4/M4A";
13668 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13669 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13671 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13677 /* we have read the complete moov node now.
13678 * This function parses all of the relevant info, creates the traks and
13679 * prepares all data structures for playback
13682 qtdemux_parse_tree (GstQTDemux * qtdemux)
13688 GstClockTime duration;
13690 guint64 creation_time;
13691 GstDateTime *datetime = NULL;
13694 /* make sure we have a usable taglist */
13695 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13697 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13698 if (mvhd == NULL) {
13699 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13700 return qtdemux_parse_redirects (qtdemux);
13703 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13704 if (version == 1) {
13705 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13706 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13707 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13708 } else if (version == 0) {
13709 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13710 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13711 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13713 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13717 /* Moving qt creation time (secs since 1904) to unix time */
13718 if (creation_time != 0) {
13719 /* Try to use epoch first as it should be faster and more commonly found */
13720 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13723 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13724 /* some data cleansing sanity */
13725 g_get_current_time (&now);
13726 if (now.tv_sec + 24 * 3600 < creation_time) {
13727 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13729 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13732 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13733 GDateTime *dt, *dt_local;
13735 dt = g_date_time_add_seconds (base_dt, creation_time);
13736 dt_local = g_date_time_to_local (dt);
13737 datetime = gst_date_time_new_from_g_date_time (dt_local);
13739 g_date_time_unref (base_dt);
13740 g_date_time_unref (dt);
13744 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13745 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13747 gst_date_time_unref (datetime);
13750 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13751 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13753 /* check for fragmented file and get some (default) data */
13754 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13757 GstByteReader mehd_data;
13759 /* let track parsing or anyone know weird stuff might happen ... */
13760 qtdemux->fragmented = TRUE;
13762 /* compensate for total duration */
13763 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13765 qtdemux_parse_mehd (qtdemux, &mehd_data);
13768 /* set duration in the segment info */
13769 gst_qtdemux_get_duration (qtdemux, &duration);
13771 qtdemux->segment.duration = duration;
13772 /* also do not exceed duration; stop is set that way post seek anyway,
13773 * and segment activation falls back to duration,
13774 * whereas loop only checks stop, so let's align this here as well */
13775 qtdemux->segment.stop = duration;
13778 /* parse all traks */
13779 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13781 qtdemux_parse_trak (qtdemux, trak);
13782 /* iterate all siblings */
13783 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13786 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13789 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13791 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13793 GST_LOG_OBJECT (qtdemux, "No udta node found.");
13796 /* maybe also some tags in meta box */
13797 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13799 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13800 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13802 GST_LOG_OBJECT (qtdemux, "No meta node found.");
13805 /* parse any protection system info */
13806 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13808 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13809 qtdemux_parse_pssh (qtdemux, pssh);
13810 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13813 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13818 /* taken from ffmpeg */
13820 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13832 len = (len << 7) | (c & 0x7f);
13841 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
13842 gsize codec_data_size)
13844 GList *list = NULL;
13845 guint8 *p = codec_data;
13846 gint i, offset, num_packets;
13847 guint *length, last;
13849 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
13851 if (codec_data == NULL || codec_data_size == 0)
13854 /* start of the stream and vorbis audio or theora video, need to
13855 * send the codec_priv data as first three packets */
13856 num_packets = p[0] + 1;
13857 GST_DEBUG_OBJECT (qtdemux,
13858 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
13859 (guint) num_packets, codec_data_size);
13861 /* Let's put some limits, Don't think there even is a xiph codec
13862 * with more than 3-4 headers */
13863 if (G_UNLIKELY (num_packets > 16)) {
13864 GST_WARNING_OBJECT (qtdemux,
13865 "Unlikely number of xiph headers, most likely not valid");
13869 length = g_alloca (num_packets * sizeof (guint));
13873 /* first packets, read length values */
13874 for (i = 0; i < num_packets - 1; i++) {
13876 while (offset < codec_data_size) {
13877 length[i] += p[offset];
13878 if (p[offset++] != 0xff)
13883 if (offset + last > codec_data_size)
13886 /* last packet is the remaining size */
13887 length[i] = codec_data_size - offset - last;
13889 for (i = 0; i < num_packets; i++) {
13892 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
13894 if (offset + length[i] > codec_data_size)
13897 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
13898 list = g_list_append (list, hdr);
13900 offset += length[i];
13909 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
13915 /* this can change the codec originally present in @list */
13917 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13918 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13920 int len = QT_UINT32 (esds->data);
13921 guint8 *ptr = esds->data;
13922 guint8 *end = ptr + len;
13924 guint8 *data_ptr = NULL;
13926 guint8 object_type_id = 0;
13927 guint8 stream_type = 0;
13928 const char *codec_name = NULL;
13929 GstCaps *caps = NULL;
13931 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13933 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13935 while (ptr + 1 < end) {
13936 tag = QT_UINT8 (ptr);
13937 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13939 len = read_descr_size (ptr, end, &ptr);
13940 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13942 /* Check the stated amount of data is available for reading */
13943 if (len < 0 || ptr + len > end)
13947 case ES_DESCRIPTOR_TAG:
13948 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
13949 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
13952 case DECODER_CONFIG_DESC_TAG:{
13953 guint max_bitrate, avg_bitrate;
13955 object_type_id = QT_UINT8 (ptr);
13956 stream_type = QT_UINT8 (ptr + 1) >> 2;
13957 max_bitrate = QT_UINT32 (ptr + 5);
13958 avg_bitrate = QT_UINT32 (ptr + 9);
13959 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13960 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
13961 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13962 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13963 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13964 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13965 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13966 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13968 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13969 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13970 avg_bitrate, NULL);
13975 case DECODER_SPECIFIC_INFO_TAG:
13976 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13977 if (object_type_id == 0xe0 && len == 0x40) {
13983 GST_DEBUG_OBJECT (qtdemux,
13984 "Have VOBSUB palette. Creating palette event");
13985 /* move to decConfigDescr data and read palette */
13987 for (i = 0; i < 16; i++) {
13988 clut[i] = QT_UINT32 (data);
13992 s = gst_structure_new ("application/x-gst-dvd", "event",
13993 G_TYPE_STRING, "dvd-spu-clut-change",
13994 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13995 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13996 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13997 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13998 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13999 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14000 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14001 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14004 /* store event and trigger custom processing */
14005 stream->pending_event =
14006 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14008 /* Generic codec_data handler puts it on the caps */
14015 case SL_CONFIG_DESC_TAG:
14016 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14020 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14022 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14028 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14029 * in use, and should also be used to override some other parameters for some
14031 switch (object_type_id) {
14032 case 0x20: /* MPEG-4 */
14033 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14034 * profile_and_level_indication */
14035 if (data_ptr != NULL && data_len >= 5 &&
14036 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14037 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14038 data_ptr + 4, data_len - 4);
14040 break; /* Nothing special needed here */
14041 case 0x21: /* H.264 */
14042 codec_name = "H.264 / AVC";
14043 caps = gst_caps_new_simple ("video/x-h264",
14044 "stream-format", G_TYPE_STRING, "avc",
14045 "alignment", G_TYPE_STRING, "au", NULL);
14047 case 0x40: /* AAC (any) */
14048 case 0x66: /* AAC Main */
14049 case 0x67: /* AAC LC */
14050 case 0x68: /* AAC SSR */
14051 /* Override channels and rate based on the codec_data, as it's often
14053 /* Only do so for basic setup without HE-AAC extension */
14054 if (data_ptr && data_len == 2) {
14055 guint channels, rate;
14057 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14059 entry->n_channels = channels;
14061 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14063 entry->rate = rate;
14066 /* Set level and profile if possible */
14067 if (data_ptr != NULL && data_len >= 2) {
14068 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14069 data_ptr, data_len);
14071 const gchar *profile_str = NULL;
14074 guint8 *codec_data;
14075 gint rate_idx, profile;
14077 /* No codec_data, let's invent something.
14078 * FIXME: This is wrong for SBR! */
14080 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14082 buffer = gst_buffer_new_and_alloc (2);
14083 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14084 codec_data = map.data;
14087 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14090 switch (object_type_id) {
14092 profile_str = "main";
14096 profile_str = "lc";
14100 profile_str = "ssr";
14108 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14110 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14112 gst_buffer_unmap (buffer, &map);
14113 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14114 GST_TYPE_BUFFER, buffer, NULL);
14115 gst_buffer_unref (buffer);
14118 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14119 G_TYPE_STRING, profile_str, NULL);
14123 case 0x60: /* MPEG-2, various profiles */
14129 codec_name = "MPEG-2 video";
14130 caps = gst_caps_new_simple ("video/mpeg",
14131 "mpegversion", G_TYPE_INT, 2,
14132 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14134 case 0x69: /* MPEG-2 BC audio */
14135 case 0x6B: /* MPEG-1 audio */
14136 caps = gst_caps_new_simple ("audio/mpeg",
14137 "mpegversion", G_TYPE_INT, 1, NULL);
14138 codec_name = "MPEG-1 audio";
14140 case 0x6A: /* MPEG-1 */
14141 codec_name = "MPEG-1 video";
14142 caps = gst_caps_new_simple ("video/mpeg",
14143 "mpegversion", G_TYPE_INT, 1,
14144 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14146 case 0x6C: /* MJPEG */
14148 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14150 codec_name = "Motion-JPEG";
14152 case 0x6D: /* PNG */
14154 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14156 codec_name = "PNG still images";
14158 case 0x6E: /* JPEG2000 */
14159 codec_name = "JPEG-2000";
14160 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14162 case 0xA4: /* Dirac */
14163 codec_name = "Dirac";
14164 caps = gst_caps_new_empty_simple ("video/x-dirac");
14166 case 0xA5: /* AC3 */
14167 codec_name = "AC-3 audio";
14168 caps = gst_caps_new_simple ("audio/x-ac3",
14169 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14171 case 0xA9: /* AC3 */
14172 codec_name = "DTS audio";
14173 caps = gst_caps_new_simple ("audio/x-dts",
14174 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14177 if (stream_type == 0x05 && data_ptr) {
14179 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14182 GValue arr_val = G_VALUE_INIT;
14183 GValue buf_val = G_VALUE_INIT;
14186 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14187 codec_name = "Vorbis";
14188 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14189 g_value_init (&arr_val, GST_TYPE_ARRAY);
14190 g_value_init (&buf_val, GST_TYPE_BUFFER);
14191 for (tmp = headers; tmp; tmp = tmp->next) {
14192 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14193 gst_value_array_append_value (&arr_val, &buf_val);
14195 s = gst_caps_get_structure (caps, 0);
14196 gst_structure_take_value (s, "streamheader", &arr_val);
14197 g_value_unset (&buf_val);
14198 g_list_free (headers);
14205 case 0xE1: /* QCELP */
14206 /* QCELP, the codec_data is a riff tag (little endian) with
14207 * 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). */
14208 caps = gst_caps_new_empty_simple ("audio/qcelp");
14209 codec_name = "QCELP";
14215 /* If we have a replacement caps, then change our caps for this stream */
14217 gst_caps_unref (entry->caps);
14218 entry->caps = caps;
14221 if (codec_name && list)
14222 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14223 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14225 /* Add the codec_data attribute to caps, if we have it */
14229 buffer = gst_buffer_new_and_alloc (data_len);
14230 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14232 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14233 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14235 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14237 gst_buffer_unref (buffer);
14242 static inline GstCaps *
14243 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14247 char *s, fourstr[5];
14249 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14250 for (i = 0; i < 4; i++) {
14251 if (!g_ascii_isalnum (fourstr[i]))
14254 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14255 caps = gst_caps_new_empty_simple (s);
14260 #define _codec(name) \
14262 if (codec_name) { \
14263 *codec_name = g_strdup (name); \
14268 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14269 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14270 const guint8 * stsd_entry_data, gchar ** codec_name)
14272 GstCaps *caps = NULL;
14273 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14277 _codec ("PNG still images");
14278 caps = gst_caps_new_empty_simple ("image/png");
14281 _codec ("JPEG still images");
14283 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14286 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14287 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14288 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14289 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14290 _codec ("Motion-JPEG");
14292 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14295 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14296 _codec ("Motion-JPEG format B");
14297 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14300 _codec ("JPEG-2000");
14301 /* override to what it should be according to spec, avoid palette_data */
14302 entry->bits_per_sample = 24;
14303 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14306 _codec ("Sorensen video v.3");
14307 caps = gst_caps_new_simple ("video/x-svq",
14308 "svqversion", G_TYPE_INT, 3, NULL);
14310 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14311 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14312 _codec ("Sorensen video v.1");
14313 caps = gst_caps_new_simple ("video/x-svq",
14314 "svqversion", G_TYPE_INT, 1, NULL);
14316 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14317 caps = gst_caps_new_empty_simple ("video/x-raw");
14318 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14319 _codec ("Windows Raw RGB");
14320 stream->alignment = 32;
14326 bps = QT_UINT16 (stsd_entry_data + 82);
14329 format = GST_VIDEO_FORMAT_RGB15;
14332 format = GST_VIDEO_FORMAT_RGB16;
14335 format = GST_VIDEO_FORMAT_RGB;
14338 format = GST_VIDEO_FORMAT_ARGB;
14346 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14347 format = GST_VIDEO_FORMAT_I420;
14349 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14350 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14351 format = GST_VIDEO_FORMAT_I420;
14354 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14355 format = GST_VIDEO_FORMAT_UYVY;
14357 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14358 format = GST_VIDEO_FORMAT_v308;
14360 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14361 format = GST_VIDEO_FORMAT_v216;
14364 format = GST_VIDEO_FORMAT_v210;
14366 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14367 format = GST_VIDEO_FORMAT_r210;
14369 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14370 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14371 format = GST_VIDEO_FORMAT_v410;
14374 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14375 * but different order than AYUV
14376 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14377 format = GST_VIDEO_FORMAT_v408;
14380 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14381 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14382 _codec ("MPEG-1 video");
14383 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14384 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14386 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14387 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14388 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14389 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14390 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14391 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14392 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14393 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14394 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14395 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14396 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14397 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14398 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14399 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14400 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14401 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14402 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14403 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14404 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14405 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14406 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14407 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14408 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14409 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14410 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14411 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14412 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14413 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14414 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14415 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14416 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14417 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14418 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14419 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14420 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14421 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14422 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14423 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14424 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14425 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14426 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14427 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14428 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14429 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14430 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14431 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14432 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14433 _codec ("MPEG-2 video");
14434 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14435 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14437 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14438 _codec ("GIF still images");
14439 caps = gst_caps_new_empty_simple ("image/gif");
14442 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14444 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14446 /* ffmpeg uses the height/width props, don't know why */
14447 caps = gst_caps_new_simple ("video/x-h263",
14448 "variant", G_TYPE_STRING, "itu", NULL);
14452 _codec ("MPEG-4 video");
14453 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14454 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14456 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14457 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14458 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14459 caps = gst_caps_new_simple ("video/x-msmpeg",
14460 "msmpegversion", G_TYPE_INT, 43, NULL);
14462 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14464 caps = gst_caps_new_simple ("video/x-divx",
14465 "divxversion", G_TYPE_INT, 3, NULL);
14467 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14468 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14470 caps = gst_caps_new_simple ("video/x-divx",
14471 "divxversion", G_TYPE_INT, 4, NULL);
14473 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14475 caps = gst_caps_new_simple ("video/x-divx",
14476 "divxversion", G_TYPE_INT, 5, NULL);
14479 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14481 caps = gst_caps_new_simple ("video/x-ffv",
14482 "ffvversion", G_TYPE_INT, 1, NULL);
14485 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14486 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14491 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14492 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14493 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14497 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14498 _codec ("Cinepak");
14499 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14501 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14502 _codec ("Apple QuickDraw");
14503 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14505 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14506 _codec ("Apple video");
14507 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14511 _codec ("H.264 / AVC");
14512 caps = gst_caps_new_simple ("video/x-h264",
14513 "stream-format", G_TYPE_STRING, "avc",
14514 "alignment", G_TYPE_STRING, "au", NULL);
14517 _codec ("H.264 / AVC");
14518 caps = gst_caps_new_simple ("video/x-h264",
14519 "stream-format", G_TYPE_STRING, "avc3",
14520 "alignment", G_TYPE_STRING, "au", NULL);
14524 _codec ("H.265 / HEVC");
14525 caps = gst_caps_new_simple ("video/x-h265",
14526 "stream-format", G_TYPE_STRING, "hvc1",
14527 "alignment", G_TYPE_STRING, "au", NULL);
14530 _codec ("H.265 / HEVC");
14531 caps = gst_caps_new_simple ("video/x-h265",
14532 "stream-format", G_TYPE_STRING, "hev1",
14533 "alignment", G_TYPE_STRING, "au", NULL);
14536 _codec ("Run-length encoding");
14537 caps = gst_caps_new_simple ("video/x-rle",
14538 "layout", G_TYPE_STRING, "quicktime", NULL);
14541 _codec ("Run-length encoding");
14542 caps = gst_caps_new_simple ("video/x-rle",
14543 "layout", G_TYPE_STRING, "microsoft", NULL);
14545 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14546 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14547 _codec ("Indeo Video 3");
14548 caps = gst_caps_new_simple ("video/x-indeo",
14549 "indeoversion", G_TYPE_INT, 3, NULL);
14551 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14552 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14553 _codec ("Intel Video 4");
14554 caps = gst_caps_new_simple ("video/x-indeo",
14555 "indeoversion", G_TYPE_INT, 4, NULL);
14559 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14560 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14561 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14562 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14563 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14564 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14565 _codec ("DV Video");
14566 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14567 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14569 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14570 case FOURCC_dv5p: /* DVCPRO50 PAL */
14571 _codec ("DVCPro50 Video");
14572 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14573 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14575 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14576 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14577 _codec ("DVCProHD Video");
14578 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14579 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14581 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14582 _codec ("Apple Graphics (SMC)");
14583 caps = gst_caps_new_empty_simple ("video/x-smc");
14585 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14587 caps = gst_caps_new_empty_simple ("video/x-vp3");
14589 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14590 _codec ("VP6 Flash");
14591 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14595 caps = gst_caps_new_empty_simple ("video/x-theora");
14596 /* theora uses one byte of padding in the data stream because it does not
14597 * allow 0 sized packets while theora does */
14598 entry->padding = 1;
14602 caps = gst_caps_new_empty_simple ("video/x-dirac");
14604 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14605 _codec ("TIFF still images");
14606 caps = gst_caps_new_empty_simple ("image/tiff");
14608 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14609 _codec ("Apple Intermediate Codec");
14610 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14612 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14613 _codec ("AVID DNxHD");
14614 caps = gst_caps_from_string ("video/x-dnxhd");
14618 _codec ("On2 VP8");
14619 caps = gst_caps_from_string ("video/x-vp8");
14622 _codec ("Google VP9");
14623 caps = gst_caps_from_string ("video/x-vp9");
14626 _codec ("Apple ProRes LT");
14628 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14632 _codec ("Apple ProRes HQ");
14634 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14638 _codec ("Apple ProRes");
14640 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14644 _codec ("Apple ProRes Proxy");
14646 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14650 _codec ("Apple ProRes 4444");
14652 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14656 _codec ("Apple ProRes 4444 XQ");
14658 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14662 _codec ("GoPro CineForm");
14663 caps = gst_caps_from_string ("video/x-cineform");
14668 caps = gst_caps_new_simple ("video/x-wmv",
14669 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14671 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14674 caps = _get_unknown_codec_name ("video", fourcc);
14679 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14682 gst_video_info_init (&info);
14683 gst_video_info_set_format (&info, format, entry->width, entry->height);
14685 caps = gst_video_info_to_caps (&info);
14686 *codec_name = gst_pb_utils_get_codec_description (caps);
14688 /* enable clipping for raw video streams */
14689 stream->need_clip = TRUE;
14690 stream->alignment = 32;
14697 round_up_pow2 (guint n)
14709 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14710 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14711 int len, gchar ** codec_name)
14714 const GstStructure *s;
14717 GstAudioFormat format = 0;
14720 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14722 depth = entry->bytes_per_packet * 8;
14725 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14727 /* 8-bit audio is unsigned */
14729 format = GST_AUDIO_FORMAT_U8;
14730 /* otherwise it's signed and big-endian just like 'twos' */
14732 endian = G_BIG_ENDIAN;
14739 endian = G_LITTLE_ENDIAN;
14742 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14744 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14748 caps = gst_caps_new_simple ("audio/x-raw",
14749 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14750 "layout", G_TYPE_STRING, "interleaved", NULL);
14751 stream->alignment = GST_ROUND_UP_8 (depth);
14752 stream->alignment = round_up_pow2 (stream->alignment);
14755 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14756 _codec ("Raw 64-bit floating-point audio");
14757 caps = gst_caps_new_simple ("audio/x-raw",
14758 "format", G_TYPE_STRING, "F64BE",
14759 "layout", G_TYPE_STRING, "interleaved", NULL);
14760 stream->alignment = 8;
14762 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14763 _codec ("Raw 32-bit floating-point audio");
14764 caps = gst_caps_new_simple ("audio/x-raw",
14765 "format", G_TYPE_STRING, "F32BE",
14766 "layout", G_TYPE_STRING, "interleaved", NULL);
14767 stream->alignment = 4;
14770 _codec ("Raw 24-bit PCM audio");
14771 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14773 caps = gst_caps_new_simple ("audio/x-raw",
14774 "format", G_TYPE_STRING, "S24BE",
14775 "layout", G_TYPE_STRING, "interleaved", NULL);
14776 stream->alignment = 4;
14778 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14779 _codec ("Raw 32-bit PCM audio");
14780 caps = gst_caps_new_simple ("audio/x-raw",
14781 "format", G_TYPE_STRING, "S32BE",
14782 "layout", G_TYPE_STRING, "interleaved", NULL);
14783 stream->alignment = 4;
14785 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14786 _codec ("Raw 16-bit PCM audio");
14787 caps = gst_caps_new_simple ("audio/x-raw",
14788 "format", G_TYPE_STRING, "S16LE",
14789 "layout", G_TYPE_STRING, "interleaved", NULL);
14790 stream->alignment = 2;
14793 _codec ("Mu-law audio");
14794 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14797 _codec ("A-law audio");
14798 caps = gst_caps_new_empty_simple ("audio/x-alaw");
14802 _codec ("Microsoft ADPCM");
14803 /* Microsoft ADPCM-ACM code 2 */
14804 caps = gst_caps_new_simple ("audio/x-adpcm",
14805 "layout", G_TYPE_STRING, "microsoft", NULL);
14809 _codec ("DVI/IMA ADPCM");
14810 caps = gst_caps_new_simple ("audio/x-adpcm",
14811 "layout", G_TYPE_STRING, "dvi", NULL);
14815 _codec ("DVI/Intel IMA ADPCM");
14816 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14817 caps = gst_caps_new_simple ("audio/x-adpcm",
14818 "layout", G_TYPE_STRING, "quicktime", NULL);
14822 /* MPEG layer 3, CBR only (pre QT4.1) */
14824 _codec ("MPEG-1 layer 3");
14825 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14826 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14827 "mpegversion", G_TYPE_INT, 1, NULL);
14829 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14830 _codec ("MPEG-1 layer 2");
14832 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14833 "mpegversion", G_TYPE_INT, 1, NULL);
14836 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14837 _codec ("EAC-3 audio");
14838 caps = gst_caps_new_simple ("audio/x-eac3",
14839 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14840 entry->sampled = TRUE;
14842 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14844 _codec ("AC-3 audio");
14845 caps = gst_caps_new_simple ("audio/x-ac3",
14846 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14847 entry->sampled = TRUE;
14849 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14850 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14851 _codec ("DTS audio");
14852 caps = gst_caps_new_simple ("audio/x-dts",
14853 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14854 entry->sampled = TRUE;
14856 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14857 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14858 _codec ("DTS-HD audio");
14859 caps = gst_caps_new_simple ("audio/x-dts",
14860 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14861 entry->sampled = TRUE;
14865 caps = gst_caps_new_simple ("audio/x-mace",
14866 "maceversion", G_TYPE_INT, 3, NULL);
14870 caps = gst_caps_new_simple ("audio/x-mace",
14871 "maceversion", G_TYPE_INT, 6, NULL);
14873 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14875 caps = gst_caps_new_empty_simple ("application/ogg");
14877 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14878 _codec ("DV audio");
14879 caps = gst_caps_new_empty_simple ("audio/x-dv");
14882 _codec ("MPEG-4 AAC audio");
14883 caps = gst_caps_new_simple ("audio/mpeg",
14884 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14885 "stream-format", G_TYPE_STRING, "raw", NULL);
14887 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14888 _codec ("QDesign Music");
14889 caps = gst_caps_new_empty_simple ("audio/x-qdm");
14892 _codec ("QDesign Music v.2");
14893 /* FIXME: QDesign music version 2 (no constant) */
14894 if (FALSE && data) {
14895 caps = gst_caps_new_simple ("audio/x-qdm2",
14896 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14897 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14898 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14900 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14904 _codec ("GSM audio");
14905 caps = gst_caps_new_empty_simple ("audio/x-gsm");
14908 _codec ("AMR audio");
14909 caps = gst_caps_new_empty_simple ("audio/AMR");
14912 _codec ("AMR-WB audio");
14913 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14916 _codec ("Quicktime IMA ADPCM");
14917 caps = gst_caps_new_simple ("audio/x-adpcm",
14918 "layout", G_TYPE_STRING, "quicktime", NULL);
14921 _codec ("Apple lossless audio");
14922 caps = gst_caps_new_empty_simple ("audio/x-alac");
14925 _codec ("Free Lossless Audio Codec");
14926 caps = gst_caps_new_simple ("audio/x-flac",
14927 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14929 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14930 _codec ("QualComm PureVoice");
14931 caps = gst_caps_from_string ("audio/qcelp");
14936 caps = gst_caps_new_empty_simple ("audio/x-wma");
14940 caps = gst_caps_new_empty_simple ("audio/x-opus");
14947 GstAudioFormat format;
14950 FLAG_IS_FLOAT = 0x1,
14951 FLAG_IS_BIG_ENDIAN = 0x2,
14952 FLAG_IS_SIGNED = 0x4,
14953 FLAG_IS_PACKED = 0x8,
14954 FLAG_IS_ALIGNED_HIGH = 0x10,
14955 FLAG_IS_NON_INTERLEAVED = 0x20
14957 _codec ("Raw LPCM audio");
14959 if (data && len >= 36) {
14960 depth = QT_UINT32 (data + 24);
14961 flags = QT_UINT32 (data + 28);
14962 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
14964 if ((flags & FLAG_IS_FLOAT) == 0) {
14969 if ((flags & FLAG_IS_ALIGNED_HIGH))
14972 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14973 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14974 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14975 caps = gst_caps_new_simple ("audio/x-raw",
14976 "format", G_TYPE_STRING,
14978 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
14979 "UNKNOWN", "layout", G_TYPE_STRING,
14980 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
14981 "interleaved", NULL);
14982 stream->alignment = GST_ROUND_UP_8 (depth);
14983 stream->alignment = round_up_pow2 (stream->alignment);
14988 if (flags & FLAG_IS_BIG_ENDIAN)
14989 format = GST_AUDIO_FORMAT_F64BE;
14991 format = GST_AUDIO_FORMAT_F64LE;
14993 if (flags & FLAG_IS_BIG_ENDIAN)
14994 format = GST_AUDIO_FORMAT_F32BE;
14996 format = GST_AUDIO_FORMAT_F32LE;
14998 caps = gst_caps_new_simple ("audio/x-raw",
14999 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15000 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15001 "non-interleaved" : "interleaved", NULL);
15002 stream->alignment = width / 8;
15006 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15010 caps = _get_unknown_codec_name ("audio", fourcc);
15016 GstCaps *templ_caps =
15017 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15018 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15019 gst_caps_unref (caps);
15020 gst_caps_unref (templ_caps);
15021 caps = intersection;
15024 /* enable clipping for raw audio streams */
15025 s = gst_caps_get_structure (caps, 0);
15026 name = gst_structure_get_name (s);
15027 if (g_str_has_prefix (name, "audio/x-raw")) {
15028 stream->need_clip = TRUE;
15029 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15030 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15036 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15037 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15038 const guint8 * stsd_entry_data, gchar ** codec_name)
15042 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15046 _codec ("DVD subtitle");
15047 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15048 stream->need_process = TRUE;
15051 _codec ("Quicktime timed text");
15054 _codec ("3GPP timed text");
15056 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15058 /* actual text piece needs to be extracted */
15059 stream->need_process = TRUE;
15062 _codec ("XML subtitles");
15063 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15066 _codec ("CEA 608 Closed Caption");
15068 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15069 G_TYPE_STRING, "cc_data", NULL);
15070 stream->need_process = TRUE;
15073 _codec ("CEA 708 Closed Caption");
15075 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15076 G_TYPE_STRING, "cdp", NULL);
15077 stream->need_process = TRUE;
15082 caps = _get_unknown_codec_name ("text", fourcc);
15090 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15091 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15092 const guint8 * stsd_entry_data, gchar ** codec_name)
15098 _codec ("MPEG 1 video");
15099 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15100 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15110 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15111 const gchar * system_id)
15115 if (!qtdemux->protection_system_ids)
15116 qtdemux->protection_system_ids =
15117 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15118 /* Check whether we already have an entry for this system ID. */
15119 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15120 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15121 if (g_ascii_strcasecmp (system_id, id) == 0) {
15125 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15126 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,