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_STREAM(s) ((QtDemuxStream *)(s))
101 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
102 #define QTDEMUX_NTH_STREAM(demux,idx) \
103 QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
104 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
105 QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
107 GST_DEBUG_CATEGORY (qtdemux_debug);
108 #define GST_CAT_DEFAULT qtdemux_debug
110 typedef struct _QtDemuxSegment QtDemuxSegment;
111 typedef struct _QtDemuxSample QtDemuxSample;
113 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
115 struct _QtDemuxSample
118 gint32 pts_offset; /* Add this value to timestamp to get the pts */
120 guint64 timestamp; /* DTS In mov time */
121 guint32 duration; /* In mov time */
122 gboolean keyframe; /* TRUE when this packet is a keyframe */
125 /* Macros for converting to/from timescale */
126 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
127 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
129 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
130 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
132 /* timestamp is the DTS */
133 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
134 /* timestamp + offset + cslg_shift is the outgoing PTS */
135 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
136 /* timestamp + offset is the PTS used for internal seek calcuations */
137 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
138 /* timestamp + duration - dts is the duration */
139 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
141 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
143 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
144 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
145 GST_TRACE("Locking from thread %p", g_thread_self()); \
146 g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
147 GST_TRACE("Locked from thread %p", g_thread_self()); \
150 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
151 GST_TRACE("Unlocking from thread %p", g_thread_self()); \
152 g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
156 * Quicktime has tracks and segments. A track is a continuous piece of
157 * multimedia content. The track is not always played from start to finish but
158 * instead, pieces of the track are 'cut out' and played in sequence. This is
159 * what the segments do.
161 * Inside the track we have keyframes (K) and delta frames. The track has its
162 * own timing, which starts from 0 and extends to end. The position in the track
163 * is called the media_time.
165 * The segments now describe the pieces that should be played from this track
166 * and are basically tuples of media_time/duration/rate entries. We can have
167 * multiple segments and they are all played after one another. An example:
169 * segment 1: media_time: 1 second, duration: 1 second, rate 1
170 * segment 2: media_time: 3 second, duration: 2 second, rate 2
172 * To correctly play back this track, one must play: 1 second of media starting
173 * from media_time 1 followed by 2 seconds of media starting from media_time 3
176 * Each of the segments will be played at a specific time, the first segment at
177 * time 0, the second one after the duration of the first one, etc.. Note that
178 * the time in resulting playback is not identical to the media_time of the
181 * Visually, assuming the track has 4 second of media_time:
184 * .-----------------------------------------------------------.
185 * track: | K.....K.........K........K.......K.......K...........K... |
186 * '-----------------------------------------------------------'
188 * .------------^ ^ .----------^ ^
189 * / .-------------' / .------------------'
191 * .--------------. .--------------.
192 * | segment 1 | | segment 2 |
193 * '--------------' '--------------'
195 * The challenge here is to cut out the right pieces of the track for each of
196 * the playback segments. This fortunately can easily be done with the SEGMENT
197 * events of GStreamer.
199 * For playback of segment 1, we need to provide the decoder with the keyframe
200 * (a), in the above figure, but we must instruct it only to output the decoded
201 * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
202 * position set to the time of the segment: 0.
204 * We then proceed to push data from keyframe (a) to frame (b). The decoder
205 * decodes but clips all before media_time 1.
207 * After finishing a segment, we push out a new SEGMENT event with the clipping
208 * boundaries of the new data.
210 * This is a good usecase for the GStreamer accumulated SEGMENT events.
213 struct _QtDemuxSegment
215 /* global time and duration, all gst time */
217 GstClockTime stop_time;
218 GstClockTime duration;
219 /* media time of trak, all gst time */
220 GstClockTime media_start;
221 GstClockTime media_stop;
223 /* Media start time in trak timescale units */
224 guint32 trak_media_start;
227 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
229 /* Used with fragmented MP4 files (mfra atom) */
234 } QtDemuxRandomAccessEntry;
236 typedef struct _QtDemuxStreamStsdEntry
247 /* Numerator/denominator framerate */
250 GstVideoColorimetry colorimetry;
251 guint16 bits_per_sample;
252 guint16 color_table_id;
253 GstMemory *rgb8_palette;
254 guint interlace_mode;
260 guint samples_per_packet;
261 guint samples_per_frame;
262 guint bytes_per_packet;
263 guint bytes_per_sample;
264 guint bytes_per_frame;
267 /* if we use chunks or samples */
271 } QtDemuxStreamStsdEntry;
273 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
275 struct _QtDemuxStream
282 QtDemuxStreamStsdEntry *stsd_entries;
283 guint stsd_entries_length;
284 guint cur_stsd_entry_index;
289 gboolean new_caps; /* If TRUE, caps need to be generated (by
290 * calling _configure_stream()) This happens
291 * for MSS and fragmented streams */
293 gboolean new_stream; /* signals that a stream_start is required */
294 gboolean on_keyframe; /* if this stream last pushed buffer was a
295 * keyframe. This is important to identify
296 * where to stop pushing buffers after a
297 * segment stop time */
299 /* if the stream has a redirect URI in its headers, we store it here */
306 guint64 duration; /* in timescale units */
310 gchar lang_id[4]; /* ISO 639-2T language code */
314 QtDemuxSample *samples;
315 gboolean all_keyframe; /* TRUE when all samples are keyframes (no stss) */
316 guint32 n_samples_moof; /* sample count in a moof */
317 guint64 duration_moof; /* duration in timescale of a moof, used for figure out
318 * the framerate of fragmented format stream */
319 guint64 duration_last_moof;
321 guint32 offset_in_sample; /* Offset in the current sample, used for
322 * streams which have got exceedingly big
323 * sample size (such as 24s of raw audio).
324 * Only used when max_buffer_size is non-NULL */
325 guint32 max_buffer_size; /* Maximum allowed size for output buffers.
326 * Currently only set for raw audio streams*/
334 gboolean use_allocator;
335 GstAllocator *allocator;
336 GstAllocationParams params;
340 /* when a discontinuity is pending */
343 /* list of buffers to push first */
346 /* if we need to clip this buffer. This is only needed for uncompressed
350 /* buffer needs some custom processing, e.g. subtitles */
351 gboolean need_process;
353 /* current position */
354 guint32 segment_index;
355 guint32 sample_index;
356 GstClockTime time_position; /* in gst time */
357 guint64 accumulated_base;
359 /* the Gst segment we are processing out, used for clipping */
362 /* quicktime segments */
364 QtDemuxSegment *segments;
365 gboolean dummy_segment;
370 GstTagList *stream_tags;
371 gboolean send_global_tags;
373 GstEvent *pending_event;
383 gboolean chunks_are_samples; /* TRUE means treat chunks as samples */
387 GstByteReader co_chunk;
389 guint32 current_chunk;
391 guint32 samples_per_chunk;
392 guint32 stsd_sample_description_id;
393 guint32 stco_sample_index;
395 guint32 sample_size; /* 0 means variable sizes are stored in stsz */
398 guint32 n_samples_per_chunk;
399 guint32 stsc_chunk_index;
400 guint32 stsc_sample_index;
401 guint64 chunk_offset;
404 guint32 stts_samples;
405 guint32 n_sample_times;
406 guint32 stts_sample_index;
408 guint32 stts_duration;
410 gboolean stss_present;
411 guint32 n_sample_syncs;
414 gboolean stps_present;
415 guint32 n_sample_partial_syncs;
417 QtDemuxRandomAccessEntry *ra_entries;
420 const QtDemuxRandomAccessEntry *pending_seek;
423 gboolean ctts_present;
424 guint32 n_composition_times;
426 guint32 ctts_sample_index;
434 gboolean parsed_trex;
435 guint32 def_sample_description_index; /* index is 1-based */
436 guint32 def_sample_duration;
437 guint32 def_sample_size;
438 guint32 def_sample_flags;
442 /* stereoscopic video streams */
443 GstVideoMultiviewMode multiview_mode;
444 GstVideoMultiviewFlags multiview_flags;
446 /* protected streams */
448 guint32 protection_scheme_type;
449 guint32 protection_scheme_version;
450 gpointer protection_scheme_info; /* specific to the protection scheme */
451 GQueue protection_scheme_event_queue;
453 gint ref_count; /* atomic */
456 /* Contains properties and cryptographic info for a set of samples from a
457 * track protected using Common Encryption (cenc) */
458 struct _QtDemuxCencSampleSetInfo
460 GstStructure *default_properties;
462 /* @crypto_info holds one GstStructure per sample */
463 GPtrArray *crypto_info;
467 qt_demux_state_string (enum QtDemuxState state)
470 case QTDEMUX_STATE_INITIAL:
472 case QTDEMUX_STATE_HEADER:
474 case QTDEMUX_STATE_MOVIE:
476 case QTDEMUX_STATE_BUFFER_MDAT:
477 return "<BUFFER_MDAT>";
483 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
484 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
485 guint32 fourcc, GstByteReader * parser);
486 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
487 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
488 guint32 fourcc, GstByteReader * parser);
490 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
492 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
494 static GstStaticPadTemplate gst_qtdemux_sink_template =
495 GST_STATIC_PAD_TEMPLATE ("sink",
498 GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
502 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
503 GST_STATIC_PAD_TEMPLATE ("video_%u",
506 GST_STATIC_CAPS_ANY);
508 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
509 GST_STATIC_PAD_TEMPLATE ("audio_%u",
512 GST_STATIC_CAPS_ANY);
514 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
515 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
518 GST_STATIC_CAPS_ANY);
520 #define gst_qtdemux_parent_class parent_class
521 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
523 static void gst_qtdemux_dispose (GObject * object);
526 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
527 GstClockTime media_time);
529 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
530 QtDemuxStream * str, gint64 media_offset);
533 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
534 static GstIndex *gst_qtdemux_get_index (GstElement * element);
536 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
537 GstStateChange transition);
538 static void gst_qtdemux_set_context (GstElement * element,
539 GstContext * context);
540 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
541 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
542 GstObject * parent, GstPadMode mode, gboolean active);
544 static void gst_qtdemux_loop (GstPad * pad);
545 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
547 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
549 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
551 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
552 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
553 QtDemuxStream * stream);
554 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
555 QtDemuxStream * stream);
556 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
559 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
561 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
562 const guint8 * buffer, guint length);
563 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
564 const guint8 * buffer, guint length);
565 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
566 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
569 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
570 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
572 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
573 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
574 const guint8 * stsd_entry_data, gchar ** codec_name);
575 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
576 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
577 const guint8 * data, int len, gchar ** codec_name);
578 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
579 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
580 gchar ** codec_name);
581 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
582 QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
583 const guint8 * stsd_entry_data, gchar ** codec_name);
585 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
586 QtDemuxStream * stream, guint32 n);
587 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
588 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
589 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
590 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
591 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
592 static void qtdemux_do_allocation (QtDemuxStream * stream,
593 GstQTDemux * qtdemux);
594 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
595 QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
596 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
597 QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
598 GstClockTime * _start, GstClockTime * _stop);
599 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
600 QtDemuxStream * stream, gint segment_index, GstClockTime pos);
602 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
603 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
605 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
607 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
608 QtDemuxStream * stream, guint sample_index);
609 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
611 static void qtdemux_gst_structure_free (GstStructure * gststructure);
612 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
615 gst_qtdemux_class_init (GstQTDemuxClass * klass)
617 GObjectClass *gobject_class;
618 GstElementClass *gstelement_class;
620 gobject_class = (GObjectClass *) klass;
621 gstelement_class = (GstElementClass *) klass;
623 parent_class = g_type_class_peek_parent (klass);
625 gobject_class->dispose = gst_qtdemux_dispose;
627 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
629 gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
630 gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
632 gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
634 gst_tag_register_musicbrainz_tags ();
636 gst_element_class_add_static_pad_template (gstelement_class,
637 &gst_qtdemux_sink_template);
638 gst_element_class_add_static_pad_template (gstelement_class,
639 &gst_qtdemux_videosrc_template);
640 gst_element_class_add_static_pad_template (gstelement_class,
641 &gst_qtdemux_audiosrc_template);
642 gst_element_class_add_static_pad_template (gstelement_class,
643 &gst_qtdemux_subsrc_template);
644 gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
646 "Demultiplex a QuickTime file into audio and video streams",
647 "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
649 GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
654 gst_qtdemux_init (GstQTDemux * qtdemux)
657 gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
658 gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
659 gst_pad_set_activatemode_function (qtdemux->sinkpad,
660 qtdemux_sink_activate_mode);
661 gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
662 gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
663 gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
664 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
666 qtdemux->adapter = gst_adapter_new ();
667 g_queue_init (&qtdemux->protection_event_queue);
668 qtdemux->flowcombiner = gst_flow_combiner_new ();
669 g_mutex_init (&qtdemux->expose_lock);
671 qtdemux->active_streams = g_ptr_array_new_with_free_func
672 ((GDestroyNotify) gst_qtdemux_stream_unref);
673 qtdemux->old_streams = g_ptr_array_new_with_free_func
674 ((GDestroyNotify) gst_qtdemux_stream_unref);
676 GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
678 gst_qtdemux_reset (qtdemux, TRUE);
682 gst_qtdemux_dispose (GObject * object)
684 GstQTDemux *qtdemux = GST_QTDEMUX (object);
686 if (qtdemux->adapter) {
687 g_object_unref (G_OBJECT (qtdemux->adapter));
688 qtdemux->adapter = NULL;
690 gst_tag_list_unref (qtdemux->tag_list);
691 gst_flow_combiner_free (qtdemux->flowcombiner);
692 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
694 g_queue_clear (&qtdemux->protection_event_queue);
696 g_free (qtdemux->cenc_aux_info_sizes);
697 qtdemux->cenc_aux_info_sizes = NULL;
698 g_mutex_clear (&qtdemux->expose_lock);
700 g_ptr_array_free (qtdemux->active_streams, TRUE);
701 g_ptr_array_free (qtdemux->old_streams, TRUE);
703 G_OBJECT_CLASS (parent_class)->dispose (object);
707 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
709 if (qtdemux->posted_redirect) {
710 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
711 (_("This file contains no playable streams.")),
712 ("no known streams found, a redirect message has been posted"));
714 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
715 (_("This file contains no playable streams.")),
716 ("no known streams found"));
721 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
723 return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
724 mem, size, 0, size, mem, free_func);
728 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
735 if (G_UNLIKELY (size == 0)) {
737 GstBuffer *tmp = NULL;
739 ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
740 if (ret != GST_FLOW_OK)
743 gst_buffer_map (tmp, &map, GST_MAP_READ);
744 size = QT_UINT32 (map.data);
745 GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
747 gst_buffer_unmap (tmp, &map);
748 gst_buffer_unref (tmp);
751 /* Sanity check: catch bogus sizes (fuzzed/broken files) */
752 if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
753 if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
754 /* we're pulling header but already got most interesting bits,
755 * so never mind the rest (e.g. tags) (that much) */
756 GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
760 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
761 (_("This file is invalid and cannot be played.")),
762 ("atom has bogus size %" G_GUINT64_FORMAT, size));
763 return GST_FLOW_ERROR;
767 flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
769 if (G_UNLIKELY (flow != GST_FLOW_OK))
772 bsize = gst_buffer_get_size (*buf);
773 /* Catch short reads - we don't want any partial atoms */
774 if (G_UNLIKELY (bsize < size)) {
775 GST_WARNING_OBJECT (qtdemux,
776 "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
777 gst_buffer_unref (*buf);
787 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
788 GstFormat src_format, gint64 src_value, GstFormat dest_format,
792 QtDemuxStream *stream = gst_pad_get_element_private (pad);
795 if (stream->subtype != FOURCC_vide) {
800 switch (src_format) {
801 case GST_FORMAT_TIME:
802 switch (dest_format) {
803 case GST_FORMAT_BYTES:{
804 index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
810 *dest_value = stream->samples[index].offset;
812 GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
813 GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
814 GST_TIME_ARGS (src_value), *dest_value);
822 case GST_FORMAT_BYTES:
823 switch (dest_format) {
824 case GST_FORMAT_TIME:{
826 gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
835 QTSTREAMTIME_TO_GSTTIME (stream,
836 stream->samples[index].timestamp);
837 GST_DEBUG_OBJECT (qtdemux,
838 "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
839 GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
858 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
860 gboolean res = FALSE;
862 *duration = GST_CLOCK_TIME_NONE;
864 if (qtdemux->duration != 0 &&
865 qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
866 *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
869 *duration = GST_CLOCK_TIME_NONE;
876 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
879 gboolean res = FALSE;
880 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
882 GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
884 switch (GST_QUERY_TYPE (query)) {
885 case GST_QUERY_POSITION:{
888 gst_query_parse_position (query, &fmt, NULL);
889 if (fmt == GST_FORMAT_TIME
890 && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
891 gst_query_set_position (query, GST_FORMAT_TIME,
892 qtdemux->segment.position);
897 case GST_QUERY_DURATION:{
900 gst_query_parse_duration (query, &fmt, NULL);
901 if (fmt == GST_FORMAT_TIME) {
902 /* First try to query upstream */
903 res = gst_pad_query_default (pad, parent, query);
905 GstClockTime duration;
906 if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
907 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
914 case GST_QUERY_CONVERT:{
915 GstFormat src_fmt, dest_fmt;
916 gint64 src_value, dest_value = 0;
918 gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
920 res = gst_qtdemux_src_convert (qtdemux, pad,
921 src_fmt, src_value, dest_fmt, &dest_value);
923 gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
927 case GST_QUERY_FORMATS:
928 gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
931 case GST_QUERY_SEEKING:{
935 /* try upstream first */
936 res = gst_pad_query_default (pad, parent, query);
939 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
940 if (fmt == GST_FORMAT_TIME) {
941 GstClockTime duration;
943 gst_qtdemux_get_duration (qtdemux, &duration);
945 if (!qtdemux->pullbased) {
948 /* we might be able with help from upstream */
950 q = gst_query_new_seeking (GST_FORMAT_BYTES);
951 if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
952 gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
953 GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
957 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
963 case GST_QUERY_SEGMENT:
968 format = qtdemux->segment.format;
971 gst_segment_to_stream_time (&qtdemux->segment, format,
972 qtdemux->segment.start);
973 if ((stop = qtdemux->segment.stop) == -1)
974 stop = qtdemux->segment.duration;
976 stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
978 gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
983 res = gst_pad_query_default (pad, parent, query);
991 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
993 if (G_LIKELY (stream->pad)) {
994 GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
995 GST_DEBUG_PAD_NAME (stream->pad));
997 if (!gst_tag_list_is_empty (stream->stream_tags)) {
998 GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
999 stream->stream_tags);
1000 gst_pad_push_event (stream->pad,
1001 gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
1004 if (G_UNLIKELY (stream->send_global_tags)) {
1005 GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1007 gst_pad_push_event (stream->pad,
1008 gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1009 stream->send_global_tags = FALSE;
1014 /* push event on all source pads; takes ownership of the event */
1016 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1018 gboolean has_valid_stream = FALSE;
1019 GstEventType etype = GST_EVENT_TYPE (event);
1022 GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1023 GST_EVENT_TYPE_NAME (event));
1025 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1027 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1028 GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1030 if ((pad = stream->pad)) {
1031 has_valid_stream = TRUE;
1033 if (etype == GST_EVENT_EOS) {
1034 /* let's not send twice */
1035 if (stream->sent_eos)
1037 stream->sent_eos = TRUE;
1040 gst_pad_push_event (pad, gst_event_ref (event));
1044 gst_event_unref (event);
1046 /* if it is EOS and there are no pads, post an error */
1047 if (!has_valid_stream && etype == GST_EVENT_EOS) {
1048 gst_qtdemux_post_no_playable_stream_error (qtdemux);
1058 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1060 if ((gint64) s1->timestamp > *media_time)
1062 if ((gint64) s1->timestamp == *media_time)
1068 /* find the index of the sample that includes the data for @media_time using a
1069 * binary search. Only to be called in optimized cases of linear search below.
1071 * Returns the index of the sample with the corresponding *DTS*.
1074 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1077 QtDemuxSample *result;
1080 /* convert media_time to mov format */
1082 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1084 result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1085 sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1086 GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1088 if (G_LIKELY (result))
1089 index = result - str->samples;
1098 /* find the index of the sample that includes the data for @media_offset using a
1101 * Returns the index of the sample.
1104 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1105 QtDemuxStream * str, gint64 media_offset)
1107 QtDemuxSample *result = str->samples;
1110 if (result == NULL || str->n_samples == 0)
1113 if (media_offset == result->offset)
1117 while (index < str->n_samples - 1) {
1118 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1121 if (media_offset < result->offset)
1132 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1137 /* find the index of the sample that includes the data for @media_time using a
1138 * linear search, and keeping in mind that not all samples may have been parsed
1139 * yet. If possible, it will delegate to binary search.
1141 * Returns the index of the sample.
1144 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1145 GstClockTime media_time)
1149 QtDemuxSample *sample;
1151 /* convert media_time to mov format */
1153 gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1155 sample = str->samples;
1156 if (mov_time == sample->timestamp + sample->pts_offset)
1159 /* use faster search if requested time in already parsed range */
1160 sample = str->samples + str->stbl_index;
1161 if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1162 index = gst_qtdemux_find_index (qtdemux, str, media_time);
1163 sample = str->samples + index;
1165 while (index < str->n_samples - 1) {
1166 if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1169 sample = str->samples + index + 1;
1170 if (mov_time < sample->timestamp) {
1171 sample = str->samples + index;
1179 /* sample->timestamp is now <= media_time, need to find the corresponding
1180 * PTS now by looking backwards */
1181 while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1183 sample = str->samples + index;
1191 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1196 /* find the index of the keyframe needed to decode the sample at @index
1197 * of stream @str, or of a subsequent keyframe (depending on @next)
1199 * Returns the index of the keyframe.
1202 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1203 guint32 index, gboolean next)
1205 guint32 new_index = index;
1207 if (index >= str->n_samples) {
1208 new_index = str->n_samples;
1212 /* all keyframes, return index */
1213 if (str->all_keyframe) {
1218 /* else search until we have a keyframe */
1219 while (new_index < str->n_samples) {
1220 if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1223 if (str->samples[new_index].keyframe)
1235 if (new_index == str->n_samples) {
1236 GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1241 GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1242 "gave %u", next ? "after" : "before", index, new_index);
1249 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1254 /* find the segment for @time_position for @stream
1256 * Returns the index of the segment containing @time_position.
1257 * Returns the last segment and sets the @eos variable to TRUE
1258 * if the time is beyond the end. @eos may be NULL
1261 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1262 GstClockTime time_position)
1267 GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1268 GST_TIME_ARGS (time_position));
1271 for (i = 0; i < stream->n_segments; i++) {
1272 QtDemuxSegment *segment = &stream->segments[i];
1274 GST_LOG_OBJECT (stream->pad,
1275 "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1276 GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1278 /* For the last segment we include stop_time in the last segment */
1279 if (i < stream->n_segments - 1) {
1280 if (segment->time <= time_position && time_position < segment->stop_time) {
1281 GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1286 /* Last segment always matches */
1294 /* move the stream @str to the sample position @index.
1296 * Updates @str->sample_index and marks discontinuity if needed.
1299 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1302 /* no change needed */
1303 if (index == str->sample_index)
1306 GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1309 /* position changed, we have a discont */
1310 str->sample_index = index;
1311 str->offset_in_sample = 0;
1312 /* Each time we move in the stream we store the position where we are
1314 str->from_sample = index;
1315 str->discont = TRUE;
1319 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1320 gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1323 gint64 min_byte_offset = -1;
1326 min_offset = desired_time;
1328 /* for each stream, find the index of the sample in the segment
1329 * and move back to the previous keyframe. */
1330 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1332 guint32 index, kindex;
1334 GstClockTime media_start;
1335 GstClockTime media_time;
1336 GstClockTime seg_time;
1337 QtDemuxSegment *seg;
1338 gboolean empty_segment = FALSE;
1340 str = QTDEMUX_NTH_STREAM (qtdemux, i);
1342 if (CUR_STREAM (str)->sparse && !use_sparse)
1345 seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1346 GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1348 /* get segment and time in the segment */
1349 seg = &str->segments[seg_idx];
1350 seg_time = (desired_time - seg->time) * seg->rate;
1352 while (QTSEGMENT_IS_EMPTY (seg)) {
1354 empty_segment = TRUE;
1355 GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1358 if (seg_idx == str->n_segments)
1360 seg = &str->segments[seg_idx];
1363 if (seg_idx == str->n_segments) {
1364 /* FIXME track shouldn't have the last segment as empty, but if it
1365 * happens we better handle it */
1369 /* get the media time in the segment */
1370 media_start = seg->media_start + seg_time;
1372 /* get the index of the sample with media time */
1373 index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1374 GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1375 " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1376 GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1379 /* shift to next frame if we are looking for next keyframe */
1380 if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1381 && index < str->stbl_index)
1384 if (!empty_segment) {
1385 /* find previous keyframe */
1386 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1388 /* we will settle for one before if none found after */
1389 if (next && kindex == -1)
1390 kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1392 /* if the keyframe is at a different position, we need to update the
1393 * requested seek time */
1394 if (index != kindex) {
1397 /* get timestamp of keyframe */
1398 media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1399 GST_DEBUG_OBJECT (qtdemux,
1400 "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1401 G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1402 str->samples[kindex].offset);
1404 /* keyframes in the segment get a chance to change the
1405 * desired_offset. keyframes out of the segment are
1407 if (media_time >= seg->media_start) {
1408 GstClockTime seg_time;
1410 /* this keyframe is inside the segment, convert back to
1412 seg_time = (media_time - seg->media_start) + seg->time;
1413 if ((!next && (seg_time < min_offset)) ||
1414 (next && (seg_time > min_offset)))
1415 min_offset = seg_time;
1420 if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1421 min_byte_offset = str->samples[index].offset;
1425 *key_time = min_offset;
1427 *key_offset = min_byte_offset;
1431 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1432 GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1436 g_return_val_if_fail (format != NULL, FALSE);
1437 g_return_val_if_fail (cur != NULL, FALSE);
1438 g_return_val_if_fail (stop != NULL, FALSE);
1440 if (*format == GST_FORMAT_TIME)
1444 if (cur_type != GST_SEEK_TYPE_NONE)
1445 res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1446 if (res && stop_type != GST_SEEK_TYPE_NONE)
1447 res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1450 *format = GST_FORMAT_TIME;
1455 /* perform seek in push based mode:
1456 find BYTE position to move to based on time and delegate to upstream
1459 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1464 GstSeekType cur_type, stop_type;
1465 gint64 cur, stop, key_cur;
1468 gint64 original_stop;
1471 GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1473 gst_event_parse_seek (event, &rate, &format, &flags,
1474 &cur_type, &cur, &stop_type, &stop);
1475 seqnum = gst_event_get_seqnum (event);
1477 /* only forward streaming and seeking is possible */
1479 goto unsupported_seek;
1481 /* convert to TIME if needed and possible */
1482 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1486 /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1487 * the original stop position to use when upstream pushes the new segment
1489 original_stop = stop;
1492 /* find reasonable corresponding BYTE position,
1493 * also try to mind about keyframes, since we can not go back a bit for them
1495 /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1496 * mostly just work, but let's not yet boldly go there ... */
1497 gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1502 GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1503 "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1506 GST_OBJECT_LOCK (qtdemux);
1507 qtdemux->seek_offset = byte_cur;
1508 if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1509 qtdemux->push_seek_start = cur;
1511 qtdemux->push_seek_start = key_cur;
1514 if (stop_type == GST_SEEK_TYPE_NONE) {
1515 qtdemux->push_seek_stop = qtdemux->segment.stop;
1517 qtdemux->push_seek_stop = original_stop;
1519 GST_OBJECT_UNLOCK (qtdemux);
1521 qtdemux->segment_seqnum = seqnum;
1522 /* BYTE seek event */
1523 event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1525 gst_event_set_seqnum (event, seqnum);
1526 res = gst_pad_push_event (qtdemux->sinkpad, event);
1533 GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1539 GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1544 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1549 /* perform the seek.
1551 * We set all segment_indexes in the streams to unknown and
1552 * adjust the time_position to the desired position. this is enough
1553 * to trigger a segment switch in the streaming thread to start
1554 * streaming from the desired position.
1556 * Keyframe seeking is a little more complicated when dealing with
1557 * segments. Ideally we want to move to the previous keyframe in
1558 * the segment but there might not be a keyframe in the segment. In
1559 * fact, none of the segments could contain a keyframe. We take a
1560 * practical approach: seek to the previous keyframe in the segment,
1561 * if there is none, seek to the beginning of the segment.
1563 * Called with STREAM_LOCK
1566 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1567 guint32 seqnum, GstSeekFlags flags)
1569 gint64 desired_offset;
1572 desired_offset = segment->position;
1574 GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1575 GST_TIME_ARGS (desired_offset));
1577 /* may not have enough fragmented info to do this adjustment,
1578 * and we can't scan (and probably should not) at this time with
1579 * possibly flushing upstream */
1580 if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1582 gboolean next, before, after;
1584 before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1585 after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1586 next = after && !before;
1587 if (segment->rate < 0)
1590 gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1592 GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1593 GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1594 desired_offset = min_offset;
1597 /* and set all streams to the final position */
1598 gst_flow_combiner_reset (qtdemux->flowcombiner);
1599 qtdemux->segment_seqnum = seqnum;
1600 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1601 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1603 stream->time_position = desired_offset;
1604 stream->accumulated_base = 0;
1605 stream->sample_index = -1;
1606 stream->offset_in_sample = 0;
1607 stream->segment_index = -1;
1608 stream->sent_eos = FALSE;
1610 if (segment->flags & GST_SEEK_FLAG_FLUSH)
1611 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1613 segment->position = desired_offset;
1614 segment->time = desired_offset;
1615 if (segment->rate >= 0) {
1616 segment->start = desired_offset;
1618 /* we stop at the end */
1619 if (segment->stop == -1)
1620 segment->stop = segment->duration;
1622 segment->stop = desired_offset;
1625 if (qtdemux->fragmented)
1626 qtdemux->fragmented_seek_pending = TRUE;
1631 /* do a seek in pull based mode */
1633 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1638 GstSeekType cur_type, stop_type;
1642 GstSegment seeksegment;
1643 guint32 seqnum = GST_SEQNUM_INVALID;
1644 GstEvent *flush_event;
1648 GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1650 gst_event_parse_seek (event, &rate, &format, &flags,
1651 &cur_type, &cur, &stop_type, &stop);
1652 seqnum = gst_event_get_seqnum (event);
1654 /* we have to have a format as the segment format. Try to convert
1656 if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1660 GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1662 GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1666 flush = flags & GST_SEEK_FLAG_FLUSH;
1668 /* stop streaming, either by flushing or by pausing the task */
1670 flush_event = gst_event_new_flush_start ();
1671 if (seqnum != GST_SEQNUM_INVALID)
1672 gst_event_set_seqnum (flush_event, seqnum);
1673 /* unlock upstream pull_range */
1674 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1675 /* make sure out loop function exits */
1676 gst_qtdemux_push_event (qtdemux, flush_event);
1678 /* non flushing seek, pause the task */
1679 gst_pad_pause_task (qtdemux->sinkpad);
1682 /* wait for streaming to finish */
1683 GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1685 /* copy segment, we need this because we still need the old
1686 * segment when we close the current segment. */
1687 memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1690 /* configure the segment with the seek variables */
1691 GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1692 if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1693 cur_type, cur, stop_type, stop, &update)) {
1695 GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1697 /* now do the seek */
1698 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1701 /* now do the seek */
1702 ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1705 /* prepare for streaming again */
1707 flush_event = gst_event_new_flush_stop (TRUE);
1708 if (seqnum != GST_SEQNUM_INVALID)
1709 gst_event_set_seqnum (flush_event, seqnum);
1711 gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1712 gst_qtdemux_push_event (qtdemux, flush_event);
1715 /* commit the new segment */
1716 memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1718 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1719 GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1720 qtdemux->segment.format, qtdemux->segment.position);
1721 if (seqnum != GST_SEQNUM_INVALID)
1722 gst_message_set_seqnum (msg, seqnum);
1723 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1726 /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1727 gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1728 qtdemux->sinkpad, NULL);
1730 GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1737 GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1743 qtdemux_ensure_index (GstQTDemux * qtdemux)
1747 GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1749 /* Build complete index */
1750 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1751 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1753 if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1754 GST_LOG_OBJECT (qtdemux,
1755 "Building complete index of track-id %u for seeking failed!",
1765 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1768 gboolean res = TRUE;
1769 GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1771 switch (GST_EVENT_TYPE (event)) {
1772 case GST_EVENT_SEEK:
1774 #ifndef GST_DISABLE_GST_DEBUG
1775 GstClockTime ts = gst_util_get_timestamp ();
1777 guint32 seqnum = gst_event_get_seqnum (event);
1779 qtdemux->received_seek = TRUE;
1781 if (seqnum == qtdemux->segment_seqnum) {
1782 GST_LOG_OBJECT (pad,
1783 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1784 gst_event_unref (event);
1788 if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1789 /* seek should be handled by upstream, we might need to re-download fragments */
1790 GST_DEBUG_OBJECT (qtdemux,
1791 "let upstream handle seek for fragmented playback");
1795 /* Build complete index for seeking;
1796 * if not a fragmented file at least */
1797 if (!qtdemux->fragmented)
1798 if (!qtdemux_ensure_index (qtdemux))
1800 #ifndef GST_DISABLE_GST_DEBUG
1801 ts = gst_util_get_timestamp () - ts;
1802 GST_INFO_OBJECT (qtdemux,
1803 "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1806 if (qtdemux->pullbased) {
1807 res = gst_qtdemux_do_seek (qtdemux, pad, event);
1808 } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1809 GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1811 } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1812 && QTDEMUX_N_STREAMS (qtdemux)
1813 && !qtdemux->fragmented) {
1814 res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1816 GST_DEBUG_OBJECT (qtdemux,
1817 "ignoring seek in push mode in current state");
1820 gst_event_unref (event);
1824 res = gst_pad_event_default (pad, parent, event);
1834 GST_ERROR_OBJECT (qtdemux, "Index failed");
1835 gst_event_unref (event);
1841 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1843 * If @fw is false, the coding order is explored backwards.
1845 * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1846 * sample is found for that track.
1848 * The stream and sample index of the sample with the minimum offset in the direction explored
1849 * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1851 * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1852 * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1853 * @_stream and @_index. */
1855 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1856 gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1859 gint64 time, min_time;
1860 QtDemuxStream *stream;
1867 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1870 gboolean set_sample;
1872 str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1879 i = str->n_samples - 1;
1883 for (; (i >= 0) && (i < str->n_samples); i += inc) {
1884 if (str->samples[i].size == 0)
1887 if (fw && (str->samples[i].offset < byte_pos))
1890 if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1893 /* move stream to first available sample */
1895 gst_qtdemux_move_stream (qtdemux, str, i);
1899 /* avoid index from sparse streams since they might be far away */
1900 if (!CUR_STREAM (str)->sparse) {
1901 /* determine min/max time */
1902 time = QTSAMPLE_PTS (str, &str->samples[i]);
1903 if (min_time == -1 || (!fw && time > min_time) ||
1904 (fw && time < min_time)) {
1908 /* determine stream with leading sample, to get its position */
1910 (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1911 (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1919 /* no sample for this stream, mark eos */
1921 gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1932 /* Copied from mpegtsbase code */
1933 /* FIXME: replace this function when we add new util function for stream-id creation */
1935 _get_upstream_id (GstQTDemux * demux)
1937 gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1940 /* Try to create one from the upstream URI, else use a randome number */
1944 /* Try to generate one from the URI query and
1945 * if it fails take a random number instead */
1946 query = gst_query_new_uri ();
1947 if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1948 gst_query_parse_uri (query, &uri);
1954 /* And then generate an SHA256 sum of the URI */
1955 cs = g_checksum_new (G_CHECKSUM_SHA256);
1956 g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1958 upstream_id = g_strdup (g_checksum_get_string (cs));
1959 g_checksum_free (cs);
1961 /* Just get some random number if the URI query fails */
1962 GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1963 "implementing a deterministic way of creating a stream-id");
1965 g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1966 g_random_int (), g_random_int ());
1969 gst_query_unref (query);
1974 static QtDemuxStream *
1975 _create_stream (GstQTDemux * demux, guint32 track_id)
1977 QtDemuxStream *stream;
1980 stream = g_new0 (QtDemuxStream, 1);
1981 stream->demux = demux;
1982 stream->track_id = track_id;
1983 upstream_id = _get_upstream_id (demux);
1984 stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1985 g_free (upstream_id);
1986 /* new streams always need a discont */
1987 stream->discont = TRUE;
1988 /* we enable clipping for raw audio/video streams */
1989 stream->need_clip = FALSE;
1990 stream->need_process = FALSE;
1991 stream->segment_index = -1;
1992 stream->time_position = 0;
1993 stream->sample_index = -1;
1994 stream->offset_in_sample = 0;
1995 stream->new_stream = TRUE;
1996 stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1997 stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1998 stream->protected = FALSE;
1999 stream->protection_scheme_type = 0;
2000 stream->protection_scheme_version = 0;
2001 stream->protection_scheme_info = NULL;
2002 stream->n_samples_moof = 0;
2003 stream->duration_moof = 0;
2004 stream->duration_last_moof = 0;
2005 stream->alignment = 1;
2006 stream->stream_tags = gst_tag_list_new_empty ();
2007 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2008 g_queue_init (&stream->protection_scheme_event_queue);
2009 stream->ref_count = 1;
2010 /* consistent default for push based mode */
2011 gst_segment_init (&stream->segment, GST_FORMAT_TIME);
2016 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2018 GstStructure *structure;
2019 const gchar *variant;
2020 const GstCaps *mediacaps = NULL;
2022 GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2024 structure = gst_caps_get_structure (caps, 0);
2025 variant = gst_structure_get_string (structure, "variant");
2027 if (variant && strcmp (variant, "mss-fragmented") == 0) {
2028 QtDemuxStream *stream;
2029 const GValue *value;
2031 demux->fragmented = TRUE;
2032 demux->mss_mode = TRUE;
2034 if (QTDEMUX_N_STREAMS (demux) > 1) {
2035 /* can't do this, we can only renegotiate for another mss format */
2039 value = gst_structure_get_value (structure, "media-caps");
2042 const GValue *timescale_v;
2044 /* TODO update when stream changes during playback */
2046 if (QTDEMUX_N_STREAMS (demux) == 0) {
2047 stream = _create_stream (demux, 1);
2048 g_ptr_array_add (demux->active_streams, stream);
2049 /* mss has no stsd/stsd entry, use id 0 as default */
2050 stream->stsd_entries_length = 1;
2051 stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2052 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2054 stream = QTDEMUX_NTH_STREAM (demux, 0);
2057 timescale_v = gst_structure_get_value (structure, "timescale");
2059 stream->timescale = g_value_get_uint64 (timescale_v);
2061 /* default mss timescale */
2062 stream->timescale = 10000000;
2064 demux->timescale = stream->timescale;
2066 mediacaps = gst_value_get_caps (value);
2067 if (!CUR_STREAM (stream)->caps
2068 || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2069 GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2071 stream->new_caps = TRUE;
2073 gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2074 structure = gst_caps_get_structure (mediacaps, 0);
2075 if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2076 stream->subtype = FOURCC_vide;
2078 gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2079 gst_structure_get_int (structure, "height",
2080 &CUR_STREAM (stream)->height);
2081 gst_structure_get_fraction (structure, "framerate",
2082 &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2083 } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2085 stream->subtype = FOURCC_soun;
2086 gst_structure_get_int (structure, "channels",
2087 &CUR_STREAM (stream)->n_channels);
2088 gst_structure_get_int (structure, "rate", &rate);
2089 CUR_STREAM (stream)->rate = rate;
2092 gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2094 demux->mss_mode = FALSE;
2101 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2105 GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2106 gst_pad_stop_task (qtdemux->sinkpad);
2108 if (hard || qtdemux->upstream_format_is_time) {
2109 qtdemux->state = QTDEMUX_STATE_INITIAL;
2110 qtdemux->neededbytes = 16;
2111 qtdemux->todrop = 0;
2112 qtdemux->pullbased = FALSE;
2113 qtdemux->posted_redirect = FALSE;
2114 qtdemux->first_mdat = -1;
2115 qtdemux->header_size = 0;
2116 qtdemux->mdatoffset = -1;
2117 qtdemux->restoredata_offset = -1;
2118 if (qtdemux->mdatbuffer)
2119 gst_buffer_unref (qtdemux->mdatbuffer);
2120 if (qtdemux->restoredata_buffer)
2121 gst_buffer_unref (qtdemux->restoredata_buffer);
2122 qtdemux->mdatbuffer = NULL;
2123 qtdemux->restoredata_buffer = NULL;
2124 qtdemux->mdatleft = 0;
2125 qtdemux->mdatsize = 0;
2126 if (qtdemux->comp_brands)
2127 gst_buffer_unref (qtdemux->comp_brands);
2128 qtdemux->comp_brands = NULL;
2129 qtdemux->last_moov_offset = -1;
2130 if (qtdemux->moov_node_compressed) {
2131 g_node_destroy (qtdemux->moov_node_compressed);
2132 if (qtdemux->moov_node)
2133 g_free (qtdemux->moov_node->data);
2135 qtdemux->moov_node_compressed = NULL;
2136 if (qtdemux->moov_node)
2137 g_node_destroy (qtdemux->moov_node);
2138 qtdemux->moov_node = NULL;
2139 if (qtdemux->tag_list)
2140 gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2141 qtdemux->tag_list = gst_tag_list_new_empty ();
2142 gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2144 if (qtdemux->element_index)
2145 gst_object_unref (qtdemux->element_index);
2146 qtdemux->element_index = NULL;
2148 qtdemux->major_brand = 0;
2149 qtdemux->upstream_format_is_time = FALSE;
2150 qtdemux->upstream_seekable = FALSE;
2151 qtdemux->upstream_size = 0;
2153 qtdemux->fragment_start = -1;
2154 qtdemux->fragment_start_offset = -1;
2155 qtdemux->duration = 0;
2156 qtdemux->moof_offset = 0;
2157 qtdemux->chapters_track_id = 0;
2158 qtdemux->have_group_id = FALSE;
2159 qtdemux->group_id = G_MAXUINT;
2161 g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2163 g_queue_clear (&qtdemux->protection_event_queue);
2165 qtdemux->received_seek = FALSE;
2166 qtdemux->first_moof_already_parsed = FALSE;
2168 qtdemux->offset = 0;
2169 gst_adapter_clear (qtdemux->adapter);
2170 gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2171 qtdemux->need_segment = TRUE;
2174 qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2175 g_ptr_array_remove_range (qtdemux->active_streams,
2176 0, qtdemux->active_streams->len);
2177 g_ptr_array_remove_range (qtdemux->old_streams,
2178 0, qtdemux->old_streams->len);
2179 qtdemux->n_video_streams = 0;
2180 qtdemux->n_audio_streams = 0;
2181 qtdemux->n_sub_streams = 0;
2182 qtdemux->exposed = FALSE;
2183 qtdemux->fragmented = FALSE;
2184 qtdemux->mss_mode = FALSE;
2185 gst_caps_replace (&qtdemux->media_caps, NULL);
2186 qtdemux->timescale = 0;
2187 qtdemux->got_moov = FALSE;
2188 qtdemux->cenc_aux_info_offset = 0;
2189 qtdemux->cenc_aux_info_sizes = NULL;
2190 qtdemux->cenc_aux_sample_count = 0;
2191 if (qtdemux->protection_system_ids) {
2192 g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2193 qtdemux->protection_system_ids = NULL;
2195 qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2196 && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2197 GST_BIN_FLAG_STREAMS_AWARE);
2199 if (qtdemux->preferred_protection_system_id) {
2200 g_free (qtdemux->preferred_protection_system_id);
2201 qtdemux->preferred_protection_system_id = NULL;
2203 } else if (qtdemux->mss_mode) {
2204 gst_flow_combiner_reset (qtdemux->flowcombiner);
2205 g_ptr_array_foreach (qtdemux->active_streams,
2206 (GFunc) gst_qtdemux_stream_clear, NULL);
2208 gst_flow_combiner_reset (qtdemux->flowcombiner);
2209 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2210 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2211 stream->sent_eos = FALSE;
2212 stream->time_position = 0;
2213 stream->accumulated_base = 0;
2219 /* Maps the @segment to the qt edts internal segments and pushes
2220 * the correspnding segment event.
2222 * If it ends up being at a empty segment, a gap will be pushed and the next
2223 * edts segment will be activated in sequence.
2225 * To be used in push-mode only */
2227 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2231 for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2232 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2234 stream->time_position = segment->start;
2236 /* in push mode we should be guaranteed that we will have empty segments
2237 * at the beginning and then one segment after, other scenarios are not
2238 * supported and are discarded when parsing the edts */
2239 for (i = 0; i < stream->n_segments; i++) {
2240 if (stream->segments[i].stop_time > segment->start) {
2241 /* push the empty segment and move to the next one */
2242 gst_qtdemux_activate_segment (qtdemux, stream, i,
2243 stream->time_position);
2244 if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2245 gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2246 stream->time_position);
2248 /* accumulate previous segments */
2249 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2250 stream->accumulated_base +=
2251 (stream->segment.stop -
2252 stream->segment.start) / ABS (stream->segment.rate);
2256 g_assert (i == stream->n_segments - 1);
2263 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2274 for (i = 0; i < len; i++) {
2275 QtDemuxStream *stream = g_ptr_array_index (src, i);
2277 #ifndef GST_DISABLE_GST_DEBUG
2278 GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2279 stream, GST_STR_NULL (stream->stream_id), dest);
2281 g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2284 g_ptr_array_remove_range (src, 0, len);
2288 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2291 GstQTDemux *demux = GST_QTDEMUX (parent);
2292 gboolean res = TRUE;
2294 GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2296 switch (GST_EVENT_TYPE (event)) {
2297 case GST_EVENT_SEGMENT:
2300 QtDemuxStream *stream;
2304 /* some debug output */
2305 gst_event_copy_segment (event, &segment);
2306 GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2309 if (segment.format == GST_FORMAT_TIME) {
2310 demux->upstream_format_is_time = TRUE;
2311 demux->segment_seqnum = gst_event_get_seqnum (event);
2313 GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2314 "not in time format");
2316 /* chain will send initial newsegment after pads have been added */
2317 if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2318 GST_DEBUG_OBJECT (demux, "still starting, eating event");
2323 /* check if this matches a time seek we received previously
2324 * FIXME for backwards compatibility reasons we use the
2325 * seek_offset here to compare. In the future we might want to
2326 * change this to use the seqnum as it uniquely should identify
2327 * the segment that corresponds to the seek. */
2328 GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2329 ", received segment offset %" G_GINT64_FORMAT,
2330 demux->seek_offset, segment.start);
2331 if (segment.format == GST_FORMAT_BYTES
2332 && demux->seek_offset == segment.start) {
2333 GST_OBJECT_LOCK (demux);
2334 offset = segment.start;
2336 segment.format = GST_FORMAT_TIME;
2337 segment.start = demux->push_seek_start;
2338 segment.stop = demux->push_seek_stop;
2339 GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2340 "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2341 GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2342 GST_OBJECT_UNLOCK (demux);
2345 /* we only expect a BYTE segment, e.g. following a seek */
2346 if (segment.format == GST_FORMAT_BYTES) {
2347 if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2348 offset = segment.start;
2350 gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2351 NULL, (gint64 *) & segment.start);
2352 if ((gint64) segment.start < 0)
2355 if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2356 gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2357 NULL, (gint64 *) & segment.stop);
2358 /* keyframe seeking should already arrange for start >= stop,
2359 * but make sure in other rare cases */
2360 segment.stop = MAX (segment.stop, segment.start);
2362 } else if (segment.format == GST_FORMAT_TIME) {
2363 /* push all data on the adapter before starting this
2365 gst_qtdemux_process_adapter (demux, TRUE);
2367 GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2371 /* We shouldn't modify upstream driven TIME FORMAT segment */
2372 if (!demux->upstream_format_is_time) {
2373 /* accept upstream's notion of segment and distribute along */
2374 segment.format = GST_FORMAT_TIME;
2375 segment.position = segment.time = segment.start;
2376 segment.duration = demux->segment.duration;
2377 segment.base = gst_segment_to_running_time (&demux->segment,
2378 GST_FORMAT_TIME, demux->segment.position);
2381 gst_segment_copy_into (&segment, &demux->segment);
2382 GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2384 /* map segment to internal qt segments and push on each stream */
2385 if (QTDEMUX_N_STREAMS (demux)) {
2386 demux->need_segment = TRUE;
2387 gst_qtdemux_check_send_pending_segment (demux);
2390 /* clear leftover in current segment, if any */
2391 gst_adapter_clear (demux->adapter);
2393 /* set up streaming thread */
2394 demux->offset = offset;
2395 if (demux->upstream_format_is_time) {
2396 GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2397 "set values to restart reading from a new atom");
2398 demux->neededbytes = 16;
2401 gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2404 demux->todrop = stream->samples[idx].offset - offset;
2405 demux->neededbytes = demux->todrop + stream->samples[idx].size;
2407 /* set up for EOS */
2408 demux->neededbytes = -1;
2413 gst_event_unref (event);
2417 case GST_EVENT_FLUSH_START:
2419 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2420 gst_event_unref (event);
2423 QTDEMUX_EXPOSE_LOCK (demux);
2424 res = gst_pad_event_default (demux->sinkpad, parent, event);
2425 QTDEMUX_EXPOSE_UNLOCK (demux);
2428 case GST_EVENT_FLUSH_STOP:
2432 dur = demux->segment.duration;
2433 gst_qtdemux_reset (demux, FALSE);
2434 demux->segment.duration = dur;
2436 if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2437 gst_event_unref (event);
2443 /* If we are in push mode, and get an EOS before we've seen any streams,
2444 * then error out - we have nowhere to send the EOS */
2445 if (!demux->pullbased) {
2447 gboolean has_valid_stream = FALSE;
2448 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2449 if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2450 has_valid_stream = TRUE;
2454 if (!has_valid_stream)
2455 gst_qtdemux_post_no_playable_stream_error (demux);
2457 GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2458 (guint) gst_adapter_available (demux->adapter));
2459 if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2465 case GST_EVENT_CAPS:{
2466 GstCaps *caps = NULL;
2468 gst_event_parse_caps (event, &caps);
2469 gst_qtdemux_setcaps (demux, caps);
2471 gst_event_unref (event);
2474 case GST_EVENT_PROTECTION:
2476 const gchar *system_id = NULL;
2478 gst_event_parse_protection (event, &system_id, NULL, NULL);
2479 GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2481 gst_qtdemux_append_protection_system_id (demux, system_id);
2482 /* save the event for later, for source pads that have not been created */
2483 g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2484 /* send it to all pads that already exist */
2485 gst_qtdemux_push_event (demux, event);
2489 case GST_EVENT_STREAM_START:
2492 gst_event_unref (event);
2494 /* Drain all the buffers */
2495 gst_qtdemux_process_adapter (demux, TRUE);
2496 gst_qtdemux_reset (demux, FALSE);
2497 /* We expect new moov box after new stream-start event */
2498 if (demux->exposed) {
2499 gst_qtdemux_stream_concat (demux,
2500 demux->old_streams, demux->active_streams);
2509 res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2516 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2519 GstQTDemux *demux = GST_QTDEMUX (parent);
2520 gboolean res = FALSE;
2522 switch (GST_QUERY_TYPE (query)) {
2523 case GST_QUERY_BITRATE:
2525 GstClockTime duration;
2527 /* populate demux->upstream_size if not done yet */
2528 gst_qtdemux_check_seekability (demux);
2530 if (demux->upstream_size != -1
2531 && gst_qtdemux_get_duration (demux, &duration)) {
2533 gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2536 GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2537 " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2538 demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2540 /* TODO: better results based on ranges/index tables */
2541 gst_query_set_bitrate (query, bitrate);
2547 res = gst_pad_query_default (pad, (GstObject *) demux, query);
2557 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2559 GstQTDemux *demux = GST_QTDEMUX (element);
2561 GST_OBJECT_LOCK (demux);
2562 if (demux->element_index)
2563 gst_object_unref (demux->element_index);
2565 demux->element_index = gst_object_ref (index);
2567 demux->element_index = NULL;
2569 GST_OBJECT_UNLOCK (demux);
2570 /* object lock might be taken again */
2572 gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2573 GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2574 demux->element_index, demux->index_id);
2578 gst_qtdemux_get_index (GstElement * element)
2580 GstIndex *result = NULL;
2581 GstQTDemux *demux = GST_QTDEMUX (element);
2583 GST_OBJECT_LOCK (demux);
2584 if (demux->element_index)
2585 result = gst_object_ref (demux->element_index);
2586 GST_OBJECT_UNLOCK (demux);
2588 GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2595 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2597 g_free ((gpointer) stream->stco.data);
2598 stream->stco.data = NULL;
2599 g_free ((gpointer) stream->stsz.data);
2600 stream->stsz.data = NULL;
2601 g_free ((gpointer) stream->stsc.data);
2602 stream->stsc.data = NULL;
2603 g_free ((gpointer) stream->stts.data);
2604 stream->stts.data = NULL;
2605 g_free ((gpointer) stream->stss.data);
2606 stream->stss.data = NULL;
2607 g_free ((gpointer) stream->stps.data);
2608 stream->stps.data = NULL;
2609 g_free ((gpointer) stream->ctts.data);
2610 stream->ctts.data = NULL;
2614 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2616 g_free (stream->segments);
2617 stream->segments = NULL;
2618 stream->segment_index = -1;
2619 stream->accumulated_base = 0;
2623 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2625 g_free (stream->samples);
2626 stream->samples = NULL;
2627 gst_qtdemux_stbl_free (stream);
2630 g_free (stream->ra_entries);
2631 stream->ra_entries = NULL;
2632 stream->n_ra_entries = 0;
2634 stream->sample_index = -1;
2635 stream->stbl_index = -1;
2636 stream->n_samples = 0;
2637 stream->time_position = 0;
2639 stream->n_samples_moof = 0;
2640 stream->duration_moof = 0;
2641 stream->duration_last_moof = 0;
2645 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2648 if (stream->allocator)
2649 gst_object_unref (stream->allocator);
2650 while (stream->buffers) {
2651 gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2652 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2654 for (i = 0; i < stream->stsd_entries_length; i++) {
2655 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2656 if (entry->rgb8_palette) {
2657 gst_memory_unref (entry->rgb8_palette);
2658 entry->rgb8_palette = NULL;
2660 entry->sparse = FALSE;
2663 if (stream->stream_tags)
2664 gst_tag_list_unref (stream->stream_tags);
2666 stream->stream_tags = gst_tag_list_new_empty ();
2667 gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2668 g_free (stream->redirect_uri);
2669 stream->redirect_uri = NULL;
2670 stream->sent_eos = FALSE;
2671 stream->protected = FALSE;
2672 if (stream->protection_scheme_info) {
2673 if (stream->protection_scheme_type == FOURCC_cenc) {
2674 QtDemuxCencSampleSetInfo *info =
2675 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2676 if (info->default_properties)
2677 gst_structure_free (info->default_properties);
2678 if (info->crypto_info)
2679 g_ptr_array_free (info->crypto_info, TRUE);
2681 g_free (stream->protection_scheme_info);
2682 stream->protection_scheme_info = NULL;
2684 stream->protection_scheme_type = 0;
2685 stream->protection_scheme_version = 0;
2686 g_queue_foreach (&stream->protection_scheme_event_queue,
2687 (GFunc) gst_event_unref, NULL);
2688 g_queue_clear (&stream->protection_scheme_event_queue);
2689 gst_qtdemux_stream_flush_segments_data (stream);
2690 gst_qtdemux_stream_flush_samples_data (stream);
2694 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2697 gst_qtdemux_stream_clear (stream);
2698 for (i = 0; i < stream->stsd_entries_length; i++) {
2699 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2701 gst_caps_unref (entry->caps);
2705 g_free (stream->stsd_entries);
2706 stream->stsd_entries = NULL;
2707 stream->stsd_entries_length = 0;
2710 static QtDemuxStream *
2711 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2713 g_atomic_int_add (&stream->ref_count, 1);
2719 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2721 if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2722 gst_qtdemux_stream_reset (stream);
2723 gst_tag_list_unref (stream->stream_tags);
2725 GstQTDemux *demux = stream->demux;
2726 gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2727 gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2729 g_free (stream->stream_id);
2734 static GstStateChangeReturn
2735 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2737 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2738 GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2740 switch (transition) {
2741 case GST_STATE_CHANGE_READY_TO_PAUSED:
2742 gst_qtdemux_reset (qtdemux, TRUE);
2748 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2750 switch (transition) {
2751 case GST_STATE_CHANGE_PAUSED_TO_READY:{
2752 gst_qtdemux_reset (qtdemux, TRUE);
2763 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2765 GstQTDemux *qtdemux = GST_QTDEMUX (element);
2767 g_return_if_fail (GST_IS_CONTEXT (context));
2769 if (gst_context_has_context_type (context,
2770 "drm-preferred-decryption-system-id")) {
2771 const GstStructure *s;
2773 s = gst_context_get_structure (context);
2774 g_free (qtdemux->preferred_protection_system_id);
2775 qtdemux->preferred_protection_system_id =
2776 g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2777 GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2778 qtdemux->preferred_protection_system_id);
2781 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2785 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2787 /* counts as header data */
2788 qtdemux->header_size += length;
2790 /* only consider at least a sufficiently complete ftyp atom */
2794 qtdemux->major_brand = QT_FOURCC (buffer + 8);
2795 GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2796 GST_FOURCC_ARGS (qtdemux->major_brand));
2797 if (qtdemux->comp_brands)
2798 gst_buffer_unref (qtdemux->comp_brands);
2799 buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2800 gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2805 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2806 GstTagList * xmptaglist)
2808 /* Strip out bogus fields */
2810 if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2811 gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2812 gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2814 gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2817 GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2819 /* prioritize native tags using _KEEP mode */
2820 gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2821 gst_tag_list_unref (xmptaglist);
2826 qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
2827 QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
2830 GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
2831 gst_buffer_fill (kid_buf, 0, kid, 16);
2832 if (info->default_properties)
2833 gst_structure_free (info->default_properties);
2834 info->default_properties =
2835 gst_structure_new ("application/x-cenc",
2836 "iv_size", G_TYPE_UINT, iv_size,
2837 "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
2838 "kid", GST_TYPE_BUFFER, kid_buf, NULL);
2839 GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
2840 "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
2841 gst_buffer_unref (kid_buf);
2845 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
2846 QtDemuxCencSampleSetInfo * info, GstByteReader * br)
2848 guint32 algorithm_id = 0;
2850 gboolean is_encrypted = TRUE;
2853 if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
2854 GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
2859 if (algorithm_id == 0) {
2860 is_encrypted = FALSE;
2861 } else if (algorithm_id == 1) {
2862 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
2863 } else if (algorithm_id == 2) {
2864 GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
2867 if (!gst_byte_reader_get_uint8 (br, &iv_size))
2870 if (!gst_byte_reader_get_data (br, 16, &kid))
2873 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
2874 is_encrypted, iv_size, kid);
2875 gst_structure_set (info->default_properties, "piff_algorithm_id",
2876 G_TYPE_UINT, algorithm_id, NULL);
2882 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
2890 QtDemuxStream *stream;
2891 GstStructure *structure;
2892 QtDemuxCencSampleSetInfo *ss_info = NULL;
2893 const gchar *system_id;
2894 gboolean uses_sub_sample_encryption = FALSE;
2895 guint32 sample_count;
2897 if (QTDEMUX_N_STREAMS (qtdemux) == 0)
2900 stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
2902 structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
2903 if (!gst_structure_has_name (structure, "application/x-cenc")) {
2904 GST_WARNING_OBJECT (qtdemux,
2905 "Attempting PIFF box parsing on an unencrypted stream.");
2909 gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
2910 G_TYPE_STRING, &system_id, NULL);
2911 gst_qtdemux_append_protection_system_id (qtdemux, system_id);
2913 stream->protected = TRUE;
2914 stream->protection_scheme_type = FOURCC_cenc;
2916 if (!stream->protection_scheme_info)
2917 stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
2919 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2920 if (!ss_info->default_properties) {
2921 ss_info->default_properties =
2922 gst_structure_new ("application/x-cenc",
2923 "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
2928 if (ss_info->crypto_info) {
2929 GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
2930 g_ptr_array_free (ss_info->crypto_info, TRUE);
2931 ss_info->crypto_info = NULL;
2935 gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
2937 if (!gst_byte_reader_get_uint8 (&br, &version)) {
2938 GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
2942 if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
2943 GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
2947 if ((flags & 0x000001)) {
2948 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
2951 } else if ((flags & 0x000002)) {
2952 uses_sub_sample_encryption = TRUE;
2955 if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
2957 GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
2961 if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
2962 GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
2966 ss_info->crypto_info =
2967 g_ptr_array_new_full (sample_count,
2968 (GDestroyNotify) qtdemux_gst_structure_free);
2970 for (i = 0; i < sample_count; ++i) {
2971 GstStructure *properties;
2975 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
2976 if (properties == NULL) {
2977 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
2978 qtdemux->cenc_aux_sample_count = i;
2982 if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
2983 GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
2984 gst_structure_free (properties);
2985 qtdemux->cenc_aux_sample_count = i;
2988 buf = gst_buffer_new_wrapped (data, iv_size);
2989 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
2990 gst_buffer_unref (buf);
2992 if (uses_sub_sample_encryption) {
2993 guint16 n_subsamples;
2994 const GValue *kid_buf_value;
2996 if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
2997 || n_subsamples == 0) {
2998 GST_ERROR_OBJECT (qtdemux,
2999 "failed to get subsample count for sample %u", i);
3000 gst_structure_free (properties);
3001 qtdemux->cenc_aux_sample_count = i;
3004 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3005 if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
3006 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3008 gst_structure_free (properties);
3009 qtdemux->cenc_aux_sample_count = i;
3012 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3015 gst_structure_get_value (ss_info->default_properties, "kid");
3017 gst_structure_set (properties,
3018 "subsample_count", G_TYPE_UINT, n_subsamples,
3019 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3020 gst_structure_set_value (properties, "kid", kid_buf_value);
3021 gst_buffer_unref (buf);
3023 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3026 g_ptr_array_add (ss_info->crypto_info, properties);
3029 qtdemux->cenc_aux_sample_count = sample_count;
3033 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3035 static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
3036 0x97, 0xA9, 0x42, 0xE8,
3037 0x9C, 0x71, 0x99, 0x94,
3038 0x91, 0xE3, 0xAF, 0xAC
3040 static const guint8 playready_uuid[] = {
3041 0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
3042 0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
3045 static const guint8 piff_sample_encryption_uuid[] = {
3046 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3047 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3052 /* counts as header data */
3053 qtdemux->header_size += length;
3055 offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3057 if (length <= offset + 16) {
3058 GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3062 if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3064 GstTagList *taglist;
3066 buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3067 length - offset - 16, NULL);
3068 taglist = gst_tag_list_from_xmp_buffer (buf);
3069 gst_buffer_unref (buf);
3071 /* make sure we have a usable taglist */
3072 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3074 qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3076 } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3078 const gunichar2 *s_utf16;
3081 len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3082 s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3083 contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3084 GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3088 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3089 (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3091 } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3092 qtdemux_parse_piff (qtdemux, buffer, length, offset);
3094 GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3095 GST_READ_UINT32_LE (buffer + offset),
3096 GST_READ_UINT32_LE (buffer + offset + 4),
3097 GST_READ_UINT32_LE (buffer + offset + 8),
3098 GST_READ_UINT32_LE (buffer + offset + 12));
3103 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3105 GstSidxParser sidx_parser;
3106 GstIsoffParserResult res;
3109 gst_isoff_qt_sidx_parser_init (&sidx_parser);
3112 gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3114 GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3115 if (res == GST_ISOFF_QT_PARSER_DONE) {
3116 check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3118 gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3121 /* caller verifies at least 8 bytes in buf */
3123 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3124 guint64 * plength, guint32 * pfourcc)
3129 length = QT_UINT32 (data);
3130 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3131 fourcc = QT_FOURCC (data + 4);
3132 GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3135 length = G_MAXUINT64;
3136 } else if (length == 1 && size >= 16) {
3137 /* this means we have an extended size, which is the 64 bit value of
3138 * the next 8 bytes */
3139 length = QT_UINT64 (data + 8);
3140 GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3150 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3152 guint32 version = 0;
3153 GstClockTime duration = 0;
3155 if (!gst_byte_reader_get_uint32_be (br, &version))
3160 if (!gst_byte_reader_get_uint64_be (br, &duration))
3165 if (!gst_byte_reader_get_uint32_be (br, &dur))
3170 GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3171 qtdemux->duration = duration;
3177 GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3183 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3184 guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3186 if (!stream->parsed_trex && qtdemux->moov_node) {
3188 GstByteReader trex_data;
3190 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3192 trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3195 guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3197 /* skip version/flags */
3198 if (!gst_byte_reader_skip (&trex_data, 4))
3200 if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3202 if (id != stream->track_id)
3204 if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3206 if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3208 if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3210 if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3213 GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3214 "duration %d, size %d, flags 0x%x", stream->track_id,
3217 stream->parsed_trex = TRUE;
3218 stream->def_sample_description_index = sdi;
3219 stream->def_sample_duration = dur;
3220 stream->def_sample_size = size;
3221 stream->def_sample_flags = flags;
3224 /* iterate all siblings */
3225 trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3231 *ds_duration = stream->def_sample_duration;
3232 *ds_size = stream->def_sample_size;
3233 *ds_flags = stream->def_sample_flags;
3235 /* even then, above values are better than random ... */
3236 if (G_UNLIKELY (!stream->parsed_trex)) {
3237 GST_WARNING_OBJECT (qtdemux,
3238 "failed to find fragment defaults for stream %d", stream->track_id);
3245 /* This method should be called whenever a more accurate duration might
3246 * have been found. It will update all relevant variables if/where needed
3249 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3253 GstClockTime prevdur;
3255 movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3257 if (movdur > qtdemux->duration) {
3258 prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3259 GST_DEBUG_OBJECT (qtdemux,
3260 "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3261 GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3262 qtdemux->duration = movdur;
3263 GST_DEBUG_OBJECT (qtdemux,
3264 "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3265 GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3266 GST_TIME_ARGS (qtdemux->segment.stop));
3267 if (qtdemux->segment.duration == prevdur) {
3268 /* If the current segment has duration/stop identical to previous duration
3269 * update them also (because they were set at that point in time with
3270 * the wrong duration */
3271 /* We convert the value *from* the timescale version to avoid rounding errors */
3272 GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3273 GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3274 qtdemux->segment.duration = fixeddur;
3275 qtdemux->segment.stop = fixeddur;
3279 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3280 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3282 movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3283 if (movdur > stream->duration) {
3284 GST_DEBUG_OBJECT (qtdemux,
3285 "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3286 GST_TIME_ARGS (duration));
3287 stream->duration = movdur;
3288 /* internal duration tracking state has been updated above, so */
3289 /* preserve an open-ended dummy segment rather than repeatedly updating
3290 * it and spamming downstream accordingly with segment events */
3291 if (stream->dummy_segment &&
3292 GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3293 /* Update all dummy values to new duration */
3294 stream->segments[0].stop_time = duration;
3295 stream->segments[0].duration = duration;
3296 stream->segments[0].media_stop = duration;
3298 /* let downstream know we possibly have a new stop time */
3299 if (stream->segment_index != -1) {
3302 if (qtdemux->segment.rate >= 0) {
3303 pos = stream->segment.start;
3305 pos = stream->segment.stop;
3308 gst_qtdemux_stream_update_segment (qtdemux, stream,
3309 stream->segment_index, pos, NULL, NULL);
3317 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3318 QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3319 guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3320 gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3323 GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3325 gint32 data_offset = 0;
3326 guint32 flags = 0, first_flags = 0, samples_count = 0;
3329 guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3330 QtDemuxSample *sample;
3331 gboolean ismv = FALSE;
3332 gint64 initial_offset;
3334 GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3335 "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3336 "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3337 d_sample_size, d_sample_flags, *base_offset, decode_ts);
3339 if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3340 GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3344 /* presence of stss or not can't really tell us much,
3345 * and flags and so on tend to be marginally reliable in these files */
3346 if (stream->subtype == FOURCC_soun) {
3347 GST_DEBUG_OBJECT (qtdemux,
3348 "sound track in fragmented file; marking all keyframes");
3349 stream->all_keyframe = TRUE;
3352 if (!gst_byte_reader_skip (trun, 1) ||
3353 !gst_byte_reader_get_uint24_be (trun, &flags))
3356 if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3359 if (flags & TR_DATA_OFFSET) {
3360 /* note this is really signed */
3361 if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3363 GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3364 /* default base offset = first byte of moof */
3365 if (*base_offset == -1) {
3366 GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3367 *base_offset = moof_offset;
3369 *running_offset = *base_offset + data_offset;
3371 /* if no offset at all, that would mean data starts at moof start,
3372 * which is a bit wrong and is ismv crappy way, so compensate
3373 * assuming data is in mdat following moof */
3374 if (*base_offset == -1) {
3375 *base_offset = moof_offset + moof_length + 8;
3376 GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3379 if (*running_offset == -1)
3380 *running_offset = *base_offset;
3383 GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3385 GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3386 data_offset, flags, samples_count);
3388 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3389 if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3390 GST_DEBUG_OBJECT (qtdemux,
3391 "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3392 flags ^= TR_FIRST_SAMPLE_FLAGS;
3394 if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3396 GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3400 /* FIXME ? spec says other bits should also be checked to determine
3401 * entry size (and prefix size for that matter) */
3403 dur_offset = size_offset = 0;
3404 if (flags & TR_SAMPLE_DURATION) {
3405 GST_LOG_OBJECT (qtdemux, "entry duration present");
3406 dur_offset = entry_size;
3409 if (flags & TR_SAMPLE_SIZE) {
3410 GST_LOG_OBJECT (qtdemux, "entry size present");
3411 size_offset = entry_size;
3414 if (flags & TR_SAMPLE_FLAGS) {
3415 GST_LOG_OBJECT (qtdemux, "entry flags present");
3416 flags_offset = entry_size;
3419 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3420 GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3421 ct_offset = entry_size;
3425 if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3427 data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3429 if (stream->n_samples + samples_count >=
3430 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3433 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3434 stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3435 (stream->n_samples + samples_count) *
3436 sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3438 /* create a new array of samples if it's the first sample parsed */
3439 if (stream->n_samples == 0) {
3440 g_assert (stream->samples == NULL);
3441 stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3442 /* or try to reallocate it with space enough to insert the new samples */
3444 stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3445 stream->n_samples + samples_count);
3446 if (stream->samples == NULL)
3449 if (qtdemux->fragment_start != -1) {
3450 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3451 qtdemux->fragment_start = -1;
3453 if (stream->n_samples == 0) {
3454 if (decode_ts > 0) {
3455 timestamp = decode_ts;
3456 } else if (stream->pending_seek != NULL) {
3457 /* if we don't have a timestamp from a tfdt box, we'll use the one
3458 * from the mfra seek table */
3459 GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3460 GST_TIME_ARGS (stream->pending_seek->ts));
3462 /* FIXME: this is not fully correct, the timestamp refers to the random
3463 * access sample refered to in the tfra entry, which may not necessarily
3464 * be the first sample in the tfrag/trun (but hopefully/usually is) */
3465 timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3470 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3471 GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3472 GST_TIME_ARGS (gst_ts));
3474 /* subsequent fragments extend stream */
3476 stream->samples[stream->n_samples - 1].timestamp +
3477 stream->samples[stream->n_samples - 1].duration;
3479 /* If this is a GST_FORMAT_BYTES stream and there's a significant
3480 * difference (1 sec.) between decode_ts and timestamp, prefer the
3482 if (has_tfdt && !qtdemux->upstream_format_is_time
3483 && ABSDIFF (decode_ts, timestamp) >
3484 MAX (stream->duration_last_moof / 2,
3485 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3486 GST_INFO_OBJECT (qtdemux,
3487 "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3488 ") are significantly different (more than %" GST_TIME_FORMAT
3489 "), using decode_ts",
3490 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3491 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3492 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3493 MAX (stream->duration_last_moof / 2,
3494 GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3495 timestamp = decode_ts;
3498 gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3499 GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3500 " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3504 initial_offset = *running_offset;
3506 sample = stream->samples + stream->n_samples;
3507 for (i = 0; i < samples_count; i++) {
3508 guint32 dur, size, sflags, ct;
3510 /* first read sample data */
3511 if (flags & TR_SAMPLE_DURATION) {
3512 dur = QT_UINT32 (data + dur_offset);
3514 dur = d_sample_duration;
3516 if (flags & TR_SAMPLE_SIZE) {
3517 size = QT_UINT32 (data + size_offset);
3519 size = d_sample_size;
3521 if (flags & TR_FIRST_SAMPLE_FLAGS) {
3523 sflags = first_flags;
3525 sflags = d_sample_flags;
3527 } else if (flags & TR_SAMPLE_FLAGS) {
3528 sflags = QT_UINT32 (data + flags_offset);
3530 sflags = d_sample_flags;
3532 if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3533 ct = QT_UINT32 (data + ct_offset);
3539 /* fill the sample information */
3540 sample->offset = *running_offset;
3541 sample->pts_offset = ct;
3542 sample->size = size;
3543 sample->timestamp = timestamp;
3544 sample->duration = dur;
3545 /* sample-is-difference-sample */
3546 /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3547 * now idea how it relates to bitfield other than massive LE/BE confusion */
3548 sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3549 *running_offset += size;
3551 stream->duration_moof += dur;
3555 /* Update total duration if needed */
3556 check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3558 /* Pre-emptively figure out size of mdat based on trun information.
3559 * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3560 * size, else we will still be able to use this when dealing with gap'ed
3562 qtdemux->mdatleft = *running_offset - initial_offset;
3563 qtdemux->mdatoffset = initial_offset;
3564 qtdemux->mdatsize = qtdemux->mdatleft;
3566 stream->n_samples += samples_count;
3567 stream->n_samples_moof += samples_count;
3569 if (stream->pending_seek != NULL)
3570 stream->pending_seek = NULL;
3576 GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3581 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3587 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3588 "be larger than %uMB (broken file?)", stream->n_samples,
3589 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3594 /* find stream with @id */
3595 static inline QtDemuxStream *
3596 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3598 QtDemuxStream *stream;
3602 if (G_UNLIKELY (!id)) {
3603 GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3607 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3608 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3609 if (stream->track_id == id)
3612 if (qtdemux->mss_mode) {
3613 /* mss should have only 1 stream anyway */
3614 return QTDEMUX_NTH_STREAM (qtdemux, 0);
3621 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3622 guint32 * fragment_number)
3624 if (!gst_byte_reader_skip (mfhd, 4))
3626 if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3631 GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3637 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3638 QtDemuxStream ** stream, guint32 * default_sample_duration,
3639 guint32 * default_sample_size, guint32 * default_sample_flags,
3640 gint64 * base_offset)
3643 guint32 track_id = 0;
3645 if (!gst_byte_reader_skip (tfhd, 1) ||
3646 !gst_byte_reader_get_uint24_be (tfhd, &flags))
3649 if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3652 *stream = qtdemux_find_stream (qtdemux, track_id);
3653 if (G_UNLIKELY (!*stream))
3654 goto unknown_stream;
3656 if (flags & TF_DEFAULT_BASE_IS_MOOF)
3657 *base_offset = qtdemux->moof_offset;
3659 if (flags & TF_BASE_DATA_OFFSET)
3660 if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3663 /* obtain stream defaults */
3664 qtdemux_parse_trex (qtdemux, *stream,
3665 default_sample_duration, default_sample_size, default_sample_flags);
3667 (*stream)->stsd_sample_description_id =
3668 (*stream)->def_sample_description_index - 1;
3670 if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
3671 guint32 sample_description_index;
3672 if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
3674 (*stream)->stsd_sample_description_id = sample_description_index - 1;
3677 if (qtdemux->mss_mode) {
3678 /* mss has no stsd entry */
3679 (*stream)->stsd_sample_description_id = 0;
3682 if (flags & TF_DEFAULT_SAMPLE_DURATION)
3683 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3686 if (flags & TF_DEFAULT_SAMPLE_SIZE)
3687 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3690 if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3691 if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3698 GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3703 GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3709 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3710 guint64 * decode_time)
3712 guint32 version = 0;
3714 if (!gst_byte_reader_get_uint32_be (br, &version))
3719 if (!gst_byte_reader_get_uint64_be (br, decode_time))
3722 guint32 dec_time = 0;
3723 if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3725 *decode_time = dec_time;
3728 GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3735 GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3740 /* Returns a pointer to a GstStructure containing the properties of
3741 * the stream sample identified by @sample_index. The caller must unref
3742 * the returned object after use. Returns NULL if unsuccessful. */
3743 static GstStructure *
3744 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3745 QtDemuxStream * stream, guint sample_index)
3747 QtDemuxCencSampleSetInfo *info = NULL;
3749 g_return_val_if_fail (stream != NULL, NULL);
3750 g_return_val_if_fail (stream->protected, NULL);
3751 g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3753 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3755 /* Currently, cenc properties for groups of samples are not supported, so
3756 * simply return a copy of the default sample properties */
3757 return gst_structure_copy (info->default_properties);
3760 /* Parses the sizes of sample auxiliary information contained within a stream,
3761 * as given in a saiz box. Returns array of sample_count guint8 size values,
3762 * or NULL on failure */
3764 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3765 GstByteReader * br, guint32 * sample_count)
3769 guint8 default_info_size;
3771 g_return_val_if_fail (qtdemux != NULL, NULL);
3772 g_return_val_if_fail (stream != NULL, NULL);
3773 g_return_val_if_fail (br != NULL, NULL);
3774 g_return_val_if_fail (sample_count != NULL, NULL);
3776 if (!gst_byte_reader_get_uint32_be (br, &flags))
3780 /* aux_info_type and aux_info_type_parameter are ignored */
3781 if (!gst_byte_reader_skip (br, 8))
3785 if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3787 GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3789 if (!gst_byte_reader_get_uint32_be (br, sample_count))
3791 GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3794 if (default_info_size == 0) {
3795 if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3799 info_sizes = g_new (guint8, *sample_count);
3800 memset (info_sizes, default_info_size, *sample_count);
3806 /* Parses the offset of sample auxiliary information contained within a stream,
3807 * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3809 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3810 GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3815 guint32 aux_info_type = 0;
3816 guint32 aux_info_type_parameter = 0;
3817 guint32 entry_count;
3820 const guint8 *aux_info_type_data = NULL;
3822 g_return_val_if_fail (qtdemux != NULL, FALSE);
3823 g_return_val_if_fail (stream != NULL, FALSE);
3824 g_return_val_if_fail (br != NULL, FALSE);
3825 g_return_val_if_fail (offset != NULL, FALSE);
3827 if (!gst_byte_reader_get_uint8 (br, &version))
3830 if (!gst_byte_reader_get_uint24_be (br, &flags))
3835 if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
3837 aux_info_type = QT_FOURCC (aux_info_type_data);
3839 if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3841 } else if (stream->protected) {
3842 aux_info_type = stream->protection_scheme_type;
3844 aux_info_type = CUR_STREAM (stream)->fourcc;
3848 *info_type = aux_info_type;
3849 if (info_type_parameter)
3850 *info_type_parameter = aux_info_type_parameter;
3852 GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3853 "aux_info_type_parameter: %#06x",
3854 GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3856 if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3859 if (entry_count != 1) {
3860 GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3865 if (!gst_byte_reader_get_uint32_be (br, &off_32))
3867 *offset = (guint64) off_32;
3869 if (!gst_byte_reader_get_uint64_be (br, &off_64))
3874 GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3879 qtdemux_gst_structure_free (GstStructure * gststructure)
3882 gst_structure_free (gststructure);
3886 /* Parses auxiliary information relating to samples protected using Common
3887 * Encryption (cenc); the format of this information is defined in
3888 * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3890 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3891 GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3893 QtDemuxCencSampleSetInfo *ss_info = NULL;
3896 GPtrArray *old_crypto_info = NULL;
3897 guint old_entries = 0;
3899 g_return_val_if_fail (qtdemux != NULL, FALSE);
3900 g_return_val_if_fail (stream != NULL, FALSE);
3901 g_return_val_if_fail (br != NULL, FALSE);
3902 g_return_val_if_fail (stream->protected, FALSE);
3903 g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3905 ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3907 if (ss_info->crypto_info) {
3908 old_crypto_info = ss_info->crypto_info;
3909 /* Count number of non-null entries remaining at the tail end */
3910 for (i = old_crypto_info->len - 1; i >= 0; i--) {
3911 if (g_ptr_array_index (old_crypto_info, i) == NULL)
3917 ss_info->crypto_info =
3918 g_ptr_array_new_full (sample_count + old_entries,
3919 (GDestroyNotify) qtdemux_gst_structure_free);
3921 /* We preserve old entries because we parse the next moof in advance
3922 * of consuming all samples from the previous moof, and otherwise
3923 * we'd discard the corresponding crypto info for the samples
3924 * from the previous fragment. */
3926 GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
3928 for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
3929 g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
3931 g_ptr_array_index (old_crypto_info, i) = NULL;
3935 if (old_crypto_info) {
3936 /* Everything now belongs to the new array */
3937 g_ptr_array_free (old_crypto_info, TRUE);
3940 for (i = 0; i < sample_count; ++i) {
3941 GstStructure *properties;
3942 guint16 n_subsamples = 0;
3947 properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3948 if (properties == NULL) {
3949 GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3952 if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3953 GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3954 gst_structure_free (properties);
3957 if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3958 GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3959 gst_structure_free (properties);
3962 buf = gst_buffer_new_wrapped (data, iv_size);
3963 gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3964 gst_buffer_unref (buf);
3965 size = info_sizes[i];
3966 if (size > iv_size) {
3967 if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3968 || !(n_subsamples > 0)) {
3969 gst_structure_free (properties);
3970 GST_ERROR_OBJECT (qtdemux,
3971 "failed to get subsample count for sample %u", i);
3974 GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3975 if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3976 GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3978 gst_structure_free (properties);
3981 buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3983 gst_structure_free (properties);
3986 gst_structure_set (properties,
3987 "subsample_count", G_TYPE_UINT, n_subsamples,
3988 "subsamples", GST_TYPE_BUFFER, buf, NULL);
3989 gst_buffer_unref (buf);
3991 gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3993 g_ptr_array_add (ss_info->crypto_info, properties);
3998 /* Converts a UUID in raw byte form to a string representation, as defined in
3999 * RFC 4122. The caller takes ownership of the returned string and is
4000 * responsible for freeing it after use. */
4002 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4004 const guint8 *uuid = (const guint8 *) uuid_bytes;
4006 return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4007 "%02x%02x-%02x%02x%02x%02x%02x%02x",
4008 uuid[0], uuid[1], uuid[2], uuid[3],
4009 uuid[4], uuid[5], uuid[6], uuid[7],
4010 uuid[8], uuid[9], uuid[10], uuid[11],
4011 uuid[12], uuid[13], uuid[14], uuid[15]);
4014 /* Parses a Protection System Specific Header box (pssh), as defined in the
4015 * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4016 * information needed by a specific content protection system in order to
4017 * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4020 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4022 gchar *sysid_string;
4023 guint32 pssh_size = QT_UINT32 (node->data);
4024 GstBuffer *pssh = NULL;
4025 GstEvent *event = NULL;
4026 guint32 parent_box_type;
4029 if (G_UNLIKELY (pssh_size < 32U)) {
4030 GST_ERROR_OBJECT (qtdemux, "invalid box size");
4035 qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4037 gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4039 pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
4040 GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4041 gst_buffer_get_size (pssh));
4043 parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4045 /* Push an event containing the pssh box onto the queues of all streams. */
4046 event = gst_event_new_protection (sysid_string, pssh,
4047 (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4048 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4049 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4050 GST_TRACE_OBJECT (qtdemux,
4051 "adding protection event for stream %s and system %s",
4052 stream->stream_id, sysid_string);
4053 g_queue_push_tail (&stream->protection_scheme_event_queue,
4054 gst_event_ref (event));
4056 g_free (sysid_string);
4057 gst_event_unref (event);
4058 gst_buffer_unref (pssh);
4063 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4064 guint64 moof_offset, QtDemuxStream * stream)
4066 GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4068 GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4069 GNode *saiz_node, *saio_node, *pssh_node;
4070 GstByteReader saiz_data, saio_data;
4071 guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4072 gint64 base_offset, running_offset;
4074 GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4076 /* NOTE @stream ignored */
4078 moof_node = g_node_new ((guint8 *) buffer);
4079 qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4080 qtdemux_node_dump (qtdemux, moof_node);
4082 /* Get fragment number from mfhd and check it's valid */
4084 qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4085 if (mfhd_node == NULL)
4087 if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4089 GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4091 /* unknown base_offset to start with */
4092 base_offset = running_offset = -1;
4093 traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4095 guint64 decode_time = 0;
4097 /* Fragment Header node */
4099 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4103 if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4104 &ds_size, &ds_flags, &base_offset))
4107 /* The following code assumes at most a single set of sample auxiliary
4108 * data in the fragment (consisting of a saiz box and a corresponding saio
4109 * box); in theory, however, there could be multiple sets of sample
4110 * auxiliary data in a fragment. */
4112 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4115 guint32 info_type = 0;
4117 guint32 info_type_parameter = 0;
4119 g_free (qtdemux->cenc_aux_info_sizes);
4121 qtdemux->cenc_aux_info_sizes =
4122 qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4123 &qtdemux->cenc_aux_sample_count);
4124 if (qtdemux->cenc_aux_info_sizes == NULL) {
4125 GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4129 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4132 GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4133 g_free (qtdemux->cenc_aux_info_sizes);
4134 qtdemux->cenc_aux_info_sizes = NULL;
4138 if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4139 &info_type, &info_type_parameter, &offset))) {
4140 GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4141 g_free (qtdemux->cenc_aux_info_sizes);
4142 qtdemux->cenc_aux_info_sizes = NULL;
4145 if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4146 offset += (guint64) (base_offset - qtdemux->moof_offset);
4147 if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4149 if (offset > length) {
4150 GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4151 qtdemux->cenc_aux_info_offset = offset;
4153 gst_byte_reader_init (&br, buffer + offset, length - offset);
4154 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4155 qtdemux->cenc_aux_info_sizes,
4156 qtdemux->cenc_aux_sample_count)) {
4157 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4158 g_free (qtdemux->cenc_aux_info_sizes);
4159 qtdemux->cenc_aux_info_sizes = NULL;
4167 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4170 /* We'll use decode_time to interpolate timestamps
4171 * in case the input timestamps are missing */
4172 qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4174 GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4175 " (%" GST_TIME_FORMAT ")", decode_time,
4176 GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4177 decode_time) : GST_CLOCK_TIME_NONE));
4179 /* Discard the fragment buffer timestamp info to avoid using it.
4180 * Rely on tfdt instead as it is more accurate than the timestamp
4181 * that is fetched from a manifest/playlist and is usually
4183 qtdemux->fragment_start = -1;
4186 if (G_UNLIKELY (!stream)) {
4187 /* we lost track of offset, we'll need to regain it,
4188 * but can delay complaining until later or avoid doing so altogether */
4192 if (G_UNLIKELY (base_offset < -1))
4195 min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4197 if (!qtdemux->pullbased) {
4198 /* Sample tables can grow enough to be problematic if the system memory
4199 * is very low (e.g. embedded devices) and the videos very long
4200 * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4201 * Fortunately, we can easily discard them for each new fragment when
4202 * we know qtdemux will not receive seeks outside of the current fragment.
4203 * adaptivedemux honors this assumption.
4204 * This optimization is also useful for applications that use qtdemux as
4205 * a push-based simple demuxer, like Media Source Extensions. */
4206 gst_qtdemux_stream_flush_samples_data (stream);
4209 /* initialise moof sample data */
4210 stream->n_samples_moof = 0;
4211 stream->duration_last_moof = stream->duration_moof;
4212 stream->duration_moof = 0;
4214 /* Track Run node */
4216 qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4219 qtdemux_parse_trun (qtdemux, &trun_data, stream,
4220 ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4221 &running_offset, decode_time, (tfdt_node != NULL));
4222 /* iterate all siblings */
4223 trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4227 uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4229 guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4230 guint32 box_length = QT_UINT32 (uuid_buffer);
4232 qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4235 /* if no new base_offset provided for next traf,
4236 * base is end of current traf */
4237 base_offset = running_offset;
4238 running_offset = -1;
4240 if (stream->n_samples_moof && stream->duration_moof)
4241 stream->new_caps = TRUE;
4244 /* iterate all siblings */
4245 traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4248 /* parse any protection system info */
4249 pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4251 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4252 qtdemux_parse_pssh (qtdemux, pssh_node);
4253 pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4256 if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4257 && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4259 /* Unless the user has explictly requested another seek, perform an
4260 * internal seek to the time specified in the tfdt.
4262 * This way if the user opens a file where the first tfdt is 1 hour
4263 * into the presentation, they will not have to wait 1 hour for run
4264 * time to catch up and actual playback to start. */
4267 GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4268 "performing an internal seek to %" GST_TIME_FORMAT,
4269 GST_TIME_ARGS (min_dts));
4271 qtdemux->segment.start = min_dts;
4272 qtdemux->segment.time = qtdemux->segment.position = min_dts;
4274 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4275 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4276 stream->time_position = min_dts;
4279 /* Before this code was run a segment was already sent when the moov was
4280 * parsed... which is OK -- some apps (mostly tests) expect a segment to
4281 * be emitted after a moov, and we can emit a second segment anyway for
4282 * special cases like this. */
4283 qtdemux->need_segment = TRUE;
4286 qtdemux->first_moof_already_parsed = TRUE;
4288 g_node_destroy (moof_node);
4293 GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4298 GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4303 GST_DEBUG_OBJECT (qtdemux, "lost offset");
4308 g_node_destroy (moof_node);
4309 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4310 (_("This file is corrupt and cannot be played.")), (NULL));
4316 /* might be used if some day we actually use mfra & co
4317 * for random access to fragments,
4318 * but that will require quite some modifications and much less relying
4319 * on a sample array */
4323 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4325 QtDemuxStream *stream;
4326 guint32 ver_flags, track_id, len, num_entries, i;
4327 guint value_size, traf_size, trun_size, sample_size;
4328 guint64 time = 0, moof_offset = 0;
4330 GstBuffer *buf = NULL;
4335 gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4337 if (!gst_byte_reader_skip (&tfra, 8))
4340 if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4343 if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4344 || !gst_byte_reader_get_uint32_be (&tfra, &len)
4345 || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4348 GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4350 stream = qtdemux_find_stream (qtdemux, track_id);
4352 goto unknown_trackid;
4354 value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4355 sample_size = (len & 3) + 1;
4356 trun_size = ((len & 12) >> 2) + 1;
4357 traf_size = ((len & 48) >> 4) + 1;
4359 GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4360 "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4362 if (num_entries == 0)
4365 if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4366 value_size + value_size + traf_size + trun_size + sample_size))
4369 g_free (stream->ra_entries);
4370 stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4371 stream->n_ra_entries = num_entries;
4373 for (i = 0; i < num_entries; i++) {
4374 qt_atom_parser_get_offset (&tfra, value_size, &time);
4375 qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4376 qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4377 qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4378 qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4380 time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4382 GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4383 " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4385 stream->ra_entries[i].ts = time;
4386 stream->ra_entries[i].moof_offset = moof_offset;
4388 /* don't want to go through the entire file and read all moofs at startup */
4390 ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4391 if (ret != GST_FLOW_OK)
4393 qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4394 moof_offset, stream);
4395 gst_buffer_unref (buf);
4399 check_update_duration (qtdemux, time);
4406 GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4411 GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4416 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4422 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4424 GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4425 GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4426 GstBuffer *mfro = NULL, *mfra = NULL;
4428 gboolean ret = FALSE;
4429 GNode *mfra_node, *tfra_node;
4430 guint64 mfra_offset = 0;
4431 guint32 fourcc, mfra_size;
4434 /* query upstream size in bytes */
4435 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4436 goto size_query_failed;
4438 /* mfro box should be at the very end of the file */
4439 flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4440 if (flow != GST_FLOW_OK)
4443 gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4445 fourcc = QT_FOURCC (mfro_map.data + 4);
4446 if (fourcc != FOURCC_mfro)
4449 GST_INFO_OBJECT (qtdemux, "Found mfro box");
4450 if (mfro_map.size < 16)
4451 goto invalid_mfro_size;
4453 mfra_size = QT_UINT32 (mfro_map.data + 12);
4454 if (mfra_size >= len)
4455 goto invalid_mfra_size;
4457 mfra_offset = len - mfra_size;
4459 GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4460 mfra_offset, mfra_size);
4462 /* now get and parse mfra box */
4463 flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4464 if (flow != GST_FLOW_OK)
4467 gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4469 mfra_node = g_node_new ((guint8 *) mfra_map.data);
4470 qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4472 tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4475 qtdemux_parse_tfra (qtdemux, tfra_node);
4476 /* iterate all siblings */
4477 tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4479 g_node_destroy (mfra_node);
4481 GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4487 if (mfro_map.memory != NULL)
4488 gst_buffer_unmap (mfro, &mfro_map);
4489 gst_buffer_unref (mfro);
4492 if (mfra_map.memory != NULL)
4493 gst_buffer_unmap (mfra, &mfra_map);
4494 gst_buffer_unref (mfra);
4501 GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4506 GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4511 GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4516 GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4522 add_offset (guint64 offset, guint64 advance)
4524 /* Avoid 64-bit overflow by clamping */
4525 if (offset > G_MAXUINT64 - advance)
4527 return offset + advance;
4530 static GstFlowReturn
4531 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4535 GstBuffer *buf = NULL;
4536 GstFlowReturn ret = GST_FLOW_OK;
4537 guint64 cur_offset = qtdemux->offset;
4540 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4541 if (G_UNLIKELY (ret != GST_FLOW_OK))
4543 gst_buffer_map (buf, &map, GST_MAP_READ);
4544 if (G_LIKELY (map.size >= 8))
4545 extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4546 gst_buffer_unmap (buf, &map);
4547 gst_buffer_unref (buf);
4549 /* maybe we already got most we needed, so only consider this eof */
4550 if (G_UNLIKELY (length == 0)) {
4551 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4552 (_("Invalid atom size.")),
4553 ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4554 GST_FOURCC_ARGS (fourcc)));
4561 /* record for later parsing when needed */
4562 if (!qtdemux->moof_offset) {
4563 qtdemux->moof_offset = qtdemux->offset;
4565 if (qtdemux_pull_mfro_mfra (qtdemux)) {
4568 qtdemux->offset += length; /* skip moof and keep going */
4570 if (qtdemux->got_moov) {
4571 GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4583 GST_LOG_OBJECT (qtdemux,
4584 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4585 GST_FOURCC_ARGS (fourcc), cur_offset);
4586 qtdemux->offset = add_offset (qtdemux->offset, length);
4591 GstBuffer *moov = NULL;
4593 if (qtdemux->got_moov) {
4594 GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4595 qtdemux->offset = add_offset (qtdemux->offset, length);
4599 ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4600 if (ret != GST_FLOW_OK)
4602 gst_buffer_map (moov, &map, GST_MAP_READ);
4604 if (length != map.size) {
4605 /* Some files have a 'moov' atom at the end of the file which contains
4606 * a terminal 'free' atom where the body of the atom is missing.
4607 * Check for, and permit, this special case.
4609 if (map.size >= 8) {
4610 guint8 *final_data = map.data + (map.size - 8);
4611 guint32 final_length = QT_UINT32 (final_data);
4612 guint32 final_fourcc = QT_FOURCC (final_data + 4);
4614 if (final_fourcc == FOURCC_free
4615 && map.size + final_length - 8 == length) {
4616 /* Ok, we've found that special case. Allocate a new buffer with
4617 * that free atom actually present. */
4618 GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4619 gst_buffer_fill (newmoov, 0, map.data, map.size);
4620 gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4621 gst_buffer_unmap (moov, &map);
4622 gst_buffer_unref (moov);
4624 gst_buffer_map (moov, &map, GST_MAP_READ);
4629 if (length != map.size) {
4630 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4631 (_("This file is incomplete and cannot be played.")),
4632 ("We got less than expected (received %" G_GSIZE_FORMAT
4633 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4634 (guint) length, cur_offset));
4635 gst_buffer_unmap (moov, &map);
4636 gst_buffer_unref (moov);
4637 ret = GST_FLOW_ERROR;
4640 qtdemux->offset += length;
4642 qtdemux_parse_moov (qtdemux, map.data, length);
4643 qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4645 qtdemux_parse_tree (qtdemux);
4646 if (qtdemux->moov_node_compressed) {
4647 g_node_destroy (qtdemux->moov_node_compressed);
4648 g_free (qtdemux->moov_node->data);
4650 qtdemux->moov_node_compressed = NULL;
4651 g_node_destroy (qtdemux->moov_node);
4652 qtdemux->moov_node = NULL;
4653 gst_buffer_unmap (moov, &map);
4654 gst_buffer_unref (moov);
4655 qtdemux->got_moov = TRUE;
4661 GstBuffer *ftyp = NULL;
4663 /* extract major brand; might come in handy for ISO vs QT issues */
4664 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4665 if (ret != GST_FLOW_OK)
4667 qtdemux->offset += length;
4668 gst_buffer_map (ftyp, &map, GST_MAP_READ);
4669 qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4670 gst_buffer_unmap (ftyp, &map);
4671 gst_buffer_unref (ftyp);
4676 GstBuffer *uuid = NULL;
4678 /* uuid are extension atoms */
4679 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4680 if (ret != GST_FLOW_OK)
4682 qtdemux->offset += length;
4683 gst_buffer_map (uuid, &map, GST_MAP_READ);
4684 qtdemux_parse_uuid (qtdemux, map.data, map.size);
4685 gst_buffer_unmap (uuid, &map);
4686 gst_buffer_unref (uuid);
4691 GstBuffer *sidx = NULL;
4692 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4693 if (ret != GST_FLOW_OK)
4695 qtdemux->offset += length;
4696 gst_buffer_map (sidx, &map, GST_MAP_READ);
4697 qtdemux_parse_sidx (qtdemux, map.data, map.size);
4698 gst_buffer_unmap (sidx, &map);
4699 gst_buffer_unref (sidx);
4704 GstBuffer *unknown = NULL;
4706 GST_LOG_OBJECT (qtdemux,
4707 "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4708 " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4710 ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4711 if (ret != GST_FLOW_OK)
4713 gst_buffer_map (unknown, &map, GST_MAP_READ);
4714 GST_MEMDUMP ("Unknown tag", map.data, map.size);
4715 gst_buffer_unmap (unknown, &map);
4716 gst_buffer_unref (unknown);
4717 qtdemux->offset += length;
4723 if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4724 /* digested all data, show what we have */
4725 qtdemux_prepare_streams (qtdemux);
4726 QTDEMUX_EXPOSE_LOCK (qtdemux);
4727 ret = qtdemux_expose_streams (qtdemux);
4728 QTDEMUX_EXPOSE_UNLOCK (qtdemux);
4730 qtdemux->state = QTDEMUX_STATE_MOVIE;
4731 GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4738 /* Seeks to the previous keyframe of the indexed stream and
4739 * aligns other streams with respect to the keyframe timestamp
4740 * of indexed stream. Only called in case of Reverse Playback
4742 static GstFlowReturn
4743 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4745 guint32 seg_idx = 0, k_index = 0;
4746 guint32 ref_seg_idx, ref_k_index;
4747 GstClockTime k_pos = 0, last_stop = 0;
4748 QtDemuxSegment *seg = NULL;
4749 QtDemuxStream *ref_str = NULL;
4750 guint64 seg_media_start_mov; /* segment media start time in mov format */
4754 /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4755 * and finally align all the other streams on that timestamp with their
4756 * respective keyframes */
4757 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4758 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4760 /* No candidate yet, take the first stream */
4766 /* So that stream has a segment, we prefer video streams */
4767 if (str->subtype == FOURCC_vide) {
4773 if (G_UNLIKELY (!ref_str)) {
4774 GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4778 if (G_UNLIKELY (!ref_str->from_sample)) {
4779 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4783 /* So that stream has been playing from from_sample to to_sample. We will
4784 * get the timestamp of the previous sample and search for a keyframe before
4785 * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4786 if (ref_str->subtype == FOURCC_vide) {
4787 k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4788 ref_str->from_sample - 1, FALSE);
4790 if (ref_str->from_sample >= 10)
4791 k_index = ref_str->from_sample - 10;
4797 ref_str->samples[k_index].timestamp +
4798 ref_str->samples[k_index].pts_offset;
4800 /* get current segment for that stream */
4801 seg = &ref_str->segments[ref_str->segment_index];
4802 /* Use segment start in original timescale for comparisons */
4803 seg_media_start_mov = seg->trak_media_start;
4805 GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4806 " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4807 k_index, target_ts, seg_media_start_mov,
4808 GST_TIME_ARGS (seg->media_start));
4810 /* Crawl back through segments to find the one containing this I frame */
4811 while (target_ts < seg_media_start_mov) {
4812 GST_DEBUG_OBJECT (qtdemux,
4813 "keyframe position (sample %u) is out of segment %u " " target %"
4814 G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4815 ref_str->segment_index, target_ts, seg_media_start_mov);
4817 if (G_UNLIKELY (!ref_str->segment_index)) {
4818 /* Reached first segment, let's consider it's EOS */
4821 ref_str->segment_index--;
4822 seg = &ref_str->segments[ref_str->segment_index];
4823 /* Use segment start in original timescale for comparisons */
4824 seg_media_start_mov = seg->trak_media_start;
4826 /* Calculate time position of the keyframe and where we should stop */
4828 QTSTREAMTIME_TO_GSTTIME (ref_str,
4829 target_ts - seg->trak_media_start) + seg->time;
4831 QTSTREAMTIME_TO_GSTTIME (ref_str,
4832 ref_str->samples[ref_str->from_sample].timestamp -
4833 seg->trak_media_start) + seg->time;
4835 GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4836 "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4837 k_index, GST_TIME_ARGS (k_pos));
4839 /* Set last_stop with the keyframe timestamp we pushed of that stream */
4840 qtdemux->segment.position = last_stop;
4841 GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4842 GST_TIME_ARGS (last_stop));
4844 if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4845 GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4849 ref_seg_idx = ref_str->segment_index;
4850 ref_k_index = k_index;
4852 /* Align them all on this */
4853 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4855 GstClockTime seg_time = 0;
4856 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
4858 /* aligning reference stream again might lead to backing up to yet another
4859 * keyframe (due to timestamp rounding issues),
4860 * potentially putting more load on downstream; so let's try to avoid */
4861 if (str == ref_str) {
4862 seg_idx = ref_seg_idx;
4863 seg = &str->segments[seg_idx];
4864 k_index = ref_k_index;
4865 GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
4866 "sample at index %d", str->track_id, ref_str->segment_index, k_index);
4868 seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4869 GST_DEBUG_OBJECT (qtdemux,
4870 "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
4871 str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
4873 /* get segment and time in the segment */
4874 seg = &str->segments[seg_idx];
4875 seg_time = k_pos - seg->time;
4877 /* get the media time in the segment.
4878 * No adjustment for empty "filler" segments */
4879 if (seg->media_start != GST_CLOCK_TIME_NONE)
4880 seg_time += seg->media_start;
4882 /* get the index of the sample with media time */
4883 index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4884 GST_DEBUG_OBJECT (qtdemux,
4885 "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
4886 GST_TIME_ARGS (seg_time), index);
4888 /* find previous keyframe */
4889 k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
4892 /* Remember until where we want to go */
4893 str->to_sample = str->from_sample - 1;
4894 /* Define our time position */
4896 str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4897 str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4898 if (seg->media_start != GST_CLOCK_TIME_NONE)
4899 str->time_position -= seg->media_start;
4901 /* Now seek back in time */
4902 gst_qtdemux_move_stream (qtdemux, str, k_index);
4903 GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
4904 GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
4905 GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4911 return GST_FLOW_EOS;
4915 * Gets the current qt segment start, stop and position for the
4916 * given time offset. This is used in update_segment()
4919 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
4920 QtDemuxStream * stream, GstClockTime offset,
4921 GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
4923 GstClockTime seg_time;
4924 GstClockTime start, stop, time;
4925 QtDemuxSegment *segment;
4927 segment = &stream->segments[stream->segment_index];
4929 /* get time in this segment */
4930 seg_time = (offset - segment->time) * segment->rate;
4932 GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4933 GST_TIME_ARGS (seg_time));
4935 if (G_UNLIKELY (seg_time > segment->duration)) {
4936 GST_LOG_OBJECT (stream->pad,
4937 "seg_time > segment->duration %" GST_TIME_FORMAT,
4938 GST_TIME_ARGS (segment->duration));
4939 seg_time = segment->duration;
4942 /* qtdemux->segment.stop is in outside-time-realm, whereas
4943 * segment->media_stop is in track-time-realm.
4945 * In order to compare the two, we need to bring segment.stop
4946 * into the track-time-realm
4948 * FIXME - does this comment still hold? Don't see any conversion here */
4950 stop = qtdemux->segment.stop;
4951 if (stop == GST_CLOCK_TIME_NONE)
4952 stop = qtdemux->segment.duration;
4953 if (stop == GST_CLOCK_TIME_NONE)
4954 stop = segment->media_stop;
4957 MIN (segment->media_stop, stop - segment->time + segment->media_start);
4959 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4960 start = segment->time + seg_time;
4962 stop = start - seg_time + segment->duration;
4963 } else if (qtdemux->segment.rate >= 0) {
4964 start = MIN (segment->media_start + seg_time, stop);
4967 if (segment->media_start >= qtdemux->segment.start) {
4968 time = segment->time;
4970 time = segment->time + (qtdemux->segment.start - segment->media_start);
4973 start = MAX (segment->media_start, qtdemux->segment.start);
4974 stop = MIN (segment->media_start + seg_time, stop);
4983 * Updates the qt segment used for the stream and pushes a new segment event
4984 * downstream on this stream's pad.
4987 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4988 gint seg_idx, GstClockTime offset, GstClockTime * _start,
4989 GstClockTime * _stop)
4991 QtDemuxSegment *segment;
4992 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
4996 /* update the current segment */
4997 stream->segment_index = seg_idx;
4999 /* get the segment */
5000 segment = &stream->segments[seg_idx];
5002 if (G_UNLIKELY (offset < segment->time)) {
5003 GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5004 GST_TIME_ARGS (segment->time));
5008 /* segment lies beyond total indicated duration */
5009 if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5010 segment->time > qtdemux->segment.duration)) {
5011 GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5012 " < segment->time %" GST_TIME_FORMAT,
5013 GST_TIME_ARGS (qtdemux->segment.duration),
5014 GST_TIME_ARGS (segment->time));
5018 gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5019 &start, &stop, &time);
5021 GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5022 " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5023 GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5025 /* combine global rate with that of the segment */
5026 rate = segment->rate * qtdemux->segment.rate;
5028 /* Copy flags from main segment */
5029 stream->segment.flags = qtdemux->segment.flags;
5031 /* update the segment values used for clipping */
5032 stream->segment.offset = qtdemux->segment.offset;
5033 stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5034 stream->segment.applied_rate = qtdemux->segment.applied_rate;
5035 stream->segment.rate = rate;
5036 stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5037 stream->cslg_shift);
5038 stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5039 stream->cslg_shift);
5040 stream->segment.time = time;
5041 stream->segment.position = stream->segment.start;
5043 GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5046 /* now prepare and send the segment */
5048 event = gst_event_new_segment (&stream->segment);
5049 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5050 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5052 gst_pad_push_event (stream->pad, event);
5053 /* assume we can send more data now */
5054 GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5055 /* clear to send tags on this pad now */
5056 gst_qtdemux_push_tags (qtdemux, stream);
5067 /* activate the given segment number @seg_idx of @stream at time @offset.
5068 * @offset is an absolute global position over all the segments.
5070 * This will push out a NEWSEGMENT event with the right values and
5071 * position the stream index to the first decodable sample before
5075 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5076 guint32 seg_idx, GstClockTime offset)
5078 QtDemuxSegment *segment;
5079 guint32 index, kf_index;
5080 GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5082 GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5083 seg_idx, GST_TIME_ARGS (offset));
5085 if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5089 segment = &stream->segments[stream->segment_index];
5091 /* in the fragmented case, we pick a fragment that starts before our
5092 * desired position and rely on downstream to wait for a keyframe
5093 * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5094 * tfra entries tells us which trun/sample the key unit is in, but we don't
5095 * make use of this additional information at the moment) */
5096 if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5097 stream->to_sample = G_MAXUINT32;
5100 /* well, it will be taken care of below */
5101 qtdemux->fragmented_seek_pending = FALSE;
5102 /* FIXME ideally the do_fragmented_seek can be done right here,
5103 * rather than at loop level
5104 * (which might even allow handling edit lists in a fragmented file) */
5107 /* We don't need to look for a sample in push-based */
5108 if (!qtdemux->pullbased)
5111 /* and move to the keyframe before the indicated media time of the
5113 if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5114 if (qtdemux->segment.rate >= 0) {
5115 index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5116 stream->to_sample = G_MAXUINT32;
5117 GST_DEBUG_OBJECT (stream->pad,
5118 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5119 GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5120 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5122 index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5123 stream->to_sample = index;
5124 GST_DEBUG_OBJECT (stream->pad,
5125 "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5126 GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5127 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5130 GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5131 "this is an empty segment");
5135 /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5136 * encountered an error and printed a message so we return appropriately */
5140 /* we're at the right spot */
5141 if (index == stream->sample_index) {
5142 GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5146 /* find keyframe of the target index */
5147 kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5150 /* indent does stupid stuff with stream->samples[].timestamp */
5152 /* if we move forwards, we don't have to go back to the previous
5153 * keyframe since we already sent that. We can also just jump to
5154 * the keyframe right before the target index if there is one. */
5155 if (index > stream->sample_index) {
5156 /* moving forwards check if we move past a keyframe */
5157 if (kf_index > stream->sample_index) {
5158 GST_DEBUG_OBJECT (stream->pad,
5159 "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5160 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5161 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5162 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5164 GST_DEBUG_OBJECT (stream->pad,
5165 "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5166 GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5167 GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5170 GST_DEBUG_OBJECT (stream->pad,
5171 "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5172 GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5173 GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5174 gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5182 /* prepare to get the current sample of @stream, getting essential values.
5184 * This function will also prepare and send the segment when needed.
5186 * Return FALSE if the stream is EOS.
5191 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5192 QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5193 GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5194 gboolean * keyframe)
5196 QtDemuxSample *sample;
5197 GstClockTime time_position;
5200 g_return_val_if_fail (stream != NULL, FALSE);
5202 time_position = stream->time_position;
5203 if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5206 seg_idx = stream->segment_index;
5207 if (G_UNLIKELY (seg_idx == -1)) {
5208 /* find segment corresponding to time_position if we are looking
5210 seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5213 /* different segment, activate it, sample_index will be set. */
5214 if (G_UNLIKELY (stream->segment_index != seg_idx))
5215 gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5217 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5218 segments[stream->segment_index]))) {
5219 QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5221 GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5222 " prepare empty sample");
5225 *pts = *dts = time_position;
5226 *duration = seg->duration - (time_position - seg->time);
5233 if (stream->sample_index == -1)
5234 stream->sample_index = 0;
5236 GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5237 stream->sample_index, stream->n_samples);
5239 if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5240 if (!qtdemux->fragmented)
5243 GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5247 GST_OBJECT_LOCK (qtdemux);
5248 flow = qtdemux_add_fragmented_samples (qtdemux);
5249 GST_OBJECT_UNLOCK (qtdemux);
5251 if (flow != GST_FLOW_OK)
5254 while (stream->sample_index >= stream->n_samples);
5257 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5258 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5259 stream->sample_index);
5263 /* now get the info for the sample we're at */
5264 sample = &stream->samples[stream->sample_index];
5266 *dts = QTSAMPLE_DTS (stream, sample);
5267 *pts = QTSAMPLE_PTS (stream, sample);
5268 *offset = sample->offset;
5269 *size = sample->size;
5270 *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5271 *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5278 stream->time_position = GST_CLOCK_TIME_NONE;
5283 /* move to the next sample in @stream.
5285 * Moves to the next segment when needed.
5288 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5290 QtDemuxSample *sample;
5291 QtDemuxSegment *segment;
5293 /* get current segment */
5294 segment = &stream->segments[stream->segment_index];
5296 if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5297 GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5301 if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5302 /* Mark the stream as EOS */
5303 GST_DEBUG_OBJECT (qtdemux,
5304 "reached max allowed sample %u, mark EOS", stream->to_sample);
5305 stream->time_position = GST_CLOCK_TIME_NONE;
5309 /* move to next sample */
5310 stream->sample_index++;
5311 stream->offset_in_sample = 0;
5313 /* reached the last sample, we need the next segment */
5314 if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5317 if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5318 GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5319 stream->sample_index);
5323 /* get next sample */
5324 sample = &stream->samples[stream->sample_index];
5326 /* see if we are past the segment */
5327 if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5330 if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5331 /* inside the segment, update time_position, looks very familiar to
5332 * GStreamer segments, doesn't it? */
5333 stream->time_position =
5334 QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5336 /* not yet in segment, time does not yet increment. This means
5337 * that we are still prerolling keyframes to the decoder so it can
5338 * decode the first sample of the segment. */
5339 stream->time_position = segment->time;
5343 /* move to the next segment */
5346 GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5348 if (stream->segment_index == stream->n_segments - 1) {
5349 /* are we at the end of the last segment, we're EOS */
5350 stream->time_position = GST_CLOCK_TIME_NONE;
5352 /* else we're only at the end of the current segment */
5353 stream->time_position = segment->stop_time;
5355 /* make sure we select a new segment */
5357 /* accumulate previous segments */
5358 if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5359 stream->accumulated_base +=
5360 (stream->segment.stop -
5361 stream->segment.start) / ABS (stream->segment.rate);
5363 stream->segment_index = -1;
5368 gst_qtdemux_sync_streams (GstQTDemux * demux)
5372 if (QTDEMUX_N_STREAMS (demux) <= 1)
5375 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5376 QtDemuxStream *stream;
5377 GstClockTime end_time;
5379 stream = QTDEMUX_NTH_STREAM (demux, i);
5384 /* TODO advance time on subtitle streams here, if any some day */
5386 /* some clips/trailers may have unbalanced streams at the end,
5387 * so send EOS on shorter stream to prevent stalling others */
5389 /* do not mess with EOS if SEGMENT seeking */
5390 if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5393 if (demux->pullbased) {
5394 /* loop mode is sample time based */
5395 if (!STREAM_IS_EOS (stream))
5398 /* push mode is byte position based */
5399 if (stream->n_samples &&
5400 stream->samples[stream->n_samples - 1].offset >= demux->offset)
5404 if (stream->sent_eos)
5407 /* only act if some gap */
5408 end_time = stream->segments[stream->n_segments - 1].stop_time;
5409 GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5410 ", stream end: %" GST_TIME_FORMAT,
5411 GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5412 if (GST_CLOCK_TIME_IS_VALID (end_time)
5413 && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5416 GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5417 GST_PAD_NAME (stream->pad));
5418 stream->sent_eos = TRUE;
5419 event = gst_event_new_eos ();
5420 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5421 gst_event_set_seqnum (event, demux->segment_seqnum);
5422 gst_pad_push_event (stream->pad, event);
5427 /* EOS and NOT_LINKED need to be combined. This means that we return:
5429 * GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5430 * GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5432 static GstFlowReturn
5433 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5436 GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5439 ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5442 ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5444 GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5448 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5449 * completely clipped
5451 * Should be used only with raw buffers */
5453 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5456 guint64 start, stop, cstart, cstop, diff;
5457 GstClockTime pts, duration;
5459 gint num_rate, denom_rate;
5464 osize = size = gst_buffer_get_size (buf);
5467 /* depending on the type, setup the clip parameters */
5468 if (stream->subtype == FOURCC_soun) {
5469 frame_size = CUR_STREAM (stream)->bytes_per_frame;
5470 num_rate = GST_SECOND;
5471 denom_rate = (gint) CUR_STREAM (stream)->rate;
5473 } else if (stream->subtype == FOURCC_vide) {
5475 num_rate = CUR_STREAM (stream)->fps_n;
5476 denom_rate = CUR_STREAM (stream)->fps_d;
5481 if (frame_size <= 0)
5482 goto bad_frame_size;
5484 /* we can only clip if we have a valid pts */
5485 pts = GST_BUFFER_PTS (buf);
5486 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5489 duration = GST_BUFFER_DURATION (buf);
5491 if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5493 gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5497 stop = start + duration;
5499 if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5500 GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5503 /* see if some clipping happened */
5504 diff = cstart - start;
5510 /* bring clipped time to samples and to bytes */
5511 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5514 GST_DEBUG_OBJECT (qtdemux,
5515 "clipping start to %" GST_TIME_FORMAT " %"
5516 G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5522 diff = stop - cstop;
5527 /* bring clipped time to samples and then to bytes */
5528 diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5530 GST_DEBUG_OBJECT (qtdemux,
5531 "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5532 " bytes", GST_TIME_ARGS (cstop), diff);
5537 if (offset != 0 || size != osize)
5538 gst_buffer_resize (buf, offset, size);
5540 GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5541 GST_BUFFER_PTS (buf) = pts;
5542 GST_BUFFER_DURATION (buf) = duration;
5546 /* dropped buffer */
5549 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5554 GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5559 GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5564 GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5565 gst_buffer_unref (buf);
5571 gst_qtdemux_align_buffer (GstQTDemux * demux,
5572 GstBuffer * buffer, gsize alignment)
5576 gst_buffer_map (buffer, &map, GST_MAP_READ);
5578 if (map.size < sizeof (guintptr)) {
5579 gst_buffer_unmap (buffer, &map);
5583 if (((guintptr) map.data) & (alignment - 1)) {
5584 GstBuffer *new_buffer;
5585 GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5587 new_buffer = gst_buffer_new_allocate (NULL,
5588 gst_buffer_get_size (buffer), ¶ms);
5590 /* Copy data "by hand", so ensure alignment is kept: */
5591 gst_buffer_fill (new_buffer, 0, map.data, map.size);
5593 gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5594 GST_DEBUG_OBJECT (demux,
5595 "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5598 gst_buffer_unmap (buffer, &map);
5599 gst_buffer_unref (buffer);
5604 gst_buffer_unmap (buffer, &map);
5609 convert_to_ccdata (const guint8 * ccpair, guint8 ccpair_size, guint field,
5615 /* We are converting from pairs to triplets */
5616 *res = ccpair_size / 2 * 3;
5617 storage = g_malloc (*res);
5618 for (i = 0; i * 2 < ccpair_size; i += 1) {
5620 storage[i * 3] = 0xfc;
5622 storage[i * 3] = 0xfd;
5623 storage[i * 3 + 1] = ccpair[i * 2];
5624 storage[i * 3 + 2] = ccpair[i * 2 + 1];
5631 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
5635 guint32 atom_length, fourcc;
5636 QtDemuxStreamStsdEntry *stsd_entry;
5638 GST_MEMDUMP ("caption atom", data, size);
5640 /* There might be multiple atoms */
5645 atom_length = QT_UINT32 (data);
5646 fourcc = QT_FOURCC (data + 4);
5647 if (G_UNLIKELY (atom_length > size || atom_length == 8))
5650 GST_DEBUG_OBJECT (stream->pad, "here");
5652 /* Check if we have somethig compatible */
5653 stsd_entry = CUR_STREAM (stream);
5654 switch (stsd_entry->fourcc) {
5656 guint8 *cdat = NULL, *cdt2 = NULL;
5657 gsize cdat_size = 0, cdt2_size = 0;
5658 /* Should be cdat or cdt2 */
5659 if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
5660 GST_WARNING_OBJECT (stream->pad,
5661 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
5662 GST_FOURCC_ARGS (fourcc));
5666 /* Convert to cc_data triplet */
5667 if (fourcc == FOURCC_cdat)
5668 cdat = convert_to_ccdata (data + 8, atom_length - 8, 1, &cdat_size);
5670 cdt2 = convert_to_ccdata (data + 8, atom_length - 8, 2, &cdt2_size);
5671 GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
5674 /* Check for another atom ? */
5675 if (size > atom_length + 8) {
5676 guint32 new_atom_length = QT_UINT32 (data + atom_length);
5677 if (size >= atom_length + new_atom_length) {
5678 fourcc = QT_FOURCC (data + atom_length + 4);
5679 if (fourcc == FOURCC_cdat) {
5682 convert_to_ccdata (data + atom_length + 8,
5683 new_atom_length - 8, 1, &cdat_size);
5685 GST_WARNING_OBJECT (stream->pad,
5686 "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5690 convert_to_ccdata (data + atom_length + 8,
5691 new_atom_length - 8, 2, &cdt2_size);
5693 GST_WARNING_OBJECT (stream->pad,
5694 "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
5699 *cclen = cdat_size + cdt2_size;
5700 res = g_malloc (*cclen);
5702 memcpy (res, cdat, cdat_size);
5704 memcpy (res + cdat_size, cdt2, cdt2_size);
5710 if (fourcc != FOURCC_ccdp) {
5711 GST_WARNING_OBJECT (stream->pad,
5712 "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
5713 GST_FOURCC_ARGS (fourcc));
5716 *cclen = atom_length - 8;
5717 res = g_memdup (data + 8, *cclen);
5720 /* Keep this here in case other closed caption formats are added */
5721 g_assert_not_reached ();
5725 GST_MEMDUMP ("Output", res, *cclen);
5730 GST_WARNING ("[cdat] atom is too small or invalid");
5734 /* the input buffer metadata must be writable,
5735 * but time/duration etc not yet set and need not be preserved */
5737 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5744 /* not many cases for now */
5745 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5746 /* send a one time dvd clut event */
5747 if (stream->pending_event && stream->pad)
5748 gst_pad_push_event (stream->pad, stream->pending_event);
5749 stream->pending_event = NULL;
5752 if (G_UNLIKELY (stream->subtype != FOURCC_text
5753 && stream->subtype != FOURCC_sbtl &&
5754 stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
5758 gst_buffer_map (buf, &map, GST_MAP_READ);
5760 /* empty buffer is sent to terminate previous subtitle */
5761 if (map.size <= 2) {
5762 gst_buffer_unmap (buf, &map);
5763 gst_buffer_unref (buf);
5766 if (stream->subtype == FOURCC_subp) {
5767 /* That's all the processing needed for subpictures */
5768 gst_buffer_unmap (buf, &map);
5772 if (stream->subtype == FOURCC_clcp) {
5775 /* For closed caption, we need to extract the information from the
5776 * [cdat],[cdt2] or [ccdp] atom */
5777 cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
5778 gst_buffer_unmap (buf, &map);
5779 gst_buffer_unref (buf);
5781 buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
5783 /* Conversion failed or there's nothing */
5789 nsize = GST_READ_UINT16_BE (map.data);
5790 nsize = MIN (nsize, map.size - 2);
5792 GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5795 /* takes care of UTF-8 validation or UTF-16 recognition,
5796 * no other encoding expected */
5797 str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5798 gst_buffer_unmap (buf, &map);
5800 gst_buffer_unref (buf);
5801 buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5803 /* this should not really happen unless the subtitle is corrupted */
5804 gst_buffer_unref (buf);
5808 /* FIXME ? convert optional subsequent style info to markup */
5813 /* Sets a buffer's attributes properly and pushes it downstream.
5814 * Also checks for additional actions and custom processing that may
5815 * need to be done first.
5817 static GstFlowReturn
5818 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5819 QtDemuxStream * stream, GstBuffer * buf,
5820 GstClockTime dts, GstClockTime pts, GstClockTime duration,
5821 gboolean keyframe, GstClockTime position, guint64 byte_position)
5823 GstFlowReturn ret = GST_FLOW_OK;
5825 /* offset the timestamps according to the edit list */
5827 if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5831 gst_buffer_map (buf, &map, GST_MAP_READ);
5832 url = g_strndup ((gchar *) map.data, map.size);
5833 gst_buffer_unmap (buf, &map);
5834 if (url != NULL && strlen (url) != 0) {
5835 /* we have RTSP redirect now */
5836 gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5837 gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5838 gst_structure_new ("redirect",
5839 "new-location", G_TYPE_STRING, url, NULL)));
5840 qtdemux->posted_redirect = TRUE;
5842 GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5848 /* position reporting */
5849 if (qtdemux->segment.rate >= 0) {
5850 qtdemux->segment.position = position;
5851 gst_qtdemux_sync_streams (qtdemux);
5854 if (G_UNLIKELY (!stream->pad)) {
5855 GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5856 gst_buffer_unref (buf);
5860 /* send out pending buffers */
5861 while (stream->buffers) {
5862 GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5864 if (G_UNLIKELY (stream->discont)) {
5865 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5866 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5867 stream->discont = FALSE;
5869 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5872 if (stream->alignment > 1)
5873 buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
5874 gst_pad_push (stream->pad, buffer);
5876 stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5879 /* we're going to modify the metadata */
5880 buf = gst_buffer_make_writable (buf);
5882 if (G_UNLIKELY (stream->need_process))
5883 buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5889 GST_BUFFER_DTS (buf) = dts;
5890 GST_BUFFER_PTS (buf) = pts;
5891 GST_BUFFER_DURATION (buf) = duration;
5892 GST_BUFFER_OFFSET (buf) = -1;
5893 GST_BUFFER_OFFSET_END (buf) = -1;
5895 if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
5896 gst_buffer_append_memory (buf,
5897 gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
5899 if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
5900 gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
5903 if (G_UNLIKELY (qtdemux->element_index)) {
5904 GstClockTime stream_time;
5907 gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5909 if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5910 GST_LOG_OBJECT (qtdemux,
5911 "adding association %" GST_TIME_FORMAT "-> %"
5912 G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5913 gst_index_add_association (qtdemux->element_index,
5915 keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5916 GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5917 GST_FORMAT_BYTES, byte_position, NULL);
5922 if (stream->need_clip)
5923 buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5925 if (G_UNLIKELY (buf == NULL))
5928 if (G_UNLIKELY (stream->discont)) {
5929 GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5930 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5931 stream->discont = FALSE;
5933 GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5937 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5938 stream->on_keyframe = FALSE;
5940 stream->on_keyframe = TRUE;
5944 GST_LOG_OBJECT (qtdemux,
5945 "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5946 ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5947 GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5948 GST_PAD_NAME (stream->pad));
5950 if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5951 GstStructure *crypto_info;
5952 QtDemuxCencSampleSetInfo *info =
5953 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5957 while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5958 GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
5959 GST_PTR_FORMAT, event);
5960 gst_pad_push_event (stream->pad, event);
5963 if (info->crypto_info == NULL) {
5964 GST_DEBUG_OBJECT (qtdemux,
5965 "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
5967 /* The end of the crypto_info array matches our n_samples position,
5968 * so count backward from there */
5969 index = stream->sample_index - stream->n_samples + info->crypto_info->len;
5970 if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5971 /* steal structure from array */
5972 crypto_info = g_ptr_array_index (info->crypto_info, index);
5973 g_ptr_array_index (info->crypto_info, index) = NULL;
5974 GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
5975 info->crypto_info->len);
5976 if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5977 GST_ERROR_OBJECT (qtdemux,
5978 "failed to attach cenc metadata to buffer");
5980 GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
5981 index, stream->sample_index);
5986 if (stream->alignment > 1)
5987 buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
5989 ret = gst_pad_push (stream->pad, buf);
5991 if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5992 /* mark position in stream, we'll need this to know when to send GAP event */
5993 stream->segment.position = pts + duration;
6000 static const QtDemuxRandomAccessEntry *
6001 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6002 GstClockTime pos, gboolean after)
6004 QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6005 guint n_entries = stream->n_ra_entries;
6008 /* we assume the table is sorted */
6009 for (i = 0; i < n_entries; ++i) {
6010 if (entries[i].ts > pos)
6014 /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6015 * probably okay to assume that the index lists the very first fragment */
6022 return &entries[i - 1];
6026 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6028 const QtDemuxRandomAccessEntry *best_entry = NULL;
6031 GST_OBJECT_LOCK (qtdemux);
6033 g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6035 /* first see if we can determine where to go to using mfra,
6036 * before we start clearing things */
6037 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6038 const QtDemuxRandomAccessEntry *entry;
6039 QtDemuxStream *stream;
6040 gboolean is_audio_or_video;
6042 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6044 if (stream->ra_entries == NULL)
6047 if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6048 is_audio_or_video = TRUE;
6050 is_audio_or_video = FALSE;
6053 gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6054 stream->time_position, !is_audio_or_video);
6056 GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6057 "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6059 stream->pending_seek = entry;
6061 /* decide position to jump to just based on audio/video tracks, not subs */
6062 if (!is_audio_or_video)
6065 if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6069 /* no luck, will handle seek otherwise */
6070 if (best_entry == NULL) {
6071 GST_OBJECT_UNLOCK (qtdemux);
6075 /* ok, now we can prepare for processing as of located moof */
6076 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6077 QtDemuxStream *stream;
6079 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6081 g_free (stream->samples);
6082 stream->samples = NULL;
6083 stream->n_samples = 0;
6084 stream->stbl_index = -1; /* no samples have yet been parsed */
6085 stream->sample_index = -1;
6087 if (stream->protection_scheme_info) {
6088 /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6089 if (stream->protection_scheme_type == FOURCC_cenc) {
6090 QtDemuxCencSampleSetInfo *info =
6091 (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6092 if (info->crypto_info) {
6093 g_ptr_array_free (info->crypto_info, TRUE);
6094 info->crypto_info = NULL;
6100 GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6101 "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6102 GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6103 best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6105 qtdemux->moof_offset = best_entry->moof_offset;
6107 qtdemux_add_fragmented_samples (qtdemux);
6109 GST_OBJECT_UNLOCK (qtdemux);
6113 static GstFlowReturn
6114 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6116 GstFlowReturn ret = GST_FLOW_OK;
6117 GstBuffer *buf = NULL;
6118 QtDemuxStream *stream, *target_stream = NULL;
6119 GstClockTime min_time;
6121 GstClockTime dts = GST_CLOCK_TIME_NONE;
6122 GstClockTime pts = GST_CLOCK_TIME_NONE;
6123 GstClockTime duration = 0;
6124 gboolean keyframe = FALSE;
6125 guint sample_size = 0;
6130 if (qtdemux->fragmented_seek_pending) {
6131 GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6132 if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6133 GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6134 qtdemux->fragmented_seek_pending = FALSE;
6136 GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6140 /* Figure out the next stream sample to output, min_time is expressed in
6141 * global time and runs over the edit list segments. */
6142 min_time = G_MAXUINT64;
6143 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6144 GstClockTime position;
6146 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6147 position = stream->time_position;
6149 /* position of -1 is EOS */
6150 if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6151 min_time = position;
6152 target_stream = stream;
6156 if (G_UNLIKELY (target_stream == NULL)) {
6157 GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6161 /* check for segment end */
6162 if (G_UNLIKELY (qtdemux->segment.stop != -1
6163 && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6164 || (qtdemux->segment.rate < 0
6165 && qtdemux->segment.start > min_time))
6166 && target_stream->on_keyframe)) {
6167 GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6168 target_stream->time_position = GST_CLOCK_TIME_NONE;
6172 /* gap events for subtitle streams */
6173 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6174 stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6175 if (stream->pad && (stream->subtype == FOURCC_subp
6176 || stream->subtype == FOURCC_text
6177 || stream->subtype == FOURCC_sbtl)) {
6178 /* send one second gap events until the stream catches up */
6179 /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6180 while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6181 GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6182 stream->segment.position + GST_SECOND < min_time) {
6184 gst_event_new_gap (stream->segment.position, GST_SECOND);
6185 gst_pad_push_event (stream->pad, gap);
6186 stream->segment.position += GST_SECOND;
6191 stream = target_stream;
6192 /* fetch info for the current sample of this stream */
6193 if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6194 &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6197 gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6198 if (stream->new_caps) {
6199 gst_qtdemux_configure_stream (qtdemux, stream);
6200 qtdemux_do_allocation (stream, qtdemux);
6203 /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6204 if (G_UNLIKELY (qtdemux->segment.
6205 flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6206 if (stream->subtype == FOURCC_vide && !keyframe) {
6207 GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6213 GST_DEBUG_OBJECT (qtdemux,
6214 "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6215 ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6216 ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6217 sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6218 GST_TIME_ARGS (duration));
6220 if (G_UNLIKELY (empty)) {
6221 /* empty segment, push a gap if there's a second or more
6222 * difference and move to the next one */
6223 if ((pts + duration - stream->segment.position) >= GST_SECOND)
6224 gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6225 stream->segment.position = pts + duration;
6229 /* hmm, empty sample, skip and move to next sample */
6230 if (G_UNLIKELY (sample_size <= 0))
6233 /* last pushed sample was out of boundary, goto next sample */
6234 if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6237 if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6240 GST_DEBUG_OBJECT (qtdemux,
6241 "size %d larger than stream max_buffer_size %d, trimming",
6242 sample_size, stream->max_buffer_size);
6244 MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6247 if (qtdemux->cenc_aux_info_offset > 0) {
6250 GstBuffer *aux_info = NULL;
6252 /* pull the data stored before the sample */
6254 gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6255 offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6256 if (G_UNLIKELY (ret != GST_FLOW_OK))
6258 gst_buffer_map (aux_info, &map, GST_MAP_READ);
6259 GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6260 gst_byte_reader_init (&br, map.data + 8, map.size);
6261 if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6262 qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6263 GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6264 gst_buffer_unmap (aux_info, &map);
6265 gst_buffer_unref (aux_info);
6266 ret = GST_FLOW_ERROR;
6269 gst_buffer_unmap (aux_info, &map);
6270 gst_buffer_unref (aux_info);
6273 GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6276 if (stream->use_allocator) {
6277 /* if we have a per-stream allocator, use it */
6278 buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6281 ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6283 if (G_UNLIKELY (ret != GST_FLOW_OK))
6286 if (size != sample_size) {
6287 pts += gst_util_uint64_scale_int (GST_SECOND,
6288 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6291 gst_util_uint64_scale_int (GST_SECOND,
6292 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6295 gst_util_uint64_scale_int (GST_SECOND,
6296 size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6299 ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6300 dts, pts, duration, keyframe, min_time, offset);
6302 if (size != sample_size) {
6303 QtDemuxSample *sample = &stream->samples[stream->sample_index];
6304 QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6306 GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6308 stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6309 if (time_position >= segment->media_start) {
6310 /* inside the segment, update time_position, looks very familiar to
6311 * GStreamer segments, doesn't it? */
6312 stream->time_position = (time_position - segment->media_start) +
6315 /* not yet in segment, time does not yet increment. This means
6316 * that we are still prerolling keyframes to the decoder so it can
6317 * decode the first sample of the segment. */
6318 stream->time_position = segment->time;
6323 ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6324 /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6325 * we have no more data for the pad to push */
6326 if (ret == GST_FLOW_EOS)
6329 stream->offset_in_sample += size;
6330 if (stream->offset_in_sample >= sample_size) {
6331 gst_qtdemux_advance_sample (qtdemux, stream);
6336 gst_qtdemux_advance_sample (qtdemux, stream);
6344 GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6350 GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6351 /* EOS will be raised if all are EOS */
6358 gst_qtdemux_loop (GstPad * pad)
6360 GstQTDemux *qtdemux;
6364 qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6366 cur_offset = qtdemux->offset;
6367 GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6368 cur_offset, qt_demux_state_string (qtdemux->state));
6370 switch (qtdemux->state) {
6371 case QTDEMUX_STATE_INITIAL:
6372 case QTDEMUX_STATE_HEADER:
6373 ret = gst_qtdemux_loop_state_header (qtdemux);
6375 case QTDEMUX_STATE_MOVIE:
6376 ret = gst_qtdemux_loop_state_movie (qtdemux);
6377 if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6378 ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6386 /* if something went wrong, pause */
6387 if (ret != GST_FLOW_OK)
6391 gst_object_unref (qtdemux);
6397 GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6398 (NULL), ("streaming stopped, invalid state"));
6399 gst_pad_pause_task (pad);
6400 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6405 const gchar *reason = gst_flow_get_name (ret);
6407 GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6409 gst_pad_pause_task (pad);
6411 /* fatal errors need special actions */
6413 if (ret == GST_FLOW_EOS) {
6414 if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
6415 /* we have no streams, post an error */
6416 gst_qtdemux_post_no_playable_stream_error (qtdemux);
6418 if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6421 if ((stop = qtdemux->segment.stop) == -1)
6422 stop = qtdemux->segment.duration;
6424 if (qtdemux->segment.rate >= 0) {
6425 GstMessage *message;
6428 GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6429 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6430 GST_FORMAT_TIME, stop);
6431 event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6432 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6433 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6434 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6436 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6437 gst_qtdemux_push_event (qtdemux, event);
6439 GstMessage *message;
6442 /* For Reverse Playback */
6443 GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6444 message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6445 GST_FORMAT_TIME, qtdemux->segment.start);
6446 event = gst_event_new_segment_done (GST_FORMAT_TIME,
6447 qtdemux->segment.start);
6448 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
6449 gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6450 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6452 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6453 gst_qtdemux_push_event (qtdemux, event);
6458 GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6459 event = gst_event_new_eos ();
6460 if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
6461 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6462 gst_qtdemux_push_event (qtdemux, event);
6464 } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6465 GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6466 gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6475 * Returns if there are samples to be played.
6478 has_next_entry (GstQTDemux * demux)
6480 QtDemuxStream *stream;
6483 GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6485 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6486 stream = QTDEMUX_NTH_STREAM (demux, i);
6488 if (stream->sample_index == -1) {
6489 stream->sample_index = 0;
6490 stream->offset_in_sample = 0;
6493 if (stream->sample_index >= stream->n_samples) {
6494 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6497 GST_DEBUG_OBJECT (demux, "Found a sample");
6501 GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6508 * Returns the size of the first entry at the current offset.
6509 * If -1, there are none (which means EOS or empty file).
6512 next_entry_size (GstQTDemux * demux)
6514 QtDemuxStream *stream, *target_stream = NULL;
6515 guint64 smalloffs = (guint64) - 1;
6516 QtDemuxSample *sample;
6519 GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6522 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6523 stream = QTDEMUX_NTH_STREAM (demux, i);
6525 if (stream->sample_index == -1) {
6526 stream->sample_index = 0;
6527 stream->offset_in_sample = 0;
6530 if (stream->sample_index >= stream->n_samples) {
6531 GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
6535 if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6536 GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6537 stream->sample_index);
6541 sample = &stream->samples[stream->sample_index];
6543 GST_LOG_OBJECT (demux,
6544 "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
6545 " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
6546 stream->sample_index, sample->offset, sample->size);
6548 if (((smalloffs == -1)
6549 || (sample->offset < smalloffs)) && (sample->size)) {
6550 smalloffs = sample->offset;
6551 target_stream = stream;
6558 GST_LOG_OBJECT (demux,
6559 "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
6560 G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
6562 stream = target_stream;
6563 sample = &stream->samples[stream->sample_index];
6565 if (sample->offset >= demux->offset) {
6566 demux->todrop = sample->offset - demux->offset;
6567 return sample->size + demux->todrop;
6570 GST_DEBUG_OBJECT (demux,
6571 "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6576 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6578 gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6580 gst_element_post_message (GST_ELEMENT_CAST (demux),
6581 gst_message_new_element (GST_OBJECT_CAST (demux),
6582 gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6586 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6591 GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6594 gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6595 GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6596 GST_SEEK_TYPE_NONE, -1);
6598 /* store seqnum to drop flush events, they don't need to reach downstream */
6599 demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6600 res = gst_pad_push_event (demux->sinkpad, event);
6601 demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
6606 /* check for seekable upstream, above and beyond a mere query */
6608 gst_qtdemux_check_seekability (GstQTDemux * demux)
6611 gboolean seekable = FALSE;
6612 gint64 start = -1, stop = -1;
6614 if (demux->upstream_size)
6617 if (demux->upstream_format_is_time)
6620 query = gst_query_new_seeking (GST_FORMAT_BYTES);
6621 if (!gst_pad_peer_query (demux->sinkpad, query)) {
6622 GST_DEBUG_OBJECT (demux, "seeking query failed");
6626 gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6628 /* try harder to query upstream size if we didn't get it the first time */
6629 if (seekable && stop == -1) {
6630 GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6631 gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6634 /* if upstream doesn't know the size, it's likely that it's not seekable in
6635 * practice even if it technically may be seekable */
6636 if (seekable && (start != 0 || stop <= start)) {
6637 GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6642 gst_query_unref (query);
6644 GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6645 G_GUINT64_FORMAT ")", seekable, start, stop);
6646 demux->upstream_seekable = seekable;
6647 demux->upstream_size = seekable ? stop : -1;
6651 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6653 g_return_if_fail (bytes <= demux->todrop);
6655 GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6656 gst_adapter_flush (demux->adapter, bytes);
6657 demux->neededbytes -= bytes;
6658 demux->offset += bytes;
6659 demux->todrop -= bytes;
6662 /* PUSH-MODE only: Send a segment, if not done already. */
6664 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6666 if (G_UNLIKELY (demux->need_segment)) {
6669 if (!demux->upstream_format_is_time) {
6670 gst_qtdemux_map_and_push_segments (demux, &demux->segment);
6672 GstEvent *segment_event;
6673 segment_event = gst_event_new_segment (&demux->segment);
6674 if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6675 gst_event_set_seqnum (segment_event, demux->segment_seqnum);
6676 gst_qtdemux_push_event (demux, segment_event);
6679 demux->need_segment = FALSE;
6681 /* clear to send tags on all streams */
6682 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6683 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6684 gst_qtdemux_push_tags (demux, stream);
6685 if (CUR_STREAM (stream)->sparse) {
6686 GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6687 gst_pad_push_event (stream->pad,
6688 gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6694 /* Used for push mode only. */
6696 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6697 QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6699 GstClockTime ts, dur;
6703 stream->segments[segment_index].duration - (pos -
6704 stream->segments[segment_index].time);
6705 stream->time_position += dur;
6707 /* Only gaps with a duration of at least one second are propagated.
6708 * Same workaround as in pull mode.
6709 * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
6710 if (dur >= GST_SECOND) {
6712 gap = gst_event_new_gap (ts, dur);
6714 GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6715 "segment: %" GST_PTR_FORMAT, gap);
6716 gst_pad_push_event (stream->pad, gap);
6720 static GstFlowReturn
6721 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6725 demux = GST_QTDEMUX (parent);
6727 GST_DEBUG_OBJECT (demux,
6728 "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6729 " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6730 G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6731 GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6732 gst_buffer_get_size (inbuf), demux->offset);
6734 if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6735 gboolean is_gap_input = FALSE;
6738 GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6740 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6741 QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
6744 /* Check if we can land back on our feet in the case where upstream is
6745 * handling the seeking/pushing of samples with gaps in between (like
6746 * in the case of trick-mode DASH for example) */
6747 if (demux->upstream_format_is_time
6748 && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6749 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6751 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
6752 GST_LOG_OBJECT (demux,
6753 "track-id #%u , checking if offset %" G_GUINT64_FORMAT
6754 " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
6756 gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6757 stream, GST_BUFFER_OFFSET (inbuf));
6759 QtDemuxSample *sample = &stream->samples[res];
6760 GST_LOG_OBJECT (demux,
6761 "Checking if sample %d from track-id %u is valid (offset:%"
6762 G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
6763 stream->track_id, sample->offset, sample->size);
6764 if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6765 GST_LOG_OBJECT (demux,
6766 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6768 is_gap_input = TRUE;
6769 /* We can go back to standard playback mode */
6770 demux->state = QTDEMUX_STATE_MOVIE;
6771 /* Remember which sample this stream is at */
6772 stream->sample_index = res;
6773 /* Finally update all push-based values to the expected values */
6774 demux->neededbytes = stream->samples[res].size;
6775 demux->offset = GST_BUFFER_OFFSET (inbuf);
6777 demux->mdatsize - demux->offset + demux->mdatoffset;
6782 if (!is_gap_input) {
6783 GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6784 /* Reset state if it's a real discont */
6785 demux->neededbytes = 16;
6786 demux->state = QTDEMUX_STATE_INITIAL;
6787 demux->offset = GST_BUFFER_OFFSET (inbuf);
6788 gst_adapter_clear (demux->adapter);
6791 /* Reverse fragmented playback, need to flush all we have before
6792 * consuming a new fragment.
6793 * The samples array have the timestamps calculated by accumulating the
6794 * durations but this won't work for reverse playback of fragments as
6795 * the timestamps of a subsequent fragment should be smaller than the
6796 * previously received one. */
6797 if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6798 gst_qtdemux_process_adapter (demux, TRUE);
6799 g_ptr_array_foreach (demux->active_streams,
6800 (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
6804 gst_adapter_push (demux->adapter, inbuf);
6806 GST_DEBUG_OBJECT (demux,
6807 "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6808 demux->neededbytes, gst_adapter_available (demux->adapter));
6810 return gst_qtdemux_process_adapter (demux, FALSE);
6813 static GstFlowReturn
6814 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6816 GstFlowReturn ret = GST_FLOW_OK;
6818 /* we never really mean to buffer that much */
6819 if (demux->neededbytes == -1) {
6823 while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6824 (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6826 #ifndef GST_DISABLE_GST_DEBUG
6828 guint64 discont_offset, distance_from_discont;
6830 discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6831 distance_from_discont =
6832 gst_adapter_distance_from_discont (demux->adapter);
6834 GST_DEBUG_OBJECT (demux,
6835 "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6836 " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6837 " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6838 demux->offset, discont_offset, distance_from_discont);
6842 switch (demux->state) {
6843 case QTDEMUX_STATE_INITIAL:{
6848 gst_qtdemux_check_seekability (demux);
6850 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6852 /* get fourcc/length, set neededbytes */
6853 extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6855 gst_adapter_unmap (demux->adapter);
6857 GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6858 "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6860 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6861 (_("This file is invalid and cannot be played.")),
6862 ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6863 GST_FOURCC_ARGS (fourcc)));
6864 ret = GST_FLOW_ERROR;
6867 if (fourcc == FOURCC_mdat) {
6868 gint next_entry = next_entry_size (demux);
6869 if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
6870 || !demux->fragmented)) {
6871 /* we have the headers, start playback */
6872 demux->state = QTDEMUX_STATE_MOVIE;
6873 demux->neededbytes = next_entry;
6874 demux->mdatleft = size;
6875 demux->mdatsize = demux->mdatleft;
6877 /* no headers yet, try to get them */
6880 guint64 old, target;
6883 old = demux->offset;
6884 target = old + size;
6886 /* try to jump over the atom with a seek */
6887 /* only bother if it seems worth doing so,
6888 * and avoids possible upstream/server problems */
6889 if (demux->upstream_seekable &&
6890 demux->upstream_size > 4 * (1 << 20)) {
6891 res = qtdemux_seek_offset (demux, target);
6893 GST_DEBUG_OBJECT (demux, "skipping seek");
6898 GST_DEBUG_OBJECT (demux, "seek success");
6899 /* remember the offset fo the first mdat so we can seek back to it
6900 * after we have the headers */
6901 if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6902 demux->first_mdat = old;
6903 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6906 /* seek worked, continue reading */
6907 demux->offset = target;
6908 demux->neededbytes = 16;
6909 demux->state = QTDEMUX_STATE_INITIAL;
6911 /* seek failed, need to buffer */
6912 demux->offset = old;
6913 GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6914 /* there may be multiple mdat (or alike) buffers */
6916 if (demux->mdatbuffer)
6917 bs = gst_buffer_get_size (demux->mdatbuffer);
6920 if (size + bs > 10 * (1 << 20))
6922 demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6923 demux->neededbytes = size;
6924 if (!demux->mdatbuffer)
6925 demux->mdatoffset = demux->offset;
6928 } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6929 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6930 (_("This file is invalid and cannot be played.")),
6931 ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6932 GST_FOURCC_ARGS (fourcc), size));
6933 ret = GST_FLOW_ERROR;
6936 /* this means we already started buffering and still no moov header,
6937 * let's continue buffering everything till we get moov */
6938 if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6939 || fourcc == FOURCC_moof))
6941 demux->neededbytes = size;
6942 demux->state = QTDEMUX_STATE_HEADER;
6946 case QTDEMUX_STATE_HEADER:{
6950 GST_DEBUG_OBJECT (demux, "In header");
6952 data = gst_adapter_map (demux->adapter, demux->neededbytes);
6954 /* parse the header */
6955 extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6957 if (fourcc == FOURCC_moov) {
6958 /* in usual fragmented setup we could try to scan for more
6959 * and end up at the the moov (after mdat) again */
6960 if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
6962 || demux->last_moov_offset == demux->offset)) {
6963 GST_DEBUG_OBJECT (demux,
6964 "Skipping moov atom as we have (this) one already");
6966 GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6968 if (demux->got_moov && demux->fragmented) {
6969 GST_DEBUG_OBJECT (demux,
6970 "Got a second moov, clean up data from old one");
6971 if (demux->moov_node_compressed) {
6972 g_node_destroy (demux->moov_node_compressed);
6973 if (demux->moov_node)
6974 g_free (demux->moov_node->data);
6976 demux->moov_node_compressed = NULL;
6977 if (demux->moov_node)
6978 g_node_destroy (demux->moov_node);
6979 demux->moov_node = NULL;
6982 demux->last_moov_offset = demux->offset;
6984 /* Update streams with new moov */
6985 gst_qtdemux_stream_concat (demux,
6986 demux->old_streams, demux->active_streams);
6988 qtdemux_parse_moov (demux, data, demux->neededbytes);
6989 qtdemux_node_dump (demux, demux->moov_node);
6990 qtdemux_parse_tree (demux);
6991 qtdemux_prepare_streams (demux);
6992 QTDEMUX_EXPOSE_LOCK (demux);
6993 qtdemux_expose_streams (demux);
6994 QTDEMUX_EXPOSE_UNLOCK (demux);
6996 demux->got_moov = TRUE;
6998 gst_qtdemux_check_send_pending_segment (demux);
7000 if (demux->moov_node_compressed) {
7001 g_node_destroy (demux->moov_node_compressed);
7002 g_free (demux->moov_node->data);
7004 demux->moov_node_compressed = NULL;
7005 g_node_destroy (demux->moov_node);
7006 demux->moov_node = NULL;
7007 GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7009 } else if (fourcc == FOURCC_moof) {
7010 if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7012 GstClockTime prev_pts;
7013 guint64 prev_offset;
7014 guint64 adapter_discont_offset, adapter_discont_dist;
7016 GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7019 * The timestamp of the moof buffer is relevant as some scenarios
7020 * won't have the initial timestamp in the atoms. Whenever a new
7021 * buffer has started, we get that buffer's PTS and use it as a base
7022 * timestamp for the trun entries.
7024 * To keep track of the current buffer timestamp and starting point
7025 * we use gst_adapter_prev_pts that gives us the PTS and the distance
7026 * from the beggining of the buffer, with the distance and demux->offset
7027 * we know if it is still the same buffer or not.
7029 prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7030 prev_offset = demux->offset - dist;
7031 if (demux->fragment_start_offset == -1
7032 || prev_offset > demux->fragment_start_offset) {
7033 demux->fragment_start_offset = prev_offset;
7034 demux->fragment_start = prev_pts;
7035 GST_DEBUG_OBJECT (demux,
7036 "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7037 GST_TIME_FORMAT, demux->fragment_start_offset,
7038 GST_TIME_ARGS (demux->fragment_start));
7041 /* We can't use prev_offset() here because this would require
7042 * upstream to set consistent and correct offsets on all buffers
7043 * since the discont. Nothing ever did that in the past and we
7044 * would break backwards compatibility here then.
7045 * Instead take the offset we had at the last discont and count
7046 * the bytes from there. This works with old code as there would
7047 * be no discont between moov and moof, and also works with
7048 * adaptivedemux which correctly sets offset and will set the
7049 * DISCONT flag accordingly when needed.
7051 * We also only do this for upstream TIME segments as otherwise
7052 * there are potential backwards compatibility problems with
7053 * seeking in PUSH mode and upstream providing inconsistent
7055 adapter_discont_offset =
7056 gst_adapter_offset_at_discont (demux->adapter);
7057 adapter_discont_dist =
7058 gst_adapter_distance_from_discont (demux->adapter);
7060 GST_DEBUG_OBJECT (demux,
7061 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7062 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7063 demux->offset, adapter_discont_offset, adapter_discont_dist);
7065 if (demux->upstream_format_is_time) {
7066 demux->moof_offset = adapter_discont_offset;
7067 if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7068 demux->moof_offset += adapter_discont_dist;
7069 if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7070 demux->moof_offset = demux->offset;
7072 demux->moof_offset = demux->offset;
7075 if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7076 demux->moof_offset, NULL)) {
7077 gst_adapter_unmap (demux->adapter);
7078 ret = GST_FLOW_ERROR;
7082 /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7083 if (demux->mss_mode && !demux->exposed) {
7084 QTDEMUX_EXPOSE_LOCK (demux);
7085 qtdemux_expose_streams (demux);
7086 QTDEMUX_EXPOSE_UNLOCK (demux);
7089 gst_qtdemux_check_send_pending_segment (demux);
7091 GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7093 } else if (fourcc == FOURCC_ftyp) {
7094 GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7095 qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7096 } else if (fourcc == FOURCC_uuid) {
7097 GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7098 qtdemux_parse_uuid (demux, data, demux->neededbytes);
7099 } else if (fourcc == FOURCC_sidx) {
7100 GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7101 qtdemux_parse_sidx (demux, data, demux->neededbytes);
7105 /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7109 /* [free] and [skip] are padding atoms */
7110 GST_DEBUG_OBJECT (demux,
7111 "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7112 GST_FOURCC_ARGS (fourcc));
7115 GST_WARNING_OBJECT (demux,
7116 "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7117 GST_FOURCC_ARGS (fourcc));
7118 /* Let's jump that one and go back to initial state */
7122 gst_adapter_unmap (demux->adapter);
7125 if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7126 gsize remaining_data_size = 0;
7128 /* the mdat was before the header */
7129 GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7130 QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7131 /* restore our adapter/offset view of things with upstream;
7132 * put preceding buffered data ahead of current moov data.
7133 * This should also handle evil mdat, moov, mdat cases and alike */
7134 gst_adapter_flush (demux->adapter, demux->neededbytes);
7136 /* Store any remaining data after the mdat for later usage */
7137 remaining_data_size = gst_adapter_available (demux->adapter);
7138 if (remaining_data_size > 0) {
7139 g_assert (demux->restoredata_buffer == NULL);
7140 demux->restoredata_buffer =
7141 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7142 demux->restoredata_offset = demux->offset + demux->neededbytes;
7143 GST_DEBUG_OBJECT (demux,
7144 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7145 G_GUINT64_FORMAT, remaining_data_size,
7146 demux->restoredata_offset);
7149 gst_adapter_push (demux->adapter, demux->mdatbuffer);
7150 demux->mdatbuffer = NULL;
7151 demux->offset = demux->mdatoffset;
7152 demux->neededbytes = next_entry_size (demux);
7153 demux->state = QTDEMUX_STATE_MOVIE;
7154 demux->mdatleft = gst_adapter_available (demux->adapter);
7155 demux->mdatsize = demux->mdatleft;
7157 GST_DEBUG_OBJECT (demux, "Carrying on normally");
7158 gst_adapter_flush (demux->adapter, demux->neededbytes);
7160 /* only go back to the mdat if there are samples to play */
7161 if (demux->got_moov && demux->first_mdat != -1
7162 && has_next_entry (demux)) {
7165 /* we need to seek back */
7166 res = qtdemux_seek_offset (demux, demux->first_mdat);
7168 demux->offset = demux->first_mdat;
7170 GST_DEBUG_OBJECT (demux, "Seek back failed");
7173 demux->offset += demux->neededbytes;
7175 demux->neededbytes = 16;
7176 demux->state = QTDEMUX_STATE_INITIAL;
7181 case QTDEMUX_STATE_BUFFER_MDAT:{
7185 GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7187 buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7188 gst_buffer_extract (buf, 0, fourcc, 4);
7189 GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7190 GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7191 if (demux->mdatbuffer)
7192 demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7194 demux->mdatbuffer = buf;
7195 demux->offset += demux->neededbytes;
7196 demux->neededbytes = 16;
7197 demux->state = QTDEMUX_STATE_INITIAL;
7198 gst_qtdemux_post_progress (demux, 1, 1);
7202 case QTDEMUX_STATE_MOVIE:{
7203 QtDemuxStream *stream = NULL;
7204 QtDemuxSample *sample;
7205 GstClockTime dts, pts, duration;
7209 GST_DEBUG_OBJECT (demux,
7210 "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7212 if (demux->fragmented) {
7213 GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7215 if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7216 /* if needed data starts within this atom,
7217 * then it should not exceed this atom */
7218 if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7219 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7220 (_("This file is invalid and cannot be played.")),
7221 ("sample data crosses atom boundary"));
7222 ret = GST_FLOW_ERROR;
7225 demux->mdatleft -= demux->neededbytes;
7227 GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7228 /* so we are dropping more than left in this atom */
7229 gst_qtdemux_drop_data (demux, demux->mdatleft);
7230 demux->mdatleft = 0;
7232 /* need to resume atom parsing so we do not miss any other pieces */
7233 demux->state = QTDEMUX_STATE_INITIAL;
7234 demux->neededbytes = 16;
7236 /* check if there was any stored post mdat data from previous buffers */
7237 if (demux->restoredata_buffer) {
7238 g_assert (gst_adapter_available (demux->adapter) == 0);
7240 gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7241 demux->restoredata_buffer = NULL;
7242 demux->offset = demux->restoredata_offset;
7249 if (demux->todrop) {
7250 if (demux->cenc_aux_info_offset > 0) {
7254 GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7255 data = gst_adapter_map (demux->adapter, demux->todrop);
7256 gst_byte_reader_init (&br, data + 8, demux->todrop);
7257 if (!qtdemux_parse_cenc_aux_info (demux,
7258 QTDEMUX_NTH_STREAM (demux, 0), &br,
7259 demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7260 GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7261 ret = GST_FLOW_ERROR;
7262 gst_adapter_unmap (demux->adapter);
7263 g_free (demux->cenc_aux_info_sizes);
7264 demux->cenc_aux_info_sizes = NULL;
7267 demux->cenc_aux_info_offset = 0;
7268 g_free (demux->cenc_aux_info_sizes);
7269 demux->cenc_aux_info_sizes = NULL;
7270 gst_adapter_unmap (demux->adapter);
7272 gst_qtdemux_drop_data (demux, demux->todrop);
7276 /* initial newsegment sent here after having added pads,
7277 * possible others in sink_event */
7278 gst_qtdemux_check_send_pending_segment (demux);
7280 /* Figure out which stream this packet belongs to */
7281 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7282 stream = QTDEMUX_NTH_STREAM (demux, i);
7283 if (stream->sample_index >= stream->n_samples) {
7284 /* reset to be checked below G_UNLIKELY (stream == NULL) */
7288 GST_LOG_OBJECT (demux,
7289 "Checking track-id %u (sample_index:%d / offset:%"
7290 G_GUINT64_FORMAT " / size:%d)", stream->track_id,
7291 stream->sample_index,
7292 stream->samples[stream->sample_index].offset,
7293 stream->samples[stream->sample_index].size);
7295 if (stream->samples[stream->sample_index].offset == demux->offset)
7299 if (G_UNLIKELY (stream == NULL))
7300 goto unknown_stream;
7302 gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7304 if (stream->new_caps) {
7305 gst_qtdemux_configure_stream (demux, stream);
7308 /* Put data in a buffer, set timestamps, caps, ... */
7309 sample = &stream->samples[stream->sample_index];
7311 if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7312 GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7313 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7315 dts = QTSAMPLE_DTS (stream, sample);
7316 pts = QTSAMPLE_PTS (stream, sample);
7317 duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7318 keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7320 /* check for segment end */
7321 if (G_UNLIKELY (demux->segment.stop != -1
7322 && demux->segment.stop <= pts && stream->on_keyframe)
7323 && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
7324 GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7325 stream->time_position = GST_CLOCK_TIME_NONE; /* this means EOS */
7327 /* skip this data, stream is EOS */
7328 gst_adapter_flush (demux->adapter, demux->neededbytes);
7329 demux->offset += demux->neededbytes;
7331 /* check if all streams are eos */
7333 for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7334 if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
7343 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7345 /* FIXME: should either be an assert or a plain check */
7346 g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7348 ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7349 dts, pts, duration, keyframe, dts, demux->offset);
7353 ret = gst_qtdemux_combine_flows (demux, stream, ret);
7355 /* skip this data, stream is EOS */
7356 gst_adapter_flush (demux->adapter, demux->neededbytes);
7359 stream->sample_index++;
7360 stream->offset_in_sample = 0;
7362 /* update current offset and figure out size of next buffer */
7363 GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7364 demux->offset, demux->neededbytes);
7365 demux->offset += demux->neededbytes;
7366 GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7370 if (ret == GST_FLOW_EOS) {
7371 GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7372 demux->neededbytes = -1;
7376 if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7377 if (demux->fragmented) {
7378 GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7379 /* there may be more to follow, only finish this atom */
7380 demux->todrop = demux->mdatleft;
7381 demux->neededbytes = demux->todrop;
7386 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7387 goto non_ok_unlinked_flow;
7396 /* when buffering movie data, at least show user something is happening */
7397 if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7398 gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7399 gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7400 demux->neededbytes);
7407 non_ok_unlinked_flow:
7409 GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7410 gst_flow_get_name (ret));
7415 GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7416 ret = GST_FLOW_ERROR;
7421 GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7427 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7428 (NULL), ("qtdemuxer invalid state %d", demux->state));
7429 ret = GST_FLOW_ERROR;
7434 GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7435 (NULL), ("no 'moov' atom within the first 10 MB"));
7436 ret = GST_FLOW_ERROR;
7442 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7447 query = gst_query_new_scheduling ();
7449 if (!gst_pad_peer_query (sinkpad, query)) {
7450 gst_query_unref (query);
7454 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7455 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7456 gst_query_unref (query);
7461 GST_DEBUG_OBJECT (sinkpad, "activating pull");
7462 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7466 GST_DEBUG_OBJECT (sinkpad, "activating push");
7467 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7472 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7473 GstPadMode mode, gboolean active)
7476 GstQTDemux *demux = GST_QTDEMUX (parent);
7479 case GST_PAD_MODE_PUSH:
7480 demux->pullbased = FALSE;
7483 case GST_PAD_MODE_PULL:
7485 demux->pullbased = TRUE;
7486 res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7489 res = gst_pad_stop_task (sinkpad);
7501 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7507 memset (&z, 0, sizeof (z));
7512 if ((ret = inflateInit (&z)) != Z_OK) {
7513 GST_ERROR ("inflateInit() returned %d", ret);
7517 z.next_in = z_buffer;
7518 z.avail_in = z_length;
7520 buffer = (guint8 *) g_malloc (*length);
7521 z.avail_out = *length;
7522 z.next_out = (Bytef *) buffer;
7524 ret = inflate (&z, Z_NO_FLUSH);
7525 if (ret == Z_STREAM_END) {
7527 } else if (ret != Z_OK) {
7528 GST_WARNING ("inflate() returned %d", ret);
7533 buffer = (guint8 *) g_realloc (buffer, *length);
7534 z.next_out = (Bytef *) (buffer + z.total_out);
7535 z.avail_out += 4096;
7536 } while (z.avail_in > 0);
7538 if (ret != Z_STREAM_END) {
7543 *length = z.total_out;
7550 #endif /* HAVE_ZLIB */
7553 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7557 qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7559 /* counts as header data */
7560 qtdemux->header_size += length;
7562 GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7563 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7565 cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7572 dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7573 cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7574 if (dcom == NULL || cmvd == NULL)
7575 goto invalid_compression;
7577 dcom_len = QT_UINT32 (dcom->data);
7579 goto invalid_compression;
7581 method = QT_FOURCC ((guint8 *) dcom->data + 8);
7585 guint uncompressed_length;
7586 guint compressed_length;
7590 cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7592 goto invalid_compression;
7594 uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7595 compressed_length = cmvd_len - 12;
7596 GST_LOG ("length = %u", uncompressed_length);
7599 (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7600 compressed_length, &uncompressed_length);
7603 qtdemux->moov_node_compressed = qtdemux->moov_node;
7604 qtdemux->moov_node = g_node_new (buf);
7606 qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7607 uncompressed_length);
7611 #endif /* HAVE_ZLIB */
7613 GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7614 "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7621 invalid_compression:
7623 GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7629 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7632 while (G_UNLIKELY (buf < end)) {
7636 if (G_UNLIKELY (buf + 4 > end)) {
7637 GST_LOG_OBJECT (qtdemux, "buffer overrun");
7640 len = QT_UINT32 (buf);
7641 if (G_UNLIKELY (len == 0)) {
7642 GST_LOG_OBJECT (qtdemux, "empty container");
7645 if (G_UNLIKELY (len < 8)) {
7646 GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7649 if (G_UNLIKELY (len > (end - buf))) {
7650 GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7651 (gint) (end - buf));
7655 child = g_node_new ((guint8 *) buf);
7656 g_node_append (node, child);
7657 GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7658 qtdemux_parse_node (qtdemux, child, buf, len);
7666 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7669 int len = QT_UINT32 (xdxt->data);
7670 guint8 *buf = xdxt->data;
7671 guint8 *end = buf + len;
7674 /* skip size and type */
7682 size = QT_UINT32 (buf);
7683 type = QT_FOURCC (buf + 4);
7685 GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7687 if (buf + size > end || size <= 0)
7693 GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7694 GST_FOURCC_ARGS (type));
7698 buffer = gst_buffer_new_and_alloc (size);
7699 gst_buffer_fill (buffer, 0, buf, size);
7700 stream->buffers = g_slist_append (stream->buffers, buffer);
7701 GST_LOG_OBJECT (qtdemux, "parsing theora header");
7704 buffer = gst_buffer_new_and_alloc (size);
7705 gst_buffer_fill (buffer, 0, buf, size);
7706 stream->buffers = g_slist_append (stream->buffers, buffer);
7707 GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7710 buffer = gst_buffer_new_and_alloc (size);
7711 gst_buffer_fill (buffer, 0, buf, size);
7712 stream->buffers = g_slist_append (stream->buffers, buffer);
7713 GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7716 GST_WARNING_OBJECT (qtdemux,
7717 "unknown theora cookie %" GST_FOURCC_FORMAT,
7718 GST_FOURCC_ARGS (type));
7727 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7731 guint32 node_length = 0;
7732 const QtNodeType *type;
7735 GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7737 if (G_UNLIKELY (length < 8))
7738 goto not_enough_data;
7740 node_length = QT_UINT32 (buffer);
7741 fourcc = QT_FOURCC (buffer + 4);
7743 /* ignore empty nodes */
7744 if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7747 type = qtdemux_type_get (fourcc);
7749 end = buffer + length;
7751 GST_LOG_OBJECT (qtdemux,
7752 "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7753 GST_FOURCC_ARGS (fourcc), node_length, type->name);
7755 if (node_length > length)
7756 goto broken_atom_size;
7758 if (type->flags & QT_FLAG_CONTAINER) {
7759 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7764 if (node_length < 20) {
7765 GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7768 GST_DEBUG_OBJECT (qtdemux,
7769 "parsing stsd (sample table, sample description) atom");
7770 /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7771 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7782 /* also read alac (or whatever) in stead of mp4a in the following,
7783 * since a similar layout is used in other cases as well */
7784 if (fourcc == FOURCC_mp4a)
7786 else if (fourcc == FOURCC_fLaC)
7791 /* There are two things we might encounter here: a true mp4a atom, and
7792 an mp4a entry in an stsd atom. The latter is what we're interested
7793 in, and it looks like an atom, but isn't really one. The true mp4a
7794 atom is short, so we detect it based on length here. */
7795 if (length < min_size) {
7796 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7797 GST_FOURCC_ARGS (fourcc));
7801 /* 'version' here is the sound sample description version. Types 0 and
7802 1 are documented in the QTFF reference, but type 2 is not: it's
7803 described in Apple header files instead (struct SoundDescriptionV2
7805 version = QT_UINT16 (buffer + 16);
7807 GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7808 GST_FOURCC_ARGS (fourcc), version);
7810 /* parse any esds descriptors */
7822 GST_WARNING_OBJECT (qtdemux,
7823 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7824 GST_FOURCC_ARGS (fourcc), version);
7829 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7855 /* codec_data is contained inside these atoms, which all have
7856 * the same format. */
7857 /* video sample description size is 86 bytes without extension.
7858 * node_length have to be bigger than 86 bytes because video sample
7859 * description can include extenstions such as esds, fiel, glbl, etc. */
7860 if (node_length < 86) {
7861 GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
7862 " sample description length too short (%u < 86)",
7863 GST_FOURCC_ARGS (fourcc), node_length);
7867 GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7868 GST_FOURCC_ARGS (fourcc));
7870 /* version (2 bytes) : this is set to 0, unless a compressor has changed
7872 * revision level (2 bytes) : must be set to 0. */
7873 version = QT_UINT32 (buffer + 16);
7874 GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7876 /* compressor name : PASCAL string and informative purposes
7877 * first byte : the number of bytes to be displayed.
7878 * it has to be less than 32 because it is reserved
7879 * space of 32 bytes total including itself. */
7880 str_len = QT_UINT8 (buffer + 50);
7882 GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
7883 (char *) buffer + 51);
7885 GST_WARNING_OBJECT (qtdemux,
7886 "compressorname length too big (%u > 31)", str_len);
7888 GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
7890 qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7895 GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7897 /* You are reading this correctly. QTFF specifies that the
7898 * metadata atom is a short atom, whereas ISO BMFF specifies
7899 * it's a full atom. But since so many people are doing things
7900 * differently, we actually peek into the atom to see which
7903 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7904 GST_FOURCC_ARGS (fourcc));
7907 if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
7908 /* Variant 1: What QTFF specifies. 'meta' is a short header which
7909 * starts with a 'hdlr' atom */
7910 qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7911 } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
7912 /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
7913 * with version/flags both set to zero */
7914 qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7916 GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
7921 GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7922 /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7923 qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7932 GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7933 GST_FOURCC_ARGS (fourcc));
7937 version = QT_UINT32 (buffer + 12);
7938 GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7945 GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7950 if (length < offset) {
7951 GST_WARNING_OBJECT (qtdemux,
7952 "skipping too small %" GST_FOURCC_FORMAT " box",
7953 GST_FOURCC_ARGS (fourcc));
7956 qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7962 qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7967 qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7972 qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7976 if (!strcmp (type->name, "unknown"))
7977 GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7981 GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7982 GST_FOURCC_ARGS (fourcc));
7988 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7989 (_("This file is corrupt and cannot be played.")),
7990 ("Not enough data for an atom header, got only %u bytes", length));
7995 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7996 (_("This file is corrupt and cannot be played.")),
7997 ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7998 "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8005 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
8009 guint32 child_fourcc;
8011 for (child = g_node_first_child (node); child;
8012 child = g_node_next_sibling (child)) {
8013 buffer = (guint8 *) child->data;
8015 child_fourcc = QT_FOURCC (buffer + 4);
8017 if (G_UNLIKELY (child_fourcc == fourcc)) {
8025 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
8026 GstByteReader * parser)
8030 guint32 child_fourcc, child_len;
8032 for (child = g_node_first_child (node); child;
8033 child = g_node_next_sibling (child)) {
8034 buffer = (guint8 *) child->data;
8036 child_len = QT_UINT32 (buffer);
8037 child_fourcc = QT_FOURCC (buffer + 4);
8039 if (G_UNLIKELY (child_fourcc == fourcc)) {
8040 if (G_UNLIKELY (child_len < (4 + 4)))
8042 /* FIXME: must verify if atom length < parent atom length */
8043 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8051 qtdemux_tree_get_child_by_index (GNode * node, guint index)
8053 return g_node_nth_child (node, index);
8057 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
8058 GstByteReader * parser)
8062 guint32 child_fourcc, child_len;
8064 for (child = g_node_next_sibling (node); child;
8065 child = g_node_next_sibling (child)) {
8066 buffer = (guint8 *) child->data;
8068 child_fourcc = QT_FOURCC (buffer + 4);
8070 if (child_fourcc == fourcc) {
8072 child_len = QT_UINT32 (buffer);
8073 if (G_UNLIKELY (child_len < (4 + 4)))
8075 /* FIXME: must verify if atom length < parent atom length */
8076 gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8085 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8087 return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8091 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8093 /* FIXME: This can only reliably work if demuxers have a
8094 * separate streaming thread per srcpad. This should be
8095 * done in a demuxer base class, which integrates parts
8098 * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8103 query = gst_query_new_allocation (stream->caps, FALSE);
8105 if (!gst_pad_peer_query (stream->pad, query)) {
8106 /* not a problem, just debug a little */
8107 GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8110 if (stream->allocator)
8111 gst_object_unref (stream->allocator);
8113 if (gst_query_get_n_allocation_params (query) > 0) {
8114 /* try the allocator */
8115 gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8117 stream->use_allocator = TRUE;
8119 stream->allocator = NULL;
8120 gst_allocation_params_init (&stream->params);
8121 stream->use_allocator = FALSE;
8123 gst_query_unref (query);
8128 pad_query (const GValue * item, GValue * value, gpointer user_data)
8130 GstPad *pad = g_value_get_object (item);
8131 GstQuery *query = user_data;
8134 res = gst_pad_peer_query (pad, query);
8137 g_value_set_boolean (value, TRUE);
8141 GST_INFO_OBJECT (pad, "pad peer query failed");
8146 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8147 GstPadDirection direction)
8150 GstIteratorFoldFunction func = pad_query;
8151 GValue res = { 0, };
8153 g_value_init (&res, G_TYPE_BOOLEAN);
8154 g_value_set_boolean (&res, FALSE);
8157 if (direction == GST_PAD_SRC)
8158 it = gst_element_iterate_src_pads (element);
8160 it = gst_element_iterate_sink_pads (element);
8162 while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8163 gst_iterator_resync (it);
8165 gst_iterator_free (it);
8167 return g_value_get_boolean (&res);
8171 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8172 QtDemuxStream * stream)
8176 GstElement *element = GST_ELEMENT (qtdemux);
8178 gchar **filtered_sys_ids;
8179 GValue event_list = G_VALUE_INIT;
8182 /* 1. Check if we already have the context. */
8183 if (qtdemux->preferred_protection_system_id != NULL) {
8184 GST_LOG_OBJECT (element,
8185 "already have the protection context, no need to request it again");
8189 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8190 filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8191 (const gchar **) qtdemux->protection_system_ids->pdata);
8193 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8194 qtdemux->protection_system_ids->len - 1);
8195 GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8196 "decryptors for %u of them, running context request",
8197 qtdemux->protection_system_ids->len,
8198 filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8201 if (stream->protection_scheme_event_queue.length) {
8202 GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8203 stream->protection_scheme_event_queue.length);
8204 walk = stream->protection_scheme_event_queue.tail;
8206 GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8207 qtdemux->protection_event_queue.length);
8208 walk = qtdemux->protection_event_queue.tail;
8211 g_value_init (&event_list, GST_TYPE_LIST);
8212 for (; walk; walk = g_list_previous (walk)) {
8213 GValue *event_value = g_new0 (GValue, 1);
8214 g_value_init (event_value, GST_TYPE_EVENT);
8215 g_value_set_boxed (event_value, walk->data);
8216 gst_value_list_append_and_take_value (&event_list, event_value);
8219 /* 2a) Query downstream with GST_QUERY_CONTEXT for the context and
8220 * check if downstream already has a context of the specific type
8221 * 2b) Query upstream as above.
8223 query = gst_query_new_context ("drm-preferred-decryption-system-id");
8224 st = gst_query_writable_structure (query);
8225 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8226 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8228 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8229 if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8230 gst_query_parse_context (query, &ctxt);
8231 GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8232 gst_element_set_context (element, ctxt);
8233 } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8234 gst_query_parse_context (query, &ctxt);
8235 GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8236 gst_element_set_context (element, ctxt);
8238 /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8239 * the required context type and afterwards check if a
8240 * usable context was set now as in 1). The message could
8241 * be handled by the parent bins of the element and the
8246 GST_INFO_OBJECT (element, "posting need context message");
8247 msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8248 "drm-preferred-decryption-system-id");
8249 st = (GstStructure *) gst_message_get_structure (msg);
8250 gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8251 "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8254 gst_structure_set_value (st, "stream-encryption-events", &event_list);
8255 gst_element_post_message (element, msg);
8258 g_strfreev (filtered_sys_ids);
8259 g_value_unset (&event_list);
8260 gst_query_unref (query);
8264 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8265 QtDemuxStream * stream)
8268 const gchar *selected_system = NULL;
8270 g_return_val_if_fail (qtdemux != NULL, FALSE);
8271 g_return_val_if_fail (stream != NULL, FALSE);
8272 g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8275 if (stream->protection_scheme_type != FOURCC_cenc) {
8276 GST_ERROR_OBJECT (qtdemux,
8277 "unsupported protection scheme: %" GST_FOURCC_FORMAT,
8278 GST_FOURCC_ARGS (stream->protection_scheme_type));
8281 if (qtdemux->protection_system_ids == NULL) {
8282 GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8283 "cenc protection system information has been found");
8287 gst_qtdemux_request_protection_context (qtdemux, stream);
8288 if (qtdemux->preferred_protection_system_id != NULL) {
8289 const gchar *preferred_system_array[] =
8290 { qtdemux->preferred_protection_system_id, NULL };
8292 selected_system = gst_protection_select_system (preferred_system_array);
8294 if (selected_system) {
8295 GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
8296 qtdemux->preferred_protection_system_id);
8298 GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
8299 "because there is no available decryptor",
8300 qtdemux->preferred_protection_system_id);
8304 if (!selected_system) {
8305 g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8306 selected_system = gst_protection_select_system ((const gchar **)
8307 qtdemux->protection_system_ids->pdata);
8308 g_ptr_array_remove_index (qtdemux->protection_system_ids,
8309 qtdemux->protection_system_ids->len - 1);
8312 if (!selected_system) {
8313 GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8314 "suitable decryptor element has been found");
8318 GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
8321 s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8322 if (!gst_structure_has_name (s, "application/x-cenc")) {
8323 gst_structure_set (s,
8324 "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8325 GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8327 gst_structure_set_name (s, "application/x-cenc");
8333 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
8335 /* fps is calculated base on the duration of the average framerate since
8336 * qt does not have a fixed framerate. */
8337 gboolean fps_available = TRUE;
8338 guint32 first_duration = 0;
8340 if (stream->n_samples > 0)
8341 first_duration = stream->samples[0].duration;
8343 if ((stream->n_samples == 1 && first_duration == 0)
8344 || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
8346 CUR_STREAM (stream)->fps_n = 0;
8347 CUR_STREAM (stream)->fps_d = 1;
8349 if (stream->duration == 0 || stream->n_samples < 2) {
8350 CUR_STREAM (stream)->fps_n = stream->timescale;
8351 CUR_STREAM (stream)->fps_d = 1;
8352 fps_available = FALSE;
8354 GstClockTime avg_duration;
8358 /* duration and n_samples can be updated for fragmented format
8359 * so, framerate of fragmented format is calculated using data in a moof */
8360 if (qtdemux->fragmented && stream->n_samples_moof > 0
8361 && stream->duration_moof > 0) {
8362 n_samples = stream->n_samples_moof;
8363 duration = stream->duration_moof;
8365 n_samples = stream->n_samples;
8366 duration = stream->duration;
8369 /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8370 /* stream->duration is guint64, timescale, n_samples are guint32 */
8372 gst_util_uint64_scale_round (duration -
8373 first_duration, GST_SECOND,
8374 (guint64) (stream->timescale) * (n_samples - 1));
8376 GST_LOG_OBJECT (qtdemux,
8377 "Calculating avg sample duration based on stream (or moof) duration %"
8379 " minus first sample %u, leaving %d samples gives %"
8380 GST_TIME_FORMAT, duration, first_duration,
8381 n_samples - 1, GST_TIME_ARGS (avg_duration));
8383 gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8384 &CUR_STREAM (stream)->fps_d);
8386 GST_DEBUG_OBJECT (qtdemux,
8387 "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8388 stream->timescale, CUR_STREAM (stream)->fps_n,
8389 CUR_STREAM (stream)->fps_d);
8393 return fps_available;
8397 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8399 if (stream->subtype == FOURCC_vide) {
8400 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8402 if (CUR_STREAM (stream)->caps) {
8403 CUR_STREAM (stream)->caps =
8404 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8406 if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
8407 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8408 "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8409 "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8411 /* set framerate if calculated framerate is reliable */
8412 if (fps_available) {
8413 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8414 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8415 CUR_STREAM (stream)->fps_d, NULL);
8418 /* calculate pixel-aspect-ratio using display width and height */
8419 GST_DEBUG_OBJECT (qtdemux,
8420 "video size %dx%d, target display size %dx%d",
8421 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8422 stream->display_width, stream->display_height);
8423 /* qt file might have pasp atom */
8424 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8425 GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8426 CUR_STREAM (stream)->par_h);
8427 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8428 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8429 CUR_STREAM (stream)->par_h, NULL);
8430 } else if (stream->display_width > 0 && stream->display_height > 0
8431 && CUR_STREAM (stream)->width > 0
8432 && CUR_STREAM (stream)->height > 0) {
8435 /* calculate the pixel aspect ratio using the display and pixel w/h */
8436 n = stream->display_width * CUR_STREAM (stream)->height;
8437 d = stream->display_height * CUR_STREAM (stream)->width;
8440 GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8441 CUR_STREAM (stream)->par_w = n;
8442 CUR_STREAM (stream)->par_h = d;
8443 gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8444 GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8445 CUR_STREAM (stream)->par_h, NULL);
8448 if (CUR_STREAM (stream)->interlace_mode > 0) {
8449 if (CUR_STREAM (stream)->interlace_mode == 1) {
8450 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8451 G_TYPE_STRING, "progressive", NULL);
8452 } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8453 gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8454 G_TYPE_STRING, "interleaved", NULL);
8455 if (CUR_STREAM (stream)->field_order == 9) {
8456 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8457 G_TYPE_STRING, "top-field-first", NULL);
8458 } else if (CUR_STREAM (stream)->field_order == 14) {
8459 gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8460 G_TYPE_STRING, "bottom-field-first", NULL);
8465 /* Create incomplete colorimetry here if needed */
8466 if (CUR_STREAM (stream)->colorimetry.range ||
8467 CUR_STREAM (stream)->colorimetry.matrix ||
8468 CUR_STREAM (stream)->colorimetry.transfer
8469 || CUR_STREAM (stream)->colorimetry.primaries) {
8470 gchar *colorimetry =
8471 gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8472 gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8473 G_TYPE_STRING, colorimetry, NULL);
8474 g_free (colorimetry);
8477 if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8478 guint par_w = 1, par_h = 1;
8480 if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8481 par_w = CUR_STREAM (stream)->par_w;
8482 par_h = CUR_STREAM (stream)->par_h;
8485 if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8486 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8488 stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8491 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8492 "multiview-mode", G_TYPE_STRING,
8493 gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8494 "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8495 stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8500 else if (stream->subtype == FOURCC_soun) {
8501 if (CUR_STREAM (stream)->caps) {
8502 CUR_STREAM (stream)->caps =
8503 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8504 if (CUR_STREAM (stream)->rate > 0)
8505 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8506 "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8507 if (CUR_STREAM (stream)->n_channels > 0)
8508 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8509 "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8510 if (CUR_STREAM (stream)->n_channels > 2) {
8511 /* FIXME: Need to parse the 'chan' atom to get channel layouts
8512 * correctly; this is just the minimum we can do - assume
8513 * we don't actually have any channel positions. */
8514 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8515 "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8520 else if (stream->subtype == FOURCC_clcp) {
8521 gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
8523 if (CUR_STREAM (stream)->caps) {
8524 CUR_STREAM (stream)->caps =
8525 gst_caps_make_writable (CUR_STREAM (stream)->caps);
8527 /* set framerate if calculated framerate is reliable */
8528 if (fps_available) {
8529 gst_caps_set_simple (CUR_STREAM (stream)->caps,
8530 "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8531 CUR_STREAM (stream)->fps_d, NULL);
8537 GstCaps *prev_caps = NULL;
8539 GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8540 gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8541 gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8542 gst_pad_set_active (stream->pad, TRUE);
8544 gst_pad_use_fixed_caps (stream->pad);
8546 if (stream->protected) {
8547 if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8548 GST_ERROR_OBJECT (qtdemux,
8549 "Failed to configure protected stream caps.");
8554 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8555 CUR_STREAM (stream)->caps);
8556 if (stream->new_stream) {
8558 GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8561 gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8564 gst_event_parse_stream_flags (event, &stream_flags);
8565 if (gst_event_parse_group_id (event, &qtdemux->group_id))
8566 qtdemux->have_group_id = TRUE;
8568 qtdemux->have_group_id = FALSE;
8569 gst_event_unref (event);
8570 } else if (!qtdemux->have_group_id) {
8571 qtdemux->have_group_id = TRUE;
8572 qtdemux->group_id = gst_util_group_id_next ();
8575 stream->new_stream = FALSE;
8576 event = gst_event_new_stream_start (stream->stream_id);
8577 if (qtdemux->have_group_id)
8578 gst_event_set_group_id (event, qtdemux->group_id);
8579 if (stream->disabled)
8580 stream_flags |= GST_STREAM_FLAG_UNSELECT;
8581 if (CUR_STREAM (stream)->sparse) {
8582 stream_flags |= GST_STREAM_FLAG_SPARSE;
8584 stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8586 gst_event_set_stream_flags (event, stream_flags);
8587 gst_pad_push_event (stream->pad, event);
8590 prev_caps = gst_pad_get_current_caps (stream->pad);
8592 if (CUR_STREAM (stream)->caps) {
8594 || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8595 GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8596 CUR_STREAM (stream)->caps);
8597 gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8599 GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8602 GST_WARNING_OBJECT (qtdemux, "stream without caps");
8606 gst_caps_unref (prev_caps);
8607 stream->new_caps = FALSE;
8613 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8614 QtDemuxStream * stream)
8616 if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8619 GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8620 stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8621 if (G_UNLIKELY (stream->stsd_sample_description_id >=
8622 stream->stsd_entries_length)) {
8623 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8624 (_("This file is invalid and cannot be played.")),
8625 ("New sample description id is out of bounds (%d >= %d)",
8626 stream->stsd_sample_description_id, stream->stsd_entries_length));
8628 stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8629 stream->new_caps = TRUE;
8634 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8635 QtDemuxStream * stream, GstTagList * list)
8637 gboolean ret = TRUE;
8639 if (stream->subtype == FOURCC_vide) {
8640 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8643 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8646 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8647 gst_object_unref (stream->pad);
8653 qtdemux->n_video_streams++;
8654 } else if (stream->subtype == FOURCC_soun) {
8655 gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8658 gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8660 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8661 gst_object_unref (stream->pad);
8666 qtdemux->n_audio_streams++;
8667 } else if (stream->subtype == FOURCC_strm) {
8668 GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8669 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8670 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
8671 || stream->subtype == FOURCC_clcp) {
8672 gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8675 gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8677 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8678 gst_object_unref (stream->pad);
8683 qtdemux->n_sub_streams++;
8684 } else if (CUR_STREAM (stream)->caps) {
8685 gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8688 gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8690 if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8691 gst_object_unref (stream->pad);
8696 qtdemux->n_video_streams++;
8698 GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8705 GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8706 GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8707 gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8708 gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8710 if (stream->stream_tags)
8711 gst_tag_list_unref (stream->stream_tags);
8712 stream->stream_tags = list;
8714 /* global tags go on each pad anyway */
8715 stream->send_global_tags = TRUE;
8716 /* send upstream GST_EVENT_PROTECTION events that were received before
8717 this source pad was created */
8718 for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8719 gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8723 gst_tag_list_unref (list);
8727 /* find next atom with @fourcc starting at @offset */
8728 static GstFlowReturn
8729 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8730 guint64 * length, guint32 fourcc)
8736 GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8737 G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8743 ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8744 if (G_UNLIKELY (ret != GST_FLOW_OK))
8746 if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8749 gst_buffer_unref (buf);
8752 gst_buffer_map (buf, &map, GST_MAP_READ);
8753 extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8754 gst_buffer_unmap (buf, &map);
8755 gst_buffer_unref (buf);
8757 if (G_UNLIKELY (*length == 0)) {
8758 GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8759 ret = GST_FLOW_ERROR;
8763 if (lfourcc == fourcc) {
8764 GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8768 GST_LOG_OBJECT (qtdemux,
8769 "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8770 GST_FOURCC_ARGS (fourcc), *offset);
8779 /* might simply have had last one */
8780 GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8785 /* should only do something in pull mode */
8786 /* call with OBJECT lock */
8787 static GstFlowReturn
8788 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8790 guint64 length, offset;
8791 GstBuffer *buf = NULL;
8792 GstFlowReturn ret = GST_FLOW_OK;
8793 GstFlowReturn res = GST_FLOW_OK;
8796 offset = qtdemux->moof_offset;
8797 GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8800 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8801 return GST_FLOW_EOS;
8804 /* best not do pull etc with lock held */
8805 GST_OBJECT_UNLOCK (qtdemux);
8807 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8808 if (ret != GST_FLOW_OK)
8811 ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8812 if (G_UNLIKELY (ret != GST_FLOW_OK))
8814 gst_buffer_map (buf, &map, GST_MAP_READ);
8815 if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8816 gst_buffer_unmap (buf, &map);
8817 gst_buffer_unref (buf);
8822 gst_buffer_unmap (buf, &map);
8823 gst_buffer_unref (buf);
8827 /* look for next moof */
8828 ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8829 if (G_UNLIKELY (ret != GST_FLOW_OK))
8833 GST_OBJECT_LOCK (qtdemux);
8835 qtdemux->moof_offset = offset;
8841 GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8843 res = GST_FLOW_ERROR;
8848 /* maybe upstream temporarily flushing */
8849 if (ret != GST_FLOW_FLUSHING) {
8850 GST_DEBUG_OBJECT (qtdemux, "no next moof");
8853 GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8854 /* resume at current position next time */
8861 /* initialise bytereaders for stbl sub-atoms */
8863 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8865 stream->stbl_index = -1; /* no samples have yet been parsed */
8866 stream->sample_index = -1;
8868 /* time-to-sample atom */
8869 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8872 /* copy atom data into a new buffer for later use */
8873 stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8875 /* skip version + flags */
8876 if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8877 !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8879 GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8881 /* make sure there's enough data */
8882 if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8883 stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8884 GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8885 stream->n_sample_times);
8886 if (!stream->n_sample_times)
8890 /* sync sample atom */
8891 stream->stps_present = FALSE;
8892 if ((stream->stss_present =
8893 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8894 &stream->stss) ? TRUE : FALSE) == TRUE) {
8895 /* copy atom data into a new buffer for later use */
8896 stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8898 /* skip version + flags */
8899 if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8900 !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8903 if (stream->n_sample_syncs) {
8904 /* make sure there's enough data */
8905 if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8909 /* partial sync sample atom */
8910 if ((stream->stps_present =
8911 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8912 &stream->stps) ? TRUE : FALSE) == TRUE) {
8913 /* copy atom data into a new buffer for later use */
8914 stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8916 /* skip version + flags */
8917 if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8918 !gst_byte_reader_get_uint32_be (&stream->stps,
8919 &stream->n_sample_partial_syncs))
8922 /* if there are no entries, the stss table contains the real
8924 if (stream->n_sample_partial_syncs) {
8925 /* make sure there's enough data */
8926 if (!qt_atom_parser_has_chunks (&stream->stps,
8927 stream->n_sample_partial_syncs, 4))
8934 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8937 /* copy atom data into a new buffer for later use */
8938 stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8940 /* skip version + flags */
8941 if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8942 !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8945 if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8948 if (!stream->n_samples)
8951 /* sample-to-chunk atom */
8952 if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8955 /* copy atom data into a new buffer for later use */
8956 stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8958 /* skip version + flags */
8959 if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8960 !gst_byte_reader_get_uint32_be (&stream->stsc,
8961 &stream->n_samples_per_chunk))
8964 GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8965 stream->n_samples_per_chunk);
8967 /* make sure there's enough data */
8968 if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8974 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8975 stream->co_size = sizeof (guint32);
8976 else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8978 stream->co_size = sizeof (guint64);
8982 /* copy atom data into a new buffer for later use */
8983 stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8985 /* skip version + flags */
8986 if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8989 /* chunks_are_samples == TRUE means treat chunks as samples */
8990 stream->chunks_are_samples = stream->sample_size
8991 && !CUR_STREAM (stream)->sampled;
8992 if (stream->chunks_are_samples) {
8993 /* treat chunks as samples */
8994 if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8997 /* skip number of entries */
8998 if (!gst_byte_reader_skip (&stream->stco, 4))
9001 /* make sure there are enough data in the stsz atom */
9002 if (!stream->sample_size) {
9003 /* different sizes for each sample */
9004 if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9009 GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9010 stream->n_samples, (guint) sizeof (QtDemuxSample),
9011 stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9013 if (stream->n_samples >=
9014 QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9015 GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9016 "be larger than %uMB (broken file?)", stream->n_samples,
9017 QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9021 g_assert (stream->samples == NULL);
9022 stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9023 if (!stream->samples) {
9024 GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9029 /* composition time-to-sample */
9030 if ((stream->ctts_present =
9031 ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9032 &stream->ctts) ? TRUE : FALSE) == TRUE) {
9033 GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9035 /* copy atom data into a new buffer for later use */
9036 stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
9038 /* skip version + flags */
9039 if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9040 || !gst_byte_reader_get_uint32_be (&stream->ctts,
9041 &stream->n_composition_times))
9044 /* make sure there's enough data */
9045 if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9049 /* This is optional, if missing we iterate the ctts */
9050 if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9051 if (!gst_byte_reader_skip (&cslg, 1 + 3)
9052 || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9053 g_free ((gpointer) cslg.data);
9057 gint32 cslg_least = 0;
9058 guint num_entries, pos;
9061 pos = gst_byte_reader_get_pos (&stream->ctts);
9062 num_entries = stream->n_composition_times;
9064 stream->cslg_shift = 0;
9066 for (i = 0; i < num_entries; i++) {
9069 gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9070 offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9071 /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9072 * slightly inaccurate PTS could be more usable than corrupted one */
9073 if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9074 GST_WARNING_OBJECT (qtdemux,
9075 "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9076 " larger than duration %" G_GUINT64_FORMAT,
9077 offset, stream->duration);
9079 stream->cslg_shift = 0;
9080 stream->ctts_present = FALSE;
9084 if (offset < cslg_least)
9085 cslg_least = offset;
9089 stream->cslg_shift = ABS (cslg_least);
9091 stream->cslg_shift = 0;
9093 /* reset the reader so we can generate sample table */
9094 gst_byte_reader_set_pos (&stream->ctts, pos);
9097 /* Ensure the cslg_shift value is consistent so we can use it
9098 * unconditionnally to produce TS and Segment */
9099 stream->cslg_shift = 0;
9106 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9107 (_("This file is corrupt and cannot be played.")), (NULL));
9112 gst_qtdemux_stbl_free (stream);
9113 if (!qtdemux->fragmented) {
9114 /* not quite good */
9115 GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9118 /* may pick up samples elsewhere */
9124 /* collect samples from the next sample to be parsed up to sample @n for @stream
9125 * by reading the info from @stbl
9127 * This code can be executed from both the streaming thread and the seeking
9128 * thread so it takes the object lock to protect itself
9131 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9134 QtDemuxSample *samples, *first, *cur, *last;
9135 guint32 n_samples_per_chunk;
9138 GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9139 GST_FOURCC_FORMAT ", pad %s",
9140 GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9141 stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9143 n_samples = stream->n_samples;
9146 goto out_of_samples;
9148 GST_OBJECT_LOCK (qtdemux);
9149 if (n <= stream->stbl_index)
9150 goto already_parsed;
9152 GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9154 if (!stream->stsz.data) {
9155 /* so we already parsed and passed all the moov samples;
9156 * onto fragmented ones */
9157 g_assert (qtdemux->fragmented);
9161 /* pointer to the sample table */
9162 samples = stream->samples;
9164 /* starts from -1, moves to the next sample index to parse */
9165 stream->stbl_index++;
9167 /* keep track of the first and last sample to fill */
9168 first = &samples[stream->stbl_index];
9171 if (!stream->chunks_are_samples) {
9172 /* set the sample sizes */
9173 if (stream->sample_size == 0) {
9174 /* different sizes for each sample */
9175 for (cur = first; cur <= last; cur++) {
9176 cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9177 GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9178 (guint) (cur - samples), cur->size);
9181 /* samples have the same size */
9182 GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9183 for (cur = first; cur <= last; cur++)
9184 cur->size = stream->sample_size;
9188 n_samples_per_chunk = stream->n_samples_per_chunk;
9191 for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9194 if (stream->stsc_chunk_index >= stream->last_chunk
9195 || stream->stsc_chunk_index < stream->first_chunk) {
9196 stream->first_chunk =
9197 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9198 stream->samples_per_chunk =
9199 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9201 stream->stsd_sample_description_id =
9202 gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9204 /* chunk numbers are counted from 1 it seems */
9205 if (G_UNLIKELY (stream->first_chunk == 0))
9208 --stream->first_chunk;
9210 /* the last chunk of each entry is calculated by taking the first chunk
9211 * of the next entry; except if there is no next, where we fake it with
9213 if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9214 stream->last_chunk = G_MAXUINT32;
9216 stream->last_chunk =
9217 gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9218 if (G_UNLIKELY (stream->last_chunk == 0))
9221 --stream->last_chunk;
9224 GST_LOG_OBJECT (qtdemux,
9225 "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9226 "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9227 stream->samples_per_chunk, stream->stsd_sample_description_id);
9229 if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9232 if (stream->last_chunk != G_MAXUINT32) {
9233 if (!qt_atom_parser_peek_sub (&stream->stco,
9234 stream->first_chunk * stream->co_size,
9235 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9240 stream->co_chunk = stream->stco;
9241 if (!gst_byte_reader_skip (&stream->co_chunk,
9242 stream->first_chunk * stream->co_size))
9246 stream->stsc_chunk_index = stream->first_chunk;
9249 last_chunk = stream->last_chunk;
9251 if (stream->chunks_are_samples) {
9252 cur = &samples[stream->stsc_chunk_index];
9254 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9257 stream->stsc_chunk_index = j;
9262 qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9265 GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9266 "%" G_GUINT64_FORMAT, j, cur->offset);
9268 if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9269 CUR_STREAM (stream)->bytes_per_frame > 0) {
9271 (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9272 CUR_STREAM (stream)->samples_per_frame *
9273 CUR_STREAM (stream)->bytes_per_frame;
9275 cur->size = stream->samples_per_chunk;
9278 GST_DEBUG_OBJECT (qtdemux,
9279 "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9280 j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9281 stream->stco_sample_index)), cur->size);
9283 cur->timestamp = stream->stco_sample_index;
9284 cur->duration = stream->samples_per_chunk;
9285 cur->keyframe = TRUE;
9288 stream->stco_sample_index += stream->samples_per_chunk;
9290 stream->stsc_chunk_index = j;
9292 for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9293 guint32 samples_per_chunk;
9294 guint64 chunk_offset;
9296 if (!stream->stsc_sample_index
9297 && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9298 &stream->chunk_offset))
9301 samples_per_chunk = stream->samples_per_chunk;
9302 chunk_offset = stream->chunk_offset;
9304 for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9305 GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9306 G_GUINT64_FORMAT " and size %d",
9307 (guint) (cur - samples), chunk_offset, cur->size);
9309 cur->offset = chunk_offset;
9310 chunk_offset += cur->size;
9313 if (G_UNLIKELY (cur > last)) {
9315 stream->stsc_sample_index = k + 1;
9316 stream->chunk_offset = chunk_offset;
9317 stream->stsc_chunk_index = j;
9321 stream->stsc_sample_index = 0;
9323 stream->stsc_chunk_index = j;
9325 stream->stsc_index++;
9328 if (stream->chunks_are_samples)
9332 guint32 n_sample_times;
9334 n_sample_times = stream->n_sample_times;
9337 for (i = stream->stts_index; i < n_sample_times; i++) {
9338 guint32 stts_samples;
9339 gint32 stts_duration;
9342 if (stream->stts_sample_index >= stream->stts_samples
9343 || !stream->stts_sample_index) {
9345 stream->stts_samples =
9346 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9347 stream->stts_duration =
9348 gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9350 GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9351 i, stream->stts_samples, stream->stts_duration);
9353 stream->stts_sample_index = 0;
9356 stts_samples = stream->stts_samples;
9357 stts_duration = stream->stts_duration;
9358 stts_time = stream->stts_time;
9360 for (j = stream->stts_sample_index; j < stts_samples; j++) {
9361 GST_DEBUG_OBJECT (qtdemux,
9362 "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9363 (guint) (cur - samples), j,
9364 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9366 cur->timestamp = stts_time;
9367 cur->duration = stts_duration;
9369 /* avoid 32-bit wrap-around,
9370 * but still mind possible 'negative' duration */
9371 stts_time += (gint64) stts_duration;
9374 if (G_UNLIKELY (cur > last)) {
9376 stream->stts_time = stts_time;
9377 stream->stts_sample_index = j + 1;
9378 if (stream->stts_sample_index >= stream->stts_samples)
9379 stream->stts_index++;
9383 stream->stts_sample_index = 0;
9384 stream->stts_time = stts_time;
9385 stream->stts_index++;
9387 /* fill up empty timestamps with the last timestamp, this can happen when
9388 * the last samples do not decode and so we don't have timestamps for them.
9389 * We however look at the last timestamp to estimate the track length so we
9390 * need something in here. */
9391 for (; cur < last; cur++) {
9392 GST_DEBUG_OBJECT (qtdemux,
9393 "fill sample %d: timestamp %" GST_TIME_FORMAT,
9394 (guint) (cur - samples),
9395 GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9396 cur->timestamp = stream->stts_time;
9402 /* sample sync, can be NULL */
9403 if (stream->stss_present == TRUE) {
9404 guint32 n_sample_syncs;
9406 n_sample_syncs = stream->n_sample_syncs;
9408 if (!n_sample_syncs) {
9409 GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9410 stream->all_keyframe = TRUE;
9412 for (i = stream->stss_index; i < n_sample_syncs; i++) {
9413 /* note that the first sample is index 1, not 0 */
9416 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9418 if (G_LIKELY (index > 0 && index <= n_samples)) {
9420 samples[index].keyframe = TRUE;
9421 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9422 /* and exit if we have enough samples */
9423 if (G_UNLIKELY (index >= n)) {
9430 stream->stss_index = i;
9433 /* stps marks partial sync frames like open GOP I-Frames */
9434 if (stream->stps_present == TRUE) {
9435 guint32 n_sample_partial_syncs;
9437 n_sample_partial_syncs = stream->n_sample_partial_syncs;
9439 /* if there are no entries, the stss table contains the real
9441 if (n_sample_partial_syncs) {
9442 for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9443 /* note that the first sample is index 1, not 0 */
9446 index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9448 if (G_LIKELY (index > 0 && index <= n_samples)) {
9450 samples[index].keyframe = TRUE;
9451 GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9452 /* and exit if we have enough samples */
9453 if (G_UNLIKELY (index >= n)) {
9460 stream->stps_index = i;
9464 /* no stss, all samples are keyframes */
9465 stream->all_keyframe = TRUE;
9466 GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9471 /* composition time to sample */
9472 if (stream->ctts_present == TRUE) {
9473 guint32 n_composition_times;
9475 gint32 ctts_soffset;
9477 /* Fill in the pts_offsets */
9479 n_composition_times = stream->n_composition_times;
9481 for (i = stream->ctts_index; i < n_composition_times; i++) {
9482 if (stream->ctts_sample_index >= stream->ctts_count
9483 || !stream->ctts_sample_index) {
9484 stream->ctts_count =
9485 gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9486 stream->ctts_soffset =
9487 gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9488 stream->ctts_sample_index = 0;
9491 ctts_count = stream->ctts_count;
9492 ctts_soffset = stream->ctts_soffset;
9494 for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9495 cur->pts_offset = ctts_soffset;
9498 if (G_UNLIKELY (cur > last)) {
9500 stream->ctts_sample_index = j + 1;
9504 stream->ctts_sample_index = 0;
9505 stream->ctts_index++;
9509 stream->stbl_index = n;
9510 /* if index has been completely parsed, free data that is no-longer needed */
9511 if (n + 1 == stream->n_samples) {
9512 gst_qtdemux_stbl_free (stream);
9513 GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9514 if (qtdemux->pullbased) {
9515 GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9516 while (n + 1 == stream->n_samples)
9517 if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9521 GST_OBJECT_UNLOCK (qtdemux);
9528 GST_LOG_OBJECT (qtdemux,
9529 "Tried to parse up to sample %u but this sample has already been parsed",
9531 /* if fragmented, there may be more */
9532 if (qtdemux->fragmented && n == stream->stbl_index)
9534 GST_OBJECT_UNLOCK (qtdemux);
9540 GST_LOG_OBJECT (qtdemux,
9541 "Tried to parse up to sample %u but there are only %u samples", n + 1,
9543 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9544 (_("This file is corrupt and cannot be played.")), (NULL));
9549 GST_OBJECT_UNLOCK (qtdemux);
9550 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9551 (_("This file is corrupt and cannot be played.")), (NULL));
9556 /* collect all segment info for @stream.
9559 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9563 /* accept edts if they contain gaps at start and there is only
9564 * one media segment */
9565 gboolean allow_pushbased_edts = TRUE;
9566 gint media_segments_count = 0;
9568 /* parse and prepare segment info from the edit list */
9569 GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9570 stream->n_segments = 0;
9571 stream->segments = NULL;
9572 if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9575 gint segment_number, entry_size;
9578 const guint8 *buffer;
9582 GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9583 if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9586 buffer = elst->data;
9588 size = QT_UINT32 (buffer);
9589 /* version, flags, n_segments */
9591 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9594 version = QT_UINT8 (buffer + 8);
9595 entry_size = (version == 1) ? 20 : 12;
9597 n_segments = QT_UINT32 (buffer + 12);
9599 if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9600 GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9604 /* we might allocate a bit too much, at least allocate 1 segment */
9605 stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9607 /* segments always start from 0 */
9611 for (segment_number = 0; segment_number < n_segments; segment_number++) {
9614 gboolean empty_edit = FALSE;
9615 QtDemuxSegment *segment;
9617 GstClockTime media_start = GST_CLOCK_TIME_NONE;
9620 media_time = QT_UINT64 (buffer + 8);
9621 duration = QT_UINT64 (buffer);
9622 if (media_time == G_MAXUINT64)
9625 media_time = QT_UINT32 (buffer + 4);
9626 duration = QT_UINT32 (buffer);
9627 if (media_time == G_MAXUINT32)
9632 media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9634 segment = &stream->segments[segment_number];
9636 /* time and duration expressed in global timescale */
9637 segment->time = stime;
9638 if (duration != 0 || empty_edit) {
9639 /* edge case: empty edits with duration=zero are treated here.
9640 * (files should not have these anyway). */
9642 /* add non scaled values so we don't cause roundoff errors */
9644 stime = QTTIME_TO_GSTTIME (qtdemux, time);
9645 segment->duration = stime - segment->time;
9647 /* zero duration does not imply media_start == media_stop
9648 * but, only specify media_start. The edit ends with the track. */
9649 stime = segment->duration = GST_CLOCK_TIME_NONE;
9650 /* Don't allow more edits after this one. */
9651 n_segments = segment_number + 1;
9653 segment->stop_time = stime;
9655 segment->trak_media_start = media_time;
9656 /* media_time expressed in stream timescale */
9658 segment->media_start = media_start;
9659 segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
9660 ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
9661 media_segments_count++;
9663 segment->media_start = GST_CLOCK_TIME_NONE;
9664 segment->media_stop = GST_CLOCK_TIME_NONE;
9666 rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9668 if (rate_int <= 1) {
9669 /* 0 is not allowed, some programs write 1 instead of the floating point
9671 GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9675 segment->rate = rate_int / 65536.0;
9678 GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9679 ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9680 " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9681 " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9682 segment_number, GST_TIME_ARGS (segment->time),
9683 GST_TIME_ARGS (segment->duration),
9684 GST_TIME_ARGS (segment->media_start), media_time,
9685 GST_TIME_ARGS (segment->media_stop),
9686 GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9688 if (segment->stop_time > qtdemux->segment.stop &&
9689 !qtdemux->upstream_format_is_time) {
9690 GST_WARNING_OBJECT (qtdemux, "Segment %d "
9691 " extends to %" GST_TIME_FORMAT
9692 " past the end of the declared movie duration %" GST_TIME_FORMAT
9693 " movie segment will be extended", segment_number,
9694 GST_TIME_ARGS (segment->stop_time),
9695 GST_TIME_ARGS (qtdemux->segment.stop));
9696 qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
9699 buffer += entry_size;
9701 GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
9702 stream->n_segments = n_segments;
9703 if (media_segments_count != 1)
9704 allow_pushbased_edts = FALSE;
9708 /* push based does not handle segments, so act accordingly here,
9709 * and warn if applicable */
9710 if (!qtdemux->pullbased && !allow_pushbased_edts) {
9711 GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9712 /* remove and use default one below, we stream like it anyway */
9713 g_free (stream->segments);
9714 stream->segments = NULL;
9715 stream->n_segments = 0;
9718 /* no segments, create one to play the complete trak */
9719 if (stream->n_segments == 0) {
9720 GstClockTime stream_duration =
9721 QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9723 if (stream->segments == NULL)
9724 stream->segments = g_new (QtDemuxSegment, 1);
9726 /* represent unknown our way */
9727 if (stream_duration == 0)
9728 stream_duration = GST_CLOCK_TIME_NONE;
9730 stream->segments[0].time = 0;
9731 stream->segments[0].stop_time = stream_duration;
9732 stream->segments[0].duration = stream_duration;
9733 stream->segments[0].media_start = 0;
9734 stream->segments[0].media_stop = stream_duration;
9735 stream->segments[0].rate = 1.0;
9736 stream->segments[0].trak_media_start = 0;
9738 GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9739 GST_TIME_ARGS (stream_duration));
9740 stream->n_segments = 1;
9741 stream->dummy_segment = TRUE;
9743 GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9749 * Parses the stsd atom of a svq3 trak looking for
9750 * the SMI and gama atoms.
9753 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9754 const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9756 const guint8 *_gamma = NULL;
9757 GstBuffer *_seqh = NULL;
9758 const guint8 *stsd_data = stsd_entry_data;
9759 guint32 length = QT_UINT32 (stsd_data);
9763 GST_WARNING_OBJECT (qtdemux, "stsd too short");
9769 version = QT_UINT16 (stsd_data);
9774 while (length > 8) {
9775 guint32 fourcc, size;
9777 size = QT_UINT32 (stsd_data);
9778 fourcc = QT_FOURCC (stsd_data + 4);
9779 data = stsd_data + 8;
9782 GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9783 "svq3 atom parsing");
9792 GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9793 " for gama atom, expected 12", size);
9798 if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9800 if (_seqh != NULL) {
9801 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9802 " found, ignoring");
9804 seqh_size = QT_UINT32 (data + 4);
9805 if (seqh_size > 0) {
9806 _seqh = gst_buffer_new_and_alloc (seqh_size);
9807 gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9814 GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9815 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9819 if (size <= length) {
9825 GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9828 GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9829 G_GUINT16_FORMAT, version);
9840 gst_buffer_unref (_seqh);
9845 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9852 * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9853 * atom that might contain a 'data' atom with the rtsp uri.
9854 * This case was reported in bug #597497, some info about
9855 * the hndl atom can be found in TN1195
9857 dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9858 GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9861 guint32 dref_num_entries = 0;
9862 if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9863 gst_byte_reader_skip (&dref, 4) &&
9864 gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9867 /* search dref entries for hndl atom */
9868 for (i = 0; i < dref_num_entries; i++) {
9869 guint32 size = 0, type;
9870 guint8 string_len = 0;
9871 if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9872 qt_atom_parser_get_fourcc (&dref, &type)) {
9873 if (type == FOURCC_hndl) {
9874 GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9876 /* skip data reference handle bytes and the
9877 * following pascal string and some extra 4
9878 * bytes I have no idea what are */
9879 if (!gst_byte_reader_skip (&dref, 4) ||
9880 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9881 !gst_byte_reader_skip (&dref, string_len + 4)) {
9882 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9886 /* iterate over the atoms to find the data atom */
9887 while (gst_byte_reader_get_remaining (&dref) >= 8) {
9891 if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9892 qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9893 if (atom_type == FOURCC_data) {
9894 const guint8 *uri_aux = NULL;
9896 /* found the data atom that might contain the rtsp uri */
9897 GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9898 "hndl atom, interpreting it as an URI");
9899 if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9901 if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9902 uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9904 GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9905 "didn't contain a rtsp address");
9907 GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9912 /* skipping to the next entry */
9913 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9916 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9923 /* skip to the next entry */
9924 if (!gst_byte_reader_skip (&dref, size - 8))
9927 GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9930 GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9936 #define AMR_NB_ALL_MODES 0x81ff
9937 #define AMR_WB_ALL_MODES 0x83ff
9939 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9941 /* The 'damr' atom is of the form:
9943 * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9944 * 32 b 8 b 16 b 8 b 8 b
9946 * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9947 * represents the highest mode used in the stream (and thus the maximum
9948 * bitrate), with a couple of special cases as seen below.
9951 /* Map of frame type ID -> bitrate */
9952 static const guint nb_bitrates[] = {
9953 4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9955 static const guint wb_bitrates[] = {
9956 6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9962 gst_buffer_map (buf, &map, GST_MAP_READ);
9964 if (map.size != 0x11) {
9965 GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9969 if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9970 GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9971 GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9975 mode_set = QT_UINT16 (map.data + 13);
9977 if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9978 max_mode = 7 + (wb ? 1 : 0);
9980 /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9981 max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9983 if (max_mode == -1) {
9984 GST_DEBUG ("No mode indication was found (mode set) = %x",
9989 gst_buffer_unmap (buf, &map);
9990 return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9993 gst_buffer_unmap (buf, &map);
9998 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9999 GstByteReader * reader, guint32 * matrix, const gchar * atom)
10002 * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10008 if (gst_byte_reader_get_remaining (reader) < 36)
10011 matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10012 matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10013 matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10014 matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10015 matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10016 matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10017 matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10018 matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10019 matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10021 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10022 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10023 matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10025 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10026 matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10028 GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10029 matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10036 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10037 QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10044 * This macro will only compare value abdegh, it expects cfi to have already
10047 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10048 (m)[3] == (d << 16) && (m)[4] == (e << 16))
10050 /* only handle the cases where the last column has standard values */
10051 if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10052 const gchar *rotation_tag = NULL;
10054 /* no rotation needed */
10055 if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10057 } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10058 rotation_tag = "rotate-90";
10059 } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10060 rotation_tag = "rotate-180";
10061 } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10062 rotation_tag = "rotate-270";
10064 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10067 GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10069 if (rotation_tag != NULL) {
10070 if (*taglist == NULL)
10071 *taglist = gst_tag_list_new_empty ();
10072 gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10073 GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10076 GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10080 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10081 * protected streams (sinf, frma, schm and schi); if the protection scheme is
10082 * Common Encryption (cenc), the function will also parse the tenc box (defined
10083 * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10084 * (typically an enc[v|a|t|s] sample entry); the function will set
10085 * @original_fmt to the fourcc of the original unencrypted stream format.
10086 * Returns TRUE if successful; FALSE otherwise. */
10088 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10089 QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10095 QtDemuxCencSampleSetInfo *info;
10097 const guint8 *tenc_data;
10099 g_return_val_if_fail (qtdemux != NULL, FALSE);
10100 g_return_val_if_fail (stream != NULL, FALSE);
10101 g_return_val_if_fail (container != NULL, FALSE);
10102 g_return_val_if_fail (original_fmt != NULL, FALSE);
10104 sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10105 if (G_UNLIKELY (!sinf)) {
10106 if (stream->protection_scheme_type == FOURCC_cenc) {
10107 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10108 "mandatory for Common Encryption");
10114 frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10115 if (G_UNLIKELY (!frma)) {
10116 GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10120 *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10121 GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10122 GST_FOURCC_ARGS (*original_fmt));
10124 schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10126 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10129 stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10130 stream->protection_scheme_version =
10131 QT_UINT32 ((const guint8 *) schm->data + 16);
10133 GST_DEBUG_OBJECT (qtdemux,
10134 "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10135 "protection_scheme_version: %#010x",
10136 GST_FOURCC_ARGS (stream->protection_scheme_type),
10137 stream->protection_scheme_version);
10139 schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10141 GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10144 if (stream->protection_scheme_type != FOURCC_cenc &&
10145 stream->protection_scheme_type != FOURCC_piff) {
10146 GST_ERROR_OBJECT (qtdemux,
10147 "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10148 GST_FOURCC_ARGS (stream->protection_scheme_type));
10152 if (G_UNLIKELY (!stream->protection_scheme_info))
10153 stream->protection_scheme_info =
10154 g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10156 info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10158 if (stream->protection_scheme_type == FOURCC_cenc) {
10159 guint32 is_encrypted;
10161 const guint8 *default_kid;
10163 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10165 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10166 "which is mandatory for Common Encryption");
10169 tenc_data = (const guint8 *) tenc->data + 12;
10170 is_encrypted = QT_UINT24 (tenc_data);
10171 iv_size = QT_UINT8 (tenc_data + 3);
10172 default_kid = (tenc_data + 4);
10173 qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10174 is_encrypted, iv_size, default_kid);
10175 } else if (stream->protection_scheme_type == FOURCC_piff) {
10177 static const guint8 piff_track_encryption_uuid[] = {
10178 0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10179 0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10182 tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10184 GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10185 "which is mandatory for Common Encryption");
10189 tenc_data = (const guint8 *) tenc->data + 8;
10190 if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10191 gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10192 GST_ERROR_OBJECT (qtdemux,
10193 "Unsupported track encryption box with uuid: %s", box_uuid);
10197 tenc_data = (const guint8 *) tenc->data + 16 + 12;
10198 gst_byte_reader_init (&br, tenc_data, 20);
10199 if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10200 GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10203 stream->protection_scheme_type = FOURCC_cenc;
10210 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10211 QtDemuxStream ** stream2)
10213 return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10216 /* parse the traks.
10217 * With each track we associate a new QtDemuxStream that contains all the info
10219 * traks that do not decode to something (like strm traks) will not have a pad.
10222 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10224 GstByteReader tkhd;
10239 QtDemuxStream *stream = NULL;
10240 const guint8 *stsd_data;
10241 const guint8 *stsd_entry_data;
10242 guint remaining_stsd_len;
10243 guint stsd_entry_count;
10245 guint16 lang_code; /* quicktime lang code or packed iso code */
10247 guint32 tkhd_flags = 0;
10248 guint8 tkhd_version = 0;
10249 guint32 w = 0, h = 0;
10250 guint value_size, stsd_len, len;
10254 GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10256 if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10257 || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10258 || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10261 /* pick between 64 or 32 bits */
10262 value_size = tkhd_version == 1 ? 8 : 4;
10263 if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10264 !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10267 /* Check if current moov has duplicated track_id */
10268 if (qtdemux_find_stream (qtdemux, track_id))
10269 goto existing_stream;
10271 stream = _create_stream (qtdemux, track_id);
10272 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10274 /* need defaults for fragments */
10275 qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10277 if ((tkhd_flags & 1) == 0)
10278 stream->disabled = TRUE;
10280 GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10281 tkhd_version, tkhd_flags, stream->track_id);
10283 if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10286 if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10287 /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10288 if (qtdemux->major_brand != FOURCC_mjp2 ||
10289 !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10293 len = QT_UINT32 ((guint8 *) mdhd->data);
10294 version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10295 GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10296 if (version == 0x01000000) {
10299 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10300 stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10301 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10305 stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10306 stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10307 lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10310 if (lang_code < 0x400) {
10311 qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10312 } else if (lang_code == 0x7fff) {
10313 stream->lang_id[0] = 0; /* unspecified */
10315 stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10316 stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10317 stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10318 stream->lang_id[3] = 0;
10321 GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10322 stream->timescale);
10323 GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10325 GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10326 lang_code, stream->lang_id);
10328 if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10331 if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10332 /* chapters track reference */
10333 GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10335 gsize length = GST_READ_UINT32_BE (chap->data);
10336 if (qtdemux->chapters_track_id)
10337 GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10339 if (length >= 12) {
10340 qtdemux->chapters_track_id =
10341 GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10346 /* fragmented files may have bogus duration in moov */
10347 if (!qtdemux->fragmented &&
10348 qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10349 guint64 tdur1, tdur2;
10351 /* don't overflow */
10352 tdur1 = stream->timescale * (guint64) qtdemux->duration;
10353 tdur2 = qtdemux->timescale * (guint64) stream->duration;
10356 * some of those trailers, nowadays, have prologue images that are
10357 * themselves video tracks as well. I haven't really found a way to
10358 * identify those yet, except for just looking at their duration. */
10359 if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10360 GST_WARNING_OBJECT (qtdemux,
10361 "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10362 " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10363 "found, assuming preview image or something; skipping track",
10364 stream->duration, stream->timescale, qtdemux->duration,
10365 qtdemux->timescale);
10366 gst_qtdemux_stream_unref (stream);
10371 if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10374 GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10375 GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10377 len = QT_UINT32 ((guint8 *) hdlr->data);
10379 stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10380 GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10381 GST_FOURCC_ARGS (stream->subtype));
10383 if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10386 if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10389 /*parse svmi header if existing */
10390 svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10392 len = QT_UINT32 ((guint8 *) svmi->data);
10393 version = QT_UINT32 ((guint8 *) svmi->data + 8);
10395 GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10396 GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10397 guint8 frame_type, frame_layout;
10399 /* MPEG-A stereo video */
10400 if (qtdemux->major_brand == FOURCC_ss02)
10401 flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10403 frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10404 frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10405 switch (frame_type) {
10407 mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10410 mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10413 mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10416 /* mode 3 is primary/secondary view sequence, ie
10417 * left/right views in separate tracks. See section 7.2
10418 * of ISO/IEC 23000-11:2009 */
10419 GST_FIXME_OBJECT (qtdemux,
10420 "Implement stereo video in separate streams");
10423 if ((frame_layout & 0x1) == 0)
10424 flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10426 GST_LOG_OBJECT (qtdemux,
10427 "StereoVideo: composition type: %u, is_left_first: %u",
10428 frame_type, frame_layout);
10429 stream->multiview_mode = mode;
10430 stream->multiview_flags = flags;
10434 /* parse rest of tkhd */
10435 if (stream->subtype == FOURCC_vide) {
10438 /* version 1 uses some 64-bit ints */
10439 if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10442 if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10445 if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10446 || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10449 qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10450 &stream->stream_tags);
10454 if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10456 stsd_data = (const guint8 *) stsd->data;
10458 /* stsd should at least have one entry */
10459 stsd_len = QT_UINT32 (stsd_data);
10460 if (stsd_len < 24) {
10461 /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10462 if (stream->subtype == FOURCC_vivo) {
10463 gst_qtdemux_stream_unref (stream);
10470 stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10471 stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10472 GST_LOG_OBJECT (qtdemux, "stsd len: %d", stsd_len);
10473 GST_LOG_OBJECT (qtdemux, "stsd entry count: %u", stsd_entry_count);
10475 stsd_entry_data = stsd_data + 16;
10476 remaining_stsd_len = stsd_len - 16;
10477 for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10479 gchar *codec = NULL;
10480 QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10482 /* and that entry should fit within stsd */
10483 len = QT_UINT32 (stsd_entry_data);
10484 if (len > remaining_stsd_len)
10487 entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10488 GST_LOG_OBJECT (qtdemux, "stsd type: %" GST_FOURCC_FORMAT,
10489 GST_FOURCC_ARGS (entry->fourcc));
10490 GST_LOG_OBJECT (qtdemux, "stsd type len: %d", len);
10492 if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10493 goto error_encrypted;
10495 if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10496 /* FIXME this looks wrong, there might be multiple children
10497 * with the same type */
10498 GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10499 stream->protected = TRUE;
10500 if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10501 GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10504 if (stream->subtype == FOURCC_vide) {
10509 gint depth, palette_size, palette_count;
10510 guint32 *palette_data = NULL;
10512 entry->sampled = TRUE;
10514 stream->display_width = w >> 16;
10515 stream->display_height = h >> 16;
10518 if (len < 86) /* TODO verify */
10521 entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10522 entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10523 entry->fps_n = 0; /* this is filled in later */
10524 entry->fps_d = 0; /* this is filled in later */
10525 entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10526 entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10528 /* if color_table_id is 0, ctab atom must follow; however some files
10529 * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10530 * if color table is not present we'll correct the value */
10531 if (entry->color_table_id == 0 &&
10533 || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10534 entry->color_table_id = -1;
10537 GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10538 entry->width, entry->height, entry->bits_per_sample,
10539 entry->color_table_id);
10541 depth = entry->bits_per_sample;
10543 /* more than 32 bits means grayscale */
10544 gray = (depth > 32);
10545 /* low 32 bits specify the depth */
10548 /* different number of palette entries is determined by depth. */
10550 if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10551 palette_count = (1 << depth);
10552 palette_size = palette_count * 4;
10554 if (entry->color_table_id) {
10555 switch (palette_count) {
10559 palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10562 palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10567 g_memdup (ff_qt_grayscale_palette_16, palette_size);
10569 palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10574 g_memdup (ff_qt_grayscale_palette_256, palette_size);
10576 palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10579 GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10580 (_("The video in this file might not play correctly.")),
10581 ("unsupported palette depth %d", depth));
10585 gint i, j, start, end;
10591 start = QT_UINT32 (stsd_entry_data + offset + 70);
10592 palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10593 end = QT_UINT16 (stsd_entry_data + offset + 76);
10595 GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10596 start, end, palette_count);
10603 if (len < 94 + (end - start) * 8)
10606 /* palette is always the same size */
10607 palette_data = g_malloc0 (256 * 4);
10608 palette_size = 256 * 4;
10610 for (j = 0, i = start; i <= end; j++, i++) {
10611 guint32 a, r, g, b;
10613 a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10614 r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10615 g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10616 b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10618 palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10619 (g & 0xff00) | (b >> 8);
10624 gst_caps_unref (entry->caps);
10627 qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10629 if (G_UNLIKELY (!entry->caps)) {
10630 g_free (palette_data);
10631 goto unknown_stream;
10635 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10636 GST_TAG_VIDEO_CODEC, codec, NULL);
10641 if (palette_data) {
10644 if (entry->rgb8_palette)
10645 gst_memory_unref (entry->rgb8_palette);
10646 entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10647 palette_data, palette_size, 0, palette_size, palette_data, g_free);
10649 s = gst_caps_get_structure (entry->caps, 0);
10651 /* non-raw video has a palette_data property. raw video has the palette as
10652 * an extra plane that we append to the output buffers before we push
10654 if (!gst_structure_has_name (s, "video/x-raw")) {
10655 GstBuffer *palette;
10657 palette = gst_buffer_new ();
10658 gst_buffer_append_memory (palette, entry->rgb8_palette);
10659 entry->rgb8_palette = NULL;
10661 gst_caps_set_simple (entry->caps, "palette_data",
10662 GST_TYPE_BUFFER, palette, NULL);
10663 gst_buffer_unref (palette);
10665 } else if (palette_count != 0) {
10666 GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10667 (NULL), ("Unsupported palette depth %d", depth));
10670 GST_LOG_OBJECT (qtdemux, "frame count: %u",
10671 QT_UINT16 (stsd_entry_data + offset + 32));
10677 /* pick 'the' stsd child */
10678 mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10679 if (!stream->protected) {
10680 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10684 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10690 esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10691 pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10692 colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10693 fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10697 const guint8 *pasp_data = (const guint8 *) pasp->data;
10698 gint len = QT_UINT32 (pasp_data);
10701 CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10702 CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10704 CUR_STREAM (stream)->par_w = 0;
10705 CUR_STREAM (stream)->par_h = 0;
10708 CUR_STREAM (stream)->par_w = 0;
10709 CUR_STREAM (stream)->par_h = 0;
10713 const guint8 *fiel_data = (const guint8 *) fiel->data;
10714 gint len = QT_UINT32 (fiel_data);
10717 CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10718 CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10723 const guint8 *colr_data = (const guint8 *) colr->data;
10724 gint len = QT_UINT32 (colr_data);
10726 if (len == 19 || len == 18) {
10727 guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10729 if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10730 guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10731 guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10732 guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10733 gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10735 switch (primaries) {
10737 CUR_STREAM (stream)->colorimetry.primaries =
10738 GST_VIDEO_COLOR_PRIMARIES_BT709;
10741 CUR_STREAM (stream)->colorimetry.primaries =
10742 GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10745 CUR_STREAM (stream)->colorimetry.primaries =
10746 GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10749 CUR_STREAM (stream)->colorimetry.primaries =
10750 GST_VIDEO_COLOR_PRIMARIES_BT2020;
10756 switch (transfer_function) {
10758 CUR_STREAM (stream)->colorimetry.transfer =
10759 GST_VIDEO_TRANSFER_BT709;
10762 CUR_STREAM (stream)->colorimetry.transfer =
10763 GST_VIDEO_TRANSFER_SMPTE240M;
10771 CUR_STREAM (stream)->colorimetry.matrix =
10772 GST_VIDEO_COLOR_MATRIX_BT709;
10775 CUR_STREAM (stream)->colorimetry.matrix =
10776 GST_VIDEO_COLOR_MATRIX_BT601;
10779 CUR_STREAM (stream)->colorimetry.matrix =
10780 GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10783 CUR_STREAM (stream)->colorimetry.matrix =
10784 GST_VIDEO_COLOR_MATRIX_BT2020;
10790 CUR_STREAM (stream)->colorimetry.range =
10791 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10792 GST_VIDEO_COLOR_RANGE_16_235;
10794 GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10797 GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10802 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10803 stream->stream_tags);
10810 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10811 const guint8 *avc_data = stsd_entry_data + 0x56;
10814 while (len >= 0x8) {
10817 if (QT_UINT32 (avc_data) <= len)
10818 size = QT_UINT32 (avc_data) - 0x8;
10823 /* No real data, so break out */
10826 switch (QT_FOURCC (avc_data + 0x4)) {
10829 /* parse, if found */
10832 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10834 /* First 4 bytes are the length of the atom, the next 4 bytes
10835 * are the fourcc, the next 1 byte is the version, and the
10836 * subsequent bytes are profile_tier_level structure like data. */
10837 gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10838 avc_data + 8 + 1, size - 1);
10839 buf = gst_buffer_new_and_alloc (size);
10840 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10841 gst_caps_set_simple (entry->caps,
10842 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10843 gst_buffer_unref (buf);
10851 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10853 /* First 4 bytes are the length of the atom, the next 4 bytes
10854 * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10855 * next 1 byte is the version, and the
10856 * subsequent bytes are sequence parameter set like data. */
10858 size -= 40; /* we'll be skipping BITMAPINFOHEADER */
10860 gst_codec_utils_h264_caps_set_level_and_profile
10861 (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10863 buf = gst_buffer_new_and_alloc (size);
10864 gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10865 gst_caps_set_simple (entry->caps,
10866 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10867 gst_buffer_unref (buf);
10873 guint avg_bitrate, max_bitrate;
10875 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10879 max_bitrate = QT_UINT32 (avc_data + 0xc);
10880 avg_bitrate = QT_UINT32 (avc_data + 0x10);
10882 if (!max_bitrate && !avg_bitrate)
10885 /* Some muxers seem to swap the average and maximum bitrates
10886 * (I'm looking at you, YouTube), so we swap for sanity. */
10887 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10888 guint temp = avg_bitrate;
10890 avg_bitrate = max_bitrate;
10891 max_bitrate = temp;
10894 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10895 gst_tag_list_add (stream->stream_tags,
10896 GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10897 max_bitrate, NULL);
10899 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10900 gst_tag_list_add (stream->stream_tags,
10901 GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10913 avc_data += size + 8;
10922 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10923 const guint8 *hevc_data = stsd_entry_data + 0x56;
10926 while (len >= 0x8) {
10929 if (QT_UINT32 (hevc_data) <= len)
10930 size = QT_UINT32 (hevc_data) - 0x8;
10935 /* No real data, so break out */
10938 switch (QT_FOURCC (hevc_data + 0x4)) {
10941 /* parse, if found */
10944 GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
10946 /* First 4 bytes are the length of the atom, the next 4 bytes
10947 * are the fourcc, the next 1 byte is the version, and the
10948 * subsequent bytes are sequence parameter set like data. */
10949 gst_codec_utils_h265_caps_set_level_tier_and_profile
10950 (entry->caps, hevc_data + 8 + 1, size - 1);
10952 buf = gst_buffer_new_and_alloc (size);
10953 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10954 gst_caps_set_simple (entry->caps,
10955 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10956 gst_buffer_unref (buf);
10963 hevc_data += size + 8;
10976 GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10977 GST_FOURCC_ARGS (fourcc));
10979 /* codec data might be in glbl extension atom */
10981 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10987 GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10989 len = QT_UINT32 (data);
10992 buf = gst_buffer_new_and_alloc (len);
10993 gst_buffer_fill (buf, 0, data + 8, len);
10994 gst_caps_set_simple (entry->caps,
10995 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10996 gst_buffer_unref (buf);
11003 /* see annex I of the jpeg2000 spec */
11004 GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11005 const guint8 *data;
11006 const gchar *colorspace = NULL;
11008 guint32 ncomp_map = 0;
11009 gint32 *comp_map = NULL;
11010 guint32 nchan_def = 0;
11011 gint32 *chan_def = NULL;
11013 GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11014 /* some required atoms */
11015 mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11018 jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11022 /* number of components; redundant with info in codestream, but useful
11024 ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11025 if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11027 ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11029 colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11032 GST_DEBUG_OBJECT (qtdemux, "found colr");
11033 /* extract colour space info */
11034 if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11035 switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11037 colorspace = "sRGB";
11040 colorspace = "GRAY";
11043 colorspace = "sYUV";
11051 /* colr is required, and only values 16, 17, and 18 are specified,
11052 so error if we have no colorspace */
11055 /* extract component mapping */
11056 cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11058 guint32 cmap_len = 0;
11060 cmap_len = QT_UINT32 (cmap->data);
11061 if (cmap_len >= 8) {
11062 /* normal box, subtract off header */
11064 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11065 if (cmap_len % 4 == 0) {
11066 ncomp_map = (cmap_len / 4);
11067 comp_map = g_new0 (gint32, ncomp_map);
11068 for (i = 0; i < ncomp_map; i++) {
11071 cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11072 mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11073 pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11074 comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11079 /* extract channel definitions */
11080 cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11082 guint32 cdef_len = 0;
11084 cdef_len = QT_UINT32 (cdef->data);
11085 if (cdef_len >= 10) {
11086 /* normal box, subtract off header and len */
11088 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11089 if (cdef_len % 6 == 0) {
11090 nchan_def = (cdef_len / 6);
11091 chan_def = g_new0 (gint32, nchan_def);
11092 for (i = 0; i < nchan_def; i++)
11094 for (i = 0; i < nchan_def; i++) {
11095 guint16 cn, typ, asoc;
11096 cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11097 typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11098 asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11099 if (cn < nchan_def) {
11102 chan_def[cn] = asoc;
11105 chan_def[cn] = 0; /* alpha */
11108 chan_def[cn] = -typ;
11116 gst_caps_set_simple (entry->caps,
11117 "num-components", G_TYPE_INT, ncomp, NULL);
11118 gst_caps_set_simple (entry->caps,
11119 "colorspace", G_TYPE_STRING, colorspace, NULL);
11122 GValue arr = { 0, };
11123 GValue elt = { 0, };
11125 g_value_init (&arr, GST_TYPE_ARRAY);
11126 g_value_init (&elt, G_TYPE_INT);
11127 for (i = 0; i < ncomp_map; i++) {
11128 g_value_set_int (&elt, comp_map[i]);
11129 gst_value_array_append_value (&arr, &elt);
11131 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11132 "component-map", &arr);
11133 g_value_unset (&elt);
11134 g_value_unset (&arr);
11139 GValue arr = { 0, };
11140 GValue elt = { 0, };
11142 g_value_init (&arr, GST_TYPE_ARRAY);
11143 g_value_init (&elt, G_TYPE_INT);
11144 for (i = 0; i < nchan_def; i++) {
11145 g_value_set_int (&elt, chan_def[i]);
11146 gst_value_array_append_value (&arr, &elt);
11148 gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11149 "channel-definitions", &arr);
11150 g_value_unset (&elt);
11151 g_value_unset (&arr);
11155 /* some optional atoms */
11156 field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11157 prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11159 /* indicate possible fields in caps */
11161 data = (guint8 *) field->data + 8;
11163 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11164 (gint) * data, NULL);
11166 /* add codec_data if provided */
11171 GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11172 data = prefix->data;
11173 len = QT_UINT32 (data);
11176 buf = gst_buffer_new_and_alloc (len);
11177 gst_buffer_fill (buf, 0, data + 8, len);
11178 gst_caps_set_simple (entry->caps,
11179 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11180 gst_buffer_unref (buf);
11189 GstBuffer *seqh = NULL;
11190 const guint8 *gamma_data = NULL;
11191 gint len = QT_UINT32 (stsd_data); /* FIXME review - why put the whole stsd in codec data? */
11193 qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11196 gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11197 QT_FP32 (gamma_data), NULL);
11200 /* sorry for the bad name, but we don't know what this is, other
11201 * than its own fourcc */
11202 gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11204 gst_buffer_unref (seqh);
11207 GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11208 buf = gst_buffer_new_and_alloc (len);
11209 gst_buffer_fill (buf, 0, stsd_data, len);
11210 gst_caps_set_simple (entry->caps,
11211 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11212 gst_buffer_unref (buf);
11217 /* https://developer.apple.com/standards/qtff-2001.pdf,
11218 * page 92, "Video Sample Description", under table 3.1 */
11221 const gint compressor_offset =
11222 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11223 const gint min_size = compressor_offset + 32 + 2 + 2;
11226 guint16 color_table_id = 0;
11229 GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11231 /* recover information on interlaced/progressive */
11232 jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11236 len = QT_UINT32 (jpeg->data);
11237 GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11239 if (len >= min_size) {
11240 gst_byte_reader_init (&br, jpeg->data, len);
11242 gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11243 gst_byte_reader_get_uint16_le (&br, &color_table_id);
11244 if (color_table_id != 0) {
11245 /* the spec says there can be concatenated chunks in the data, and we want
11246 * to find one called field. Walk through them. */
11247 gint offset = min_size;
11248 while (offset + 8 < len) {
11249 guint32 size = 0, tag;
11250 ok = gst_byte_reader_get_uint32_le (&br, &size);
11251 ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11252 if (!ok || size < 8) {
11253 GST_WARNING_OBJECT (qtdemux,
11254 "Failed to walk optional chunk list");
11257 GST_DEBUG_OBJECT (qtdemux,
11258 "Found optional %4.4s chunk, size %u",
11259 (const char *) &tag, size);
11260 if (tag == FOURCC_fiel) {
11261 guint8 n_fields = 0, ordering = 0;
11262 gst_byte_reader_get_uint8 (&br, &n_fields);
11263 gst_byte_reader_get_uint8 (&br, &ordering);
11264 if (n_fields == 1 || n_fields == 2) {
11265 GST_DEBUG_OBJECT (qtdemux,
11266 "Found fiel tag with %u fields, ordering %u",
11267 n_fields, ordering);
11269 gst_caps_set_simple (CUR_STREAM (stream)->caps,
11270 "interlace-mode", G_TYPE_STRING, "interleaved",
11273 GST_WARNING_OBJECT (qtdemux,
11274 "Found fiel tag with invalid fields (%u)", n_fields);
11280 GST_DEBUG_OBJECT (qtdemux,
11281 "Color table ID is 0, not trying to get interlacedness");
11284 GST_WARNING_OBJECT (qtdemux,
11285 "Length of jpeg chunk is too small, not trying to get interlacedness");
11293 gst_caps_set_simple (entry->caps,
11294 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11300 GNode *xith, *xdxt;
11302 GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11303 xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11307 xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11311 GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11312 /* collect the headers and store them in a stream list so that we can
11313 * send them out first */
11314 qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11324 GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11325 ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11328 ovc1_data = ovc1->data;
11329 ovc1_len = QT_UINT32 (ovc1_data);
11330 if (ovc1_len <= 198) {
11331 GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11334 buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11335 gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11336 gst_caps_set_simple (entry->caps,
11337 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11338 gst_buffer_unref (buf);
11343 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11344 const guint8 *vc1_data = stsd_entry_data + 0x56;
11350 if (QT_UINT32 (vc1_data) <= len)
11351 size = QT_UINT32 (vc1_data) - 8;
11356 /* No real data, so break out */
11359 switch (QT_FOURCC (vc1_data + 0x4)) {
11360 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11364 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11365 buf = gst_buffer_new_and_alloc (size);
11366 gst_buffer_fill (buf, 0, vc1_data + 8, size);
11367 gst_caps_set_simple (entry->caps,
11368 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11369 gst_buffer_unref (buf);
11376 vc1_data += size + 8;
11382 gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11383 const guint8 *av1_data = stsd_entry_data + 0x56;
11386 while (len >= 0x8) {
11389 if (QT_UINT32 (av1_data) <= len)
11390 size = QT_UINT32 (av1_data) - 0x8;
11395 /* No real data, so break out */
11398 switch (QT_FOURCC (av1_data + 0x4)) {
11401 /* parse, if found */
11403 guint8 pres_delay_field;
11405 GST_DEBUG_OBJECT (qtdemux,
11406 "found av1C codec_data in stsd of size %d", size);
11408 /* not enough data, just ignore and hope for the best */
11413 * 4 bytes: atom length
11418 * 1 bits: initial_presentation_delay_present
11419 * 4 bits: initial_presentation_delay (if present else reserved
11423 if (av1_data[9] != 0) {
11424 GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
11428 /* We skip initial_presentation_delay* for now */
11429 pres_delay_field = *(av1_data + 12);
11430 if (pres_delay_field & (1 << 5)) {
11431 gst_caps_set_simple (entry->caps,
11432 "presentation-delay", G_TYPE_INT,
11433 (gint) (pres_delay_field & 0x0F) + 1, NULL);
11436 buf = gst_buffer_new_and_alloc (size - 5);
11437 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
11438 gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
11439 gst_caps_set_simple (entry->caps,
11440 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11441 gst_buffer_unref (buf);
11450 av1_data += size + 8;
11460 GST_INFO_OBJECT (qtdemux,
11461 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11462 GST_FOURCC_ARGS (fourcc), entry->caps);
11464 } else if (stream->subtype == FOURCC_soun) {
11466 int version, samplesize;
11467 guint16 compression_id;
11468 gboolean amrwb = FALSE;
11471 /* sample description entry (16) + sound sample description v0 (20) */
11475 version = QT_UINT32 (stsd_entry_data + offset);
11476 entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11477 samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11478 compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11479 entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11481 GST_LOG_OBJECT (qtdemux, "version/rev: %08x", version);
11482 GST_LOG_OBJECT (qtdemux, "vendor: %08x",
11483 QT_UINT32 (stsd_entry_data + offset + 4));
11484 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11485 GST_LOG_OBJECT (qtdemux, "sample_size: %d", samplesize);
11486 GST_LOG_OBJECT (qtdemux, "compression_id: %d", compression_id);
11487 GST_LOG_OBJECT (qtdemux, "packet size: %d",
11488 QT_UINT16 (stsd_entry_data + offset + 14));
11489 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11491 if (compression_id == 0xfffe)
11492 entry->sampled = TRUE;
11494 /* first assume uncompressed audio */
11495 entry->bytes_per_sample = samplesize / 8;
11496 entry->samples_per_frame = entry->n_channels;
11497 entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11498 entry->samples_per_packet = entry->samples_per_frame;
11499 entry->bytes_per_packet = entry->bytes_per_sample;
11503 /* Yes, these have to be hard-coded */
11506 entry->samples_per_packet = 6;
11507 entry->bytes_per_packet = 1;
11508 entry->bytes_per_frame = 1 * entry->n_channels;
11509 entry->bytes_per_sample = 1;
11510 entry->samples_per_frame = 6 * entry->n_channels;
11515 entry->samples_per_packet = 3;
11516 entry->bytes_per_packet = 1;
11517 entry->bytes_per_frame = 1 * entry->n_channels;
11518 entry->bytes_per_sample = 1;
11519 entry->samples_per_frame = 3 * entry->n_channels;
11524 entry->samples_per_packet = 64;
11525 entry->bytes_per_packet = 34;
11526 entry->bytes_per_frame = 34 * entry->n_channels;
11527 entry->bytes_per_sample = 2;
11528 entry->samples_per_frame = 64 * entry->n_channels;
11534 entry->samples_per_packet = 1;
11535 entry->bytes_per_packet = 1;
11536 entry->bytes_per_frame = 1 * entry->n_channels;
11537 entry->bytes_per_sample = 1;
11538 entry->samples_per_frame = 1 * entry->n_channels;
11543 entry->samples_per_packet = 160;
11544 entry->bytes_per_packet = 33;
11545 entry->bytes_per_frame = 33 * entry->n_channels;
11546 entry->bytes_per_sample = 2;
11547 entry->samples_per_frame = 160 * entry->n_channels;
11554 if (version == 0x00010000) {
11555 /* sample description entry (16) + sound sample description v1 (20+16) */
11567 /* only parse extra decoding config for non-pcm audio */
11568 entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11569 entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11570 entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11571 entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11573 GST_LOG_OBJECT (qtdemux, "samples/packet: %d",
11574 entry->samples_per_packet);
11575 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11576 entry->bytes_per_packet);
11577 GST_LOG_OBJECT (qtdemux, "bytes/frame: %d",
11578 entry->bytes_per_frame);
11579 GST_LOG_OBJECT (qtdemux, "bytes/sample: %d",
11580 entry->bytes_per_sample);
11582 if (!entry->sampled && entry->bytes_per_packet) {
11583 entry->samples_per_frame = (entry->bytes_per_frame /
11584 entry->bytes_per_packet) * entry->samples_per_packet;
11585 GST_LOG_OBJECT (qtdemux, "samples/frame: %d",
11586 entry->samples_per_frame);
11591 } else if (version == 0x00020000) {
11598 /* sample description entry (16) + sound sample description v2 (56) */
11602 qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11603 entry->rate = qtfp.fp;
11604 entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11606 GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11607 GST_LOG_OBJECT (qtdemux, "sample rate: %g", entry->rate);
11608 GST_LOG_OBJECT (qtdemux, "n_channels: %d", entry->n_channels);
11609 GST_LOG_OBJECT (qtdemux, "bits/channel: %d",
11610 QT_UINT32 (stsd_entry_data + offset + 20));
11611 GST_LOG_OBJECT (qtdemux, "format flags: %X",
11612 QT_UINT32 (stsd_entry_data + offset + 24));
11613 GST_LOG_OBJECT (qtdemux, "bytes/packet: %d",
11614 QT_UINT32 (stsd_entry_data + offset + 28));
11615 GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11616 QT_UINT32 (stsd_entry_data + offset + 32));
11617 } else if (version != 0x00000) {
11618 GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11623 gst_caps_unref (entry->caps);
11625 entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11626 stsd_entry_data + 32, len - 16, &codec);
11634 in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11636 enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11638 wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11640 enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11643 int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11644 gst_caps_set_simple (entry->caps,
11645 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11652 const guint8 *owma_data;
11653 const gchar *codec_name = NULL;
11657 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11658 /* FIXME this should also be gst_riff_strf_auds,
11659 * but the latter one is actually missing bits-per-sample :( */
11664 gint32 nSamplesPerSec;
11665 gint32 nAvgBytesPerSec;
11666 gint16 nBlockAlign;
11667 gint16 wBitsPerSample;
11670 WAVEFORMATEX *wfex;
11672 GST_DEBUG_OBJECT (qtdemux, "parse owma");
11673 owma_data = stsd_entry_data;
11674 owma_len = QT_UINT32 (owma_data);
11675 if (owma_len <= 54) {
11676 GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11679 wfex = (WAVEFORMATEX *) (owma_data + 36);
11680 buf = gst_buffer_new_and_alloc (owma_len - 54);
11681 gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11682 if (wfex->wFormatTag == 0x0161) {
11683 codec_name = "Windows Media Audio";
11685 } else if (wfex->wFormatTag == 0x0162) {
11686 codec_name = "Windows Media Audio 9 Pro";
11688 } else if (wfex->wFormatTag == 0x0163) {
11689 codec_name = "Windows Media Audio 9 Lossless";
11690 /* is that correct? gstffmpegcodecmap.c is missing it, but
11691 * fluendo codec seems to support it */
11695 gst_caps_set_simple (entry->caps,
11696 "codec_data", GST_TYPE_BUFFER, buf,
11697 "wmaversion", G_TYPE_INT, version,
11698 "block_align", G_TYPE_INT,
11699 GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11700 GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11701 GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11702 GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11703 gst_buffer_unref (buf);
11707 codec = g_strdup (codec_name);
11713 gint len = QT_UINT32 (stsd_entry_data) - offset;
11714 const guint8 *wfex_data = stsd_entry_data + offset;
11715 const gchar *codec_name = NULL;
11717 /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11718 /* FIXME this should also be gst_riff_strf_auds,
11719 * but the latter one is actually missing bits-per-sample :( */
11724 gint32 nSamplesPerSec;
11725 gint32 nAvgBytesPerSec;
11726 gint16 nBlockAlign;
11727 gint16 wBitsPerSample;
11732 /* FIXME: unify with similar wavformatex parsing code above */
11733 GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11739 if (QT_UINT32 (wfex_data) <= len)
11740 size = QT_UINT32 (wfex_data) - 8;
11745 /* No real data, so break out */
11748 switch (QT_FOURCC (wfex_data + 4)) {
11749 case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11751 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11756 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11757 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11758 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11759 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11760 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11761 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11762 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11764 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11765 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11766 "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11767 "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11768 wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11769 wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11771 if (wfex.wFormatTag == 0x0161) {
11772 codec_name = "Windows Media Audio";
11774 } else if (wfex.wFormatTag == 0x0162) {
11775 codec_name = "Windows Media Audio 9 Pro";
11777 } else if (wfex.wFormatTag == 0x0163) {
11778 codec_name = "Windows Media Audio 9 Lossless";
11779 /* is that correct? gstffmpegcodecmap.c is missing it, but
11780 * fluendo codec seems to support it */
11784 gst_caps_set_simple (entry->caps,
11785 "wmaversion", G_TYPE_INT, version,
11786 "block_align", G_TYPE_INT, wfex.nBlockAlign,
11787 "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11788 "width", G_TYPE_INT, wfex.wBitsPerSample,
11789 "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11791 if (size > wfex.cbSize) {
11794 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11795 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11796 size - wfex.cbSize);
11797 gst_caps_set_simple (entry->caps,
11798 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11799 gst_buffer_unref (buf);
11801 GST_WARNING_OBJECT (qtdemux, "no codec data");
11806 codec = g_strdup (codec_name);
11814 wfex_data += size + 8;
11820 const guint8 *opus_data;
11821 guint8 *channel_mapping = NULL;
11824 guint8 channel_mapping_family;
11825 guint8 stream_count;
11826 guint8 coupled_count;
11829 opus_data = stsd_entry_data;
11831 channels = GST_READ_UINT8 (opus_data + 45);
11832 rate = GST_READ_UINT32_LE (opus_data + 48);
11833 channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11834 stream_count = GST_READ_UINT8 (opus_data + 55);
11835 coupled_count = GST_READ_UINT8 (opus_data + 56);
11837 if (channels > 0) {
11838 channel_mapping = g_malloc (channels * sizeof (guint8));
11839 for (i = 0; i < channels; i++)
11840 channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11843 entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11844 channel_mapping_family, stream_count, coupled_count,
11856 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11857 GST_TAG_AUDIO_CODEC, codec, NULL);
11861 /* some bitrate info may have ended up in caps */
11862 s = gst_caps_get_structure (entry->caps, 0);
11863 gst_structure_get_int (s, "bitrate", &bitrate);
11865 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11866 GST_TAG_BITRATE, bitrate, NULL);
11869 mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11870 if (!stream->protected) {
11872 if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11876 if (stream->protected && fourcc == FOURCC_mp4a) {
11877 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11881 if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11889 wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11891 esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11893 esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11897 /* If the fourcc's bottom 16 bits gives 'sm', then the top
11898 16 bits is a byte-swapped wave-style codec identifier,
11899 and we can find a WAVE header internally to a 'wave' atom here.
11900 This can more clearly be thought of as 'ms' as the top 16 bits, and a
11901 codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11904 if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11905 if (len < offset + 20) {
11906 GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11908 guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11909 const guint8 *data = stsd_entry_data + offset + 16;
11911 GNode *waveheadernode;
11913 wavenode = g_node_new ((guint8 *) data);
11914 if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11915 const guint8 *waveheader;
11918 waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11919 if (waveheadernode) {
11920 waveheader = (const guint8 *) waveheadernode->data;
11921 headerlen = QT_UINT32 (waveheader);
11923 if (headerlen > 8) {
11924 gst_riff_strf_auds *header = NULL;
11925 GstBuffer *headerbuf;
11931 headerbuf = gst_buffer_new_and_alloc (headerlen);
11932 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11934 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11935 headerbuf, &header, &extra)) {
11936 gst_caps_unref (entry->caps);
11937 /* FIXME: Need to do something with the channel reorder map */
11939 gst_riff_create_audio_caps (header->format, NULL, header,
11940 extra, NULL, NULL, NULL);
11943 gst_buffer_unref (extra);
11948 GST_DEBUG ("Didn't find waveheadernode for this codec");
11950 g_node_destroy (wavenode);
11953 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11954 stream->stream_tags);
11958 /* FIXME: what is in the chunk? */
11961 gint len = QT_UINT32 (stsd_data);
11963 /* seems to be always = 116 = 0x74 */
11969 gint len = QT_UINT32 (stsd_entry_data);
11972 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11974 gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11975 gst_caps_set_simple (entry->caps,
11976 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11977 gst_buffer_unref (buf);
11979 gst_caps_set_simple (entry->caps,
11980 "samplesize", G_TYPE_INT, samplesize, NULL);
11985 GNode *alac, *wave = NULL;
11987 /* apparently, m4a has this atom appended directly in the stsd entry,
11988 * while mov has it in a wave atom */
11989 alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11991 /* alac now refers to stsd entry atom */
11992 wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11994 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11996 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11999 const guint8 *alac_data = alac->data;
12000 gint len = QT_UINT32 (alac->data);
12004 GST_DEBUG_OBJECT (qtdemux,
12005 "discarding alac atom with unexpected len %d", len);
12007 /* codec-data contains alac atom size and prefix,
12008 * ffmpeg likes it that way, not quite gst-ish though ...*/
12009 buf = gst_buffer_new_and_alloc (len);
12010 gst_buffer_fill (buf, 0, alac->data, len);
12011 gst_caps_set_simple (entry->caps,
12012 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12013 gst_buffer_unref (buf);
12015 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12016 entry->n_channels = QT_UINT8 (alac_data + 21);
12017 entry->rate = QT_UINT32 (alac_data + 32);
12020 gst_caps_set_simple (entry->caps,
12021 "samplesize", G_TYPE_INT, samplesize, NULL);
12026 /* The codingname of the sample entry is 'fLaC' */
12027 GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12030 /* The 'dfLa' box is added to the sample entry to convey
12031 initializing information for the decoder. */
12032 const GNode *dfla =
12033 qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12036 const guint32 len = QT_UINT32 (dfla->data);
12038 /* Must contain at least dfLa box header (12),
12039 * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12041 GST_DEBUG_OBJECT (qtdemux,
12042 "discarding dfla atom with unexpected len %d", len);
12044 /* skip dfLa header to get the METADATA_BLOCKs */
12045 const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12046 const guint32 metadata_blocks_len = len - 12;
12048 gchar *stream_marker = g_strdup ("fLaC");
12049 GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12050 strlen (stream_marker));
12053 guint32 remainder = 0;
12054 guint32 block_size = 0;
12055 gboolean is_last = FALSE;
12057 GValue array = G_VALUE_INIT;
12058 GValue value = G_VALUE_INIT;
12060 g_value_init (&array, GST_TYPE_ARRAY);
12061 g_value_init (&value, GST_TYPE_BUFFER);
12063 gst_value_set_buffer (&value, block);
12064 gst_value_array_append_value (&array, &value);
12065 g_value_reset (&value);
12067 gst_buffer_unref (block);
12069 /* check there's at least one METADATA_BLOCK_HEADER's worth
12070 * of data, and we haven't already finished parsing */
12071 while (!is_last && ((index + 3) < metadata_blocks_len)) {
12072 remainder = metadata_blocks_len - index;
12074 /* add the METADATA_BLOCK_HEADER size to the signalled size */
12076 (metadata_blocks[index + 1] << 16) +
12077 (metadata_blocks[index + 2] << 8) +
12078 metadata_blocks[index + 3];
12080 /* be careful not to read off end of box */
12081 if (block_size > remainder) {
12085 is_last = metadata_blocks[index] >> 7;
12087 block = gst_buffer_new_and_alloc (block_size);
12089 gst_buffer_fill (block, 0, &metadata_blocks[index],
12092 gst_value_set_buffer (&value, block);
12093 gst_value_array_append_value (&array, &value);
12094 g_value_reset (&value);
12096 gst_buffer_unref (block);
12098 index += block_size;
12101 /* only append the metadata if we successfully read all of it */
12103 gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12104 (stream)->caps, 0), "streamheader", &array);
12106 GST_WARNING_OBJECT (qtdemux,
12107 "discarding all METADATA_BLOCKs due to invalid "
12108 "block_size %d at idx %d, rem %d", block_size, index,
12112 g_value_unset (&value);
12113 g_value_unset (&array);
12115 /* The sample rate obtained from the stsd may not be accurate
12116 * since it cannot represent rates greater than 65535Hz, so
12117 * override that value with the sample rate from the
12118 * METADATA_BLOCK_STREAMINFO block */
12119 CUR_STREAM (stream)->rate =
12120 (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12131 gint len = QT_UINT32 (stsd_entry_data);
12134 GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12137 gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12139 /* If we have enough data, let's try to get the 'damr' atom. See
12140 * the 3GPP container spec (26.244) for more details. */
12141 if ((len - 0x34) > 8 &&
12142 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12143 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12144 GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12147 gst_caps_set_simple (entry->caps,
12148 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12149 gst_buffer_unref (buf);
12155 /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12156 gint len = QT_UINT32 (stsd_entry_data);
12159 guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12161 if (sound_version == 1) {
12162 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12163 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12164 guint8 codec_data[2];
12166 gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12168 gint sample_rate_index =
12169 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12171 /* build AAC codec data */
12172 codec_data[0] = profile << 3;
12173 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12174 codec_data[1] = (sample_rate_index & 0x01) << 7;
12175 codec_data[1] |= (channels & 0xF) << 3;
12177 buf = gst_buffer_new_and_alloc (2);
12178 gst_buffer_fill (buf, 0, codec_data, 2);
12179 gst_caps_set_simple (entry->caps,
12180 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12181 gst_buffer_unref (buf);
12187 /* Fully handled elsewhere */
12190 GST_INFO_OBJECT (qtdemux,
12191 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12195 GST_INFO_OBJECT (qtdemux,
12196 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12197 GST_FOURCC_ARGS (fourcc), entry->caps);
12199 } else if (stream->subtype == FOURCC_strm) {
12200 if (fourcc == FOURCC_rtsp) {
12201 stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12203 GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12204 GST_FOURCC_ARGS (fourcc));
12205 goto unknown_stream;
12207 entry->sampled = TRUE;
12208 } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12209 || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12210 || stream->subtype == FOURCC_clcp) {
12212 entry->sampled = TRUE;
12213 entry->sparse = TRUE;
12216 qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12219 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12220 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12225 /* hunt for sort-of codec data */
12229 GNode *mp4s = NULL;
12230 GNode *esds = NULL;
12232 /* look for palette in a stsd->mp4s->esds sub-atom */
12233 mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12235 esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12236 if (esds == NULL) {
12238 GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12242 gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12243 stream->stream_tags);
12247 GST_INFO_OBJECT (qtdemux,
12248 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12251 GST_INFO_OBJECT (qtdemux,
12252 "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12253 GST_FOURCC_ARGS (fourcc), entry->caps);
12255 /* everything in 1 sample */
12256 entry->sampled = TRUE;
12259 qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12262 if (entry->caps == NULL)
12263 goto unknown_stream;
12266 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12267 GST_TAG_SUBTITLE_CODEC, codec, NULL);
12273 /* promote to sampled format */
12274 if (entry->fourcc == FOURCC_samr) {
12275 /* force mono 8000 Hz for AMR */
12276 entry->sampled = TRUE;
12277 entry->n_channels = 1;
12278 entry->rate = 8000;
12279 } else if (entry->fourcc == FOURCC_sawb) {
12280 /* force mono 16000 Hz for AMR-WB */
12281 entry->sampled = TRUE;
12282 entry->n_channels = 1;
12283 entry->rate = 16000;
12284 } else if (entry->fourcc == FOURCC_mp4a) {
12285 entry->sampled = TRUE;
12289 stsd_entry_data += len;
12290 remaining_stsd_len -= len;
12294 /* collect sample information */
12295 if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12296 goto samples_failed;
12298 if (qtdemux->fragmented) {
12301 /* need all moov samples as basis; probably not many if any at all */
12302 /* prevent moof parsing taking of at this time */
12303 offset = qtdemux->moof_offset;
12304 qtdemux->moof_offset = 0;
12305 if (stream->n_samples &&
12306 !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12307 qtdemux->moof_offset = offset;
12308 goto samples_failed;
12310 qtdemux->moof_offset = 0;
12311 /* movie duration more reliable in this case (e.g. mehd) */
12312 if (qtdemux->segment.duration &&
12313 GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12315 GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12318 /* configure segments */
12319 if (!qtdemux_parse_segments (qtdemux, stream, trak))
12320 goto segments_failed;
12322 /* add some language tag, if useful */
12323 if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12324 strcmp (stream->lang_id, "und")) {
12325 const gchar *lang_code;
12327 /* convert ISO 639-2 code to ISO 639-1 */
12328 lang_code = gst_tag_get_language_code (stream->lang_id);
12329 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12330 GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12333 /* Check for UDTA tags */
12334 if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12335 qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12338 /* Insert and sort new stream in track-id order.
12339 * This will help in comparing old/new streams during stream update check */
12340 g_ptr_array_add (qtdemux->active_streams, stream);
12341 g_ptr_array_sort (qtdemux->active_streams,
12342 (GCompareFunc) qtdemux_track_id_compare_func);
12343 GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
12344 QTDEMUX_N_STREAMS (qtdemux));
12351 GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12352 (_("This file is corrupt and cannot be played.")), (NULL));
12354 gst_qtdemux_stream_unref (stream);
12359 GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12360 gst_qtdemux_stream_unref (stream);
12366 /* we posted an error already */
12367 /* free stbl sub-atoms */
12368 gst_qtdemux_stbl_free (stream);
12369 gst_qtdemux_stream_unref (stream);
12374 GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12380 GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12381 GST_FOURCC_ARGS (stream->subtype));
12382 gst_qtdemux_stream_unref (stream);
12387 /* If we can estimate the overall bitrate, and don't have information about the
12388 * stream bitrate for exactly one stream, this guesses the stream bitrate as
12389 * the overall bitrate minus the sum of the bitrates of all other streams. This
12390 * should be useful for the common case where we have one audio and one video
12391 * stream and can estimate the bitrate of one, but not the other. */
12393 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12395 QtDemuxStream *stream = NULL;
12396 gint64 size, sys_bitrate, sum_bitrate = 0;
12397 GstClockTime duration;
12401 if (qtdemux->fragmented)
12404 GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12406 if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12408 GST_DEBUG_OBJECT (qtdemux,
12409 "Size in bytes of the stream not known - bailing");
12413 /* Subtract the header size */
12414 GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12415 size, qtdemux->header_size);
12417 if (size < qtdemux->header_size)
12420 size = size - qtdemux->header_size;
12422 if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12423 GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12427 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12428 QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
12429 switch (str->subtype) {
12432 GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12433 CUR_STREAM (str)->caps);
12434 /* retrieve bitrate, prefer avg then max */
12436 if (str->stream_tags) {
12437 if (gst_tag_list_get_uint (str->stream_tags,
12438 GST_TAG_MAXIMUM_BITRATE, &bitrate))
12439 GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12440 if (gst_tag_list_get_uint (str->stream_tags,
12441 GST_TAG_NOMINAL_BITRATE, &bitrate))
12442 GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12443 if (gst_tag_list_get_uint (str->stream_tags,
12444 GST_TAG_BITRATE, &bitrate))
12445 GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12448 sum_bitrate += bitrate;
12451 GST_DEBUG_OBJECT (qtdemux,
12452 ">1 stream with unknown bitrate - bailing");
12459 /* For other subtypes, we assume no significant impact on bitrate */
12465 GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12469 sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12471 if (sys_bitrate < sum_bitrate) {
12472 /* This can happen, since sum_bitrate might be derived from maximum
12473 * bitrates and not average bitrates */
12474 GST_DEBUG_OBJECT (qtdemux,
12475 "System bitrate less than sum bitrate - bailing");
12479 bitrate = sys_bitrate - sum_bitrate;
12480 GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12481 ", Stream bitrate = %u", sys_bitrate, bitrate);
12483 if (!stream->stream_tags)
12484 stream->stream_tags = gst_tag_list_new_empty ();
12486 stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12488 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12489 GST_TAG_BITRATE, bitrate, NULL);
12492 static GstFlowReturn
12493 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12495 GstFlowReturn ret = GST_FLOW_OK;
12498 GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12500 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12501 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12502 guint32 sample_num = 0;
12504 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12505 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12507 if (qtdemux->fragmented) {
12508 /* need all moov samples first */
12509 GST_OBJECT_LOCK (qtdemux);
12510 while (stream->n_samples == 0)
12511 if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12513 GST_OBJECT_UNLOCK (qtdemux);
12515 /* discard any stray moof */
12516 qtdemux->moof_offset = 0;
12519 /* prepare braking */
12520 if (ret != GST_FLOW_ERROR)
12523 /* in pull mode, we should have parsed some sample info by now;
12524 * and quite some code will not handle no samples.
12525 * in push mode, we'll just have to deal with it */
12526 if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12527 GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12528 g_ptr_array_remove_index (qtdemux->active_streams, i);
12531 } else if (stream->track_id == qtdemux->chapters_track_id &&
12532 (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
12533 /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12534 so that it doesn't look like a subtitle track */
12535 g_ptr_array_remove_index (qtdemux->active_streams, i);
12540 /* parse the initial sample for use in setting the frame rate cap */
12541 while (sample_num == 0 && sample_num < stream->n_samples) {
12542 if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12552 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
12554 return g_strcmp0 (stream->stream_id, stream_id) == 0;
12558 qtdemux_is_streams_update (GstQTDemux * qtdemux)
12562 /* Different length, updated */
12563 if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
12566 /* streams in list are sorted in track-id order */
12567 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12568 /* Different stream-id, updated */
12569 if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
12570 QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
12578 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
12579 QtDemuxStream * oldstream, QtDemuxStream * newstream)
12581 /* Connect old stream's srcpad to new stream */
12582 newstream->pad = oldstream->pad;
12583 oldstream->pad = NULL;
12585 /* unset new_stream to prevent stream-start event */
12586 newstream->new_stream = FALSE;
12588 return gst_qtdemux_configure_stream (qtdemux, newstream);
12591 /* g_ptr_array_find_with_equal_func is available since 2.54,
12592 * replacement until we can depend unconditionally on the real one in GLib */
12593 #if !GLIB_CHECK_VERSION(2,54,0)
12594 #define g_ptr_array_find_with_equal_func qtdemux_ptr_array_find_with_equal_func
12596 qtdemux_ptr_array_find_with_equal_func (GPtrArray * haystack,
12597 gconstpointer needle, GEqualFunc equal_func, guint * index_)
12601 g_return_val_if_fail (haystack != NULL, FALSE);
12603 if (equal_func == NULL)
12604 equal_func = g_direct_equal;
12606 for (i = 0; i < haystack->len; i++) {
12607 if (equal_func (g_ptr_array_index (haystack, i), needle)) {
12608 if (index_ != NULL)
12619 qtdemux_update_streams (GstQTDemux * qtdemux)
12622 g_assert (qtdemux->streams_aware);
12624 /* At below, figure out which stream in active_streams has identical stream-id
12625 * with that of in old_streams. If there is matching stream-id,
12626 * corresponding newstream will not be exposed again,
12627 * but demux will reuse srcpad of matched old stream
12629 * active_streams : newly created streams from the latest moov
12630 * old_streams : existing streams (belong to previous moov)
12633 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12634 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12635 QtDemuxStream *oldstream = NULL;
12638 GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
12639 stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12641 if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
12642 stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
12643 oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
12645 /* null pad stream cannot be reused */
12646 if (oldstream->pad == NULL)
12651 GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
12653 if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
12656 /* we don't need to preserve order of old streams */
12657 g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
12661 /* now we have all info and can expose */
12662 list = stream->stream_tags;
12663 stream->stream_tags = NULL;
12664 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12672 /* Must be called with expose lock */
12673 static GstFlowReturn
12674 qtdemux_expose_streams (GstQTDemux * qtdemux)
12678 GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12680 if (!qtdemux_is_streams_update (qtdemux)) {
12681 GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
12682 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12683 QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12684 QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
12685 if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
12686 return GST_FLOW_ERROR;
12689 g_ptr_array_remove_range (qtdemux->old_streams,
12690 0, qtdemux->old_streams->len);
12692 qtdemux->need_segment = TRUE;
12694 return GST_FLOW_OK;
12697 if (qtdemux->streams_aware) {
12698 if (!qtdemux_update_streams (qtdemux))
12699 return GST_FLOW_ERROR;
12701 for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
12702 QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
12705 /* now we have all info and can expose */
12706 list = stream->stream_tags;
12707 stream->stream_tags = NULL;
12708 if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12709 return GST_FLOW_ERROR;
12714 gst_qtdemux_guess_bitrate (qtdemux);
12716 gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12718 /* If we have still old_streams, it's no more used stream */
12719 for (i = 0; i < qtdemux->old_streams->len; i++) {
12720 QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
12725 event = gst_event_new_eos ();
12726 if (qtdemux->segment_seqnum)
12727 gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12729 gst_pad_push_event (stream->pad, event);
12733 g_ptr_array_remove_range (qtdemux->old_streams, 0, qtdemux->old_streams->len);
12735 /* check if we should post a redirect in case there is a single trak
12736 * and it is a redirecting trak */
12737 if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
12738 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
12741 GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12742 "an external content");
12743 m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12744 gst_structure_new ("redirect",
12745 "new-location", G_TYPE_STRING,
12746 QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
12747 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12748 qtdemux->posted_redirect = TRUE;
12751 g_ptr_array_foreach (qtdemux->active_streams,
12752 (GFunc) qtdemux_do_allocation, qtdemux);
12754 qtdemux->need_segment = TRUE;
12756 qtdemux->exposed = TRUE;
12757 return GST_FLOW_OK;
12760 /* check if major or compatible brand is 3GP */
12761 static inline gboolean
12762 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12765 return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12767 } else if (qtdemux->comp_brands != NULL) {
12771 gboolean res = FALSE;
12773 gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12776 while (size >= 4) {
12777 res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12782 gst_buffer_unmap (qtdemux->comp_brands, &map);
12789 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12790 static inline gboolean
12791 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12793 return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12794 || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12795 || fourcc == FOURCC_albm;
12799 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12800 const char *tag, const char *dummy, GNode * node)
12802 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12806 gdouble longitude, latitude, altitude;
12809 len = QT_UINT32 (node->data);
12816 /* TODO: language code skipped */
12818 name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12821 /* do not alarm in trivial case, but bail out otherwise */
12822 if (*(data + offset) != 0) {
12823 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12827 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12828 GST_TAG_GEO_LOCATION_NAME, name, NULL);
12829 offset += strlen (name);
12833 if (len < offset + 2 + 4 + 4 + 4)
12836 /* +1 +1 = skip null-terminator and location role byte */
12838 /* table in spec says unsigned, semantics say negative has meaning ... */
12839 longitude = QT_SFP32 (data + offset);
12842 latitude = QT_SFP32 (data + offset);
12845 altitude = QT_SFP32 (data + offset);
12847 /* one invalid means all are invalid */
12848 if (longitude >= -180.0 && longitude <= 180.0 &&
12849 latitude >= -90.0 && latitude <= 90.0) {
12850 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12851 GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12852 GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12853 GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12856 /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12863 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12870 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12871 const char *tag, const char *dummy, GNode * node)
12877 len = QT_UINT32 (node->data);
12881 y = QT_UINT16 ((guint8 *) node->data + 12);
12883 GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12886 GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12888 date = g_date_new_dmy (1, 1, y);
12889 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12890 g_date_free (date);
12894 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12895 const char *tag, const char *dummy, GNode * node)
12898 char *tag_str = NULL;
12903 len = QT_UINT32 (node->data);
12908 entity = (guint8 *) node->data + offset;
12909 if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12910 GST_DEBUG_OBJECT (qtdemux,
12911 "classification info: %c%c%c%c invalid classification entity",
12912 entity[0], entity[1], entity[2], entity[3]);
12917 table = QT_UINT16 ((guint8 *) node->data + offset);
12919 /* Language code skipped */
12923 /* Tag format: "XXXX://Y[YYYY]/classification info string"
12924 * XXXX: classification entity, fixed length 4 chars.
12925 * Y[YYYY]: classification table, max 5 chars.
12927 tag_str = g_strdup_printf ("----://%u/%s",
12928 table, (char *) node->data + offset);
12930 /* memcpy To be sure we're preserving byte order */
12931 memcpy (tag_str, entity, 4);
12932 GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12934 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12943 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12949 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12950 const char *tag, const char *dummy, GNode * node)
12952 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12958 gboolean ret = TRUE;
12959 const gchar *charset = NULL;
12961 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12963 len = QT_UINT32 (data->data);
12964 type = QT_UINT32 ((guint8 *) data->data + 8);
12965 if (type == 0x00000001 && len > 16) {
12966 s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12969 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12970 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12973 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12977 len = QT_UINT32 (node->data);
12978 type = QT_UINT32 ((guint8 *) node->data + 4);
12979 if ((type >> 24) == 0xa9 && len > 8 + 4) {
12983 /* Type starts with the (C) symbol, so the next data is a list
12984 * of (string size(16), language code(16), string) */
12986 str_len = QT_UINT16 ((guint8 *) node->data + 8);
12987 lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12989 /* the string + fourcc + size + 2 16bit fields,
12990 * means that there are more tags in this atom */
12991 if (len > str_len + 8 + 4) {
12992 /* TODO how to represent the same tag in different languages? */
12993 GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12994 "text alternatives, reading only first one");
12998 len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12999 GST_DEBUG_OBJECT (qtdemux, "found international text tag");
13001 if (lang_code < 0x800) { /* MAC encoded string */
13004 } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
13005 QT_FOURCC ((guint8 *) node->data + 4))) {
13006 guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
13008 /* we go for 3GP style encoding if major brands claims so,
13009 * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
13010 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13011 (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
13012 ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
13014 /* 16-bit Language code is ignored here as well */
13015 GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
13022 GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
13023 ret = FALSE; /* may have to fallback */
13026 GError *err = NULL;
13028 s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
13029 charset, NULL, NULL, &err);
13031 GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
13032 " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
13034 g_error_free (err);
13037 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13038 len - offset, env_vars);
13041 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13042 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13046 GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13053 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
13054 const char *tag, const char *dummy, GNode * node)
13056 qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
13060 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
13061 const char *tag, const char *dummy, GNode * node)
13063 const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13065 char *s, *t, *k = NULL;
13070 /* first try normal string tag if major brand not 3GP */
13071 if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
13072 if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
13073 /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
13074 * let's try it 3gpp way after minor safety check */
13076 if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
13082 GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
13086 len = QT_UINT32 (data);
13090 count = QT_UINT8 (data + 14);
13092 for (; count; count--) {
13095 if (offset + 1 > len)
13097 slen = QT_UINT8 (data + offset);
13099 if (offset + slen > len)
13101 s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13104 GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
13106 t = g_strjoin (",", k, s, NULL);
13114 GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
13121 GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
13122 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
13131 GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
13137 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
13138 const char *tag1, const char *tag2, GNode * node)
13145 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13147 len = QT_UINT32 (data->data);
13148 type = QT_UINT32 ((guint8 *) data->data + 8);
13149 if (type == 0x00000000 && len >= 22) {
13150 n1 = QT_UINT16 ((guint8 *) data->data + 18);
13151 n2 = QT_UINT16 ((guint8 *) data->data + 20);
13153 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
13154 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
13157 GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
13158 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
13165 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
13166 const char *tag1, const char *dummy, GNode * node)
13173 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13175 len = QT_UINT32 (data->data);
13176 type = QT_UINT32 ((guint8 *) data->data + 8);
13177 GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
13178 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13179 if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
13180 n1 = QT_UINT16 ((guint8 *) data->data + 16);
13182 /* do not add bpm=0 */
13183 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
13184 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13192 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13193 const char *tag1, const char *dummy, GNode * node)
13200 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13202 len = QT_UINT32 (data->data);
13203 type = QT_UINT32 ((guint8 *) data->data + 8);
13204 GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13205 /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13206 if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13207 num = QT_UINT32 ((guint8 *) data->data + 16);
13209 /* do not add num=0 */
13210 GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13211 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13218 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13219 const char *tag1, const char *dummy, GNode * node)
13226 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13228 len = QT_UINT32 (data->data);
13229 type = QT_UINT32 ((guint8 *) data->data + 8);
13230 GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13231 if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13232 GstTagImageType image_type;
13234 if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13235 image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13237 image_type = GST_TAG_IMAGE_TYPE_NONE;
13240 gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13241 len - 16, image_type))) {
13242 GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13243 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13244 gst_sample_unref (sample);
13251 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
13252 const char *tag, const char *dummy, GNode * node)
13255 GstDateTime *datetime = NULL;
13260 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13262 len = QT_UINT32 (data->data);
13263 type = QT_UINT32 ((guint8 *) data->data + 8);
13264 if (type == 0x00000001 && len > 16) {
13265 guint y, m = 1, d = 1;
13268 s = g_strndup ((char *) data->data + 16, len - 16);
13269 GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13270 datetime = gst_date_time_new_from_iso8601_string (s);
13271 if (datetime != NULL) {
13272 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
13274 gst_date_time_unref (datetime);
13277 ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13278 if (ret >= 1 && y > 1500 && y < 3000) {
13281 date = g_date_new_dmy (d, m, y);
13282 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13283 g_date_free (date);
13285 GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13293 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13294 const char *tag, const char *dummy, GNode * node)
13298 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13300 /* re-route to normal string tag if major brand says so
13301 * or no data atom and compatible brand suggests so */
13302 if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13303 (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13304 qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13309 guint len, type, n;
13311 len = QT_UINT32 (data->data);
13312 type = QT_UINT32 ((guint8 *) data->data + 8);
13313 if (type == 0x00000000 && len >= 18) {
13314 n = QT_UINT16 ((guint8 *) data->data + 16);
13316 const gchar *genre;
13318 genre = gst_tag_id3_genre_get (n - 1);
13319 if (genre != NULL) {
13320 GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13321 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13329 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13330 const gchar * tag, guint8 * data, guint32 datasize)
13335 /* make a copy to have \0 at the end */
13336 datacopy = g_strndup ((gchar *) data, datasize);
13338 /* convert the str to double */
13339 if (sscanf (datacopy, "%lf", &value) == 1) {
13340 GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13341 gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13343 GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13351 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13352 const char *tag, const char *tag_bis, GNode * node)
13361 const gchar *meanstr;
13362 const gchar *namestr;
13364 /* checking the whole ---- atom size for consistency */
13365 if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13366 GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13370 mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13372 GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13376 meansize = QT_UINT32 (mean->data);
13377 if (meansize <= 12) {
13378 GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13381 meanstr = ((gchar *) mean->data) + 12;
13384 name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13386 GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13390 namesize = QT_UINT32 (name->data);
13391 if (namesize <= 12) {
13392 GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13395 namestr = ((gchar *) name->data) + 12;
13403 * uint24 - data type
13407 data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13409 GST_WARNING_OBJECT (demux, "No data atom in this tag");
13412 datasize = QT_UINT32 (data->data);
13413 if (datasize <= 16) {
13414 GST_WARNING_OBJECT (demux, "Data atom too small");
13417 datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13419 if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13420 (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13421 static const struct
13423 const gchar name[28];
13424 const gchar tag[28];
13427 "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13428 "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13429 "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13430 "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13431 "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13432 "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13433 "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13434 "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13438 for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13439 if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13440 switch (gst_tag_get_type (tags[i].tag)) {
13441 case G_TYPE_DOUBLE:
13442 qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13443 ((guint8 *) data->data) + 16, datasize - 16);
13445 case G_TYPE_STRING:
13446 qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13455 if (i == G_N_ELEMENTS (tags))
13465 #ifndef GST_DISABLE_GST_DEBUG
13467 gchar *namestr_dbg;
13468 gchar *meanstr_dbg;
13470 meanstr_dbg = g_strndup (meanstr, meansize);
13471 namestr_dbg = g_strndup (namestr, namesize);
13473 GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13474 "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13476 g_free (namestr_dbg);
13477 g_free (meanstr_dbg);
13484 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13485 const char *tag_bis, GNode * node)
13490 GstTagList *id32_taglist = NULL;
13492 GST_LOG_OBJECT (demux, "parsing ID32");
13495 len = GST_READ_UINT32_BE (data);
13497 /* need at least full box and language tag */
13501 buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13502 gst_buffer_fill (buf, 0, data + 14, len - 14);
13504 id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13505 if (id32_taglist) {
13506 GST_LOG_OBJECT (demux, "parsing ok");
13507 gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13508 gst_tag_list_unref (id32_taglist);
13510 GST_LOG_OBJECT (demux, "parsing failed");
13513 gst_buffer_unref (buf);
13516 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13517 const char *tag, const char *tag_bis, GNode * node);
13520 FOURCC_pcst -> if media is a podcast -> bool
13521 FOURCC_cpil -> if media is part of a compilation -> bool
13522 FOURCC_pgap -> if media is part of a gapless context -> bool
13523 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13526 static const struct
13529 const gchar *gst_tag;
13530 const gchar *gst_tag_bis;
13531 const GstQTDemuxAddTagFunc func;
13534 FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13535 FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13536 FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13537 FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13538 FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13539 FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13540 FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13541 FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13542 FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13543 FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13544 FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13545 FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13546 FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13547 FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13548 FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13549 FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13550 FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13551 FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13552 FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13553 FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13554 FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13555 FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13556 FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13557 qtdemux_tag_add_num}, {
13558 FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13559 qtdemux_tag_add_num}, {
13560 FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13561 FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13562 FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13563 FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13564 FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13565 FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13566 FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13567 FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13568 FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13569 FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13570 FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13571 FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13572 FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13573 FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13574 FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13575 FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13576 FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13577 FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13578 qtdemux_tag_add_classification}, {
13579 FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13580 FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13581 FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13583 /* This is a special case, some tags are stored in this
13584 * 'reverse dns naming', according to:
13585 * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13588 FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13589 /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13590 FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13593 struct _GstQtDemuxTagList
13596 GstTagList *taglist;
13598 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13601 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13607 const gchar *style;
13612 GstQTDemux *demux = qtdemuxtaglist->demux;
13613 GstTagList *taglist = qtdemuxtaglist->taglist;
13616 len = QT_UINT32 (data);
13617 buf = gst_buffer_new_and_alloc (len);
13618 gst_buffer_fill (buf, 0, data, len);
13620 /* heuristic to determine style of tag */
13621 if (QT_FOURCC (data + 4) == FOURCC_____ ||
13622 (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13624 else if (demux->major_brand == FOURCC_qt__)
13625 style = "quicktime";
13626 /* fall back to assuming iso/3gp tag style */
13630 /* santize the name for the caps. */
13631 for (i = 0; i < 4; i++) {
13632 guint8 d = data[4 + i];
13633 if (g_ascii_isalnum (d))
13634 ndata[i] = g_ascii_tolower (d);
13639 media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13640 ndata[0], ndata[1], ndata[2], ndata[3]);
13641 GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13643 s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13644 sample = gst_sample_new (buf, NULL, NULL, s);
13645 gst_buffer_unref (buf);
13646 g_free (media_type);
13648 GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13651 gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13652 GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13654 gst_sample_unref (sample);
13658 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13665 GstQtDemuxTagList demuxtaglist;
13667 demuxtaglist.demux = qtdemux;
13668 demuxtaglist.taglist = taglist;
13670 meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13671 if (meta != NULL) {
13672 ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13673 if (ilst == NULL) {
13674 GST_LOG_OBJECT (qtdemux, "no ilst");
13679 GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13683 while (i < G_N_ELEMENTS (add_funcs)) {
13684 node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13688 len = QT_UINT32 (node->data);
13690 GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13691 GST_FOURCC_ARGS (add_funcs[i].fourcc));
13693 add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13694 add_funcs[i].gst_tag_bis, node);
13696 g_node_destroy (node);
13702 /* parsed nodes have been removed, pass along remainder as blob */
13703 g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13704 (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13706 /* parse up XMP_ node if existing */
13707 xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13708 if (xmp_ != NULL) {
13710 GstTagList *xmptaglist;
13712 buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13713 QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13714 xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13715 gst_buffer_unref (buf);
13717 qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13719 GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13725 GstStructure *structure; /* helper for sort function */
13727 guint min_req_bitrate;
13728 guint min_req_qt_version;
13732 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13734 GstQtReference *ref_a = (GstQtReference *) a;
13735 GstQtReference *ref_b = (GstQtReference *) b;
13737 if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13738 return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13740 /* known bitrates go before unknown; higher bitrates go first */
13741 return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13744 /* sort the redirects and post a message for the application.
13747 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13749 GstQtReference *best;
13752 GValue list_val = { 0, };
13755 g_assert (references != NULL);
13757 references = g_list_sort (references, qtdemux_redirects_sort_func);
13759 best = (GstQtReference *) references->data;
13761 g_value_init (&list_val, GST_TYPE_LIST);
13763 for (l = references; l != NULL; l = l->next) {
13764 GstQtReference *ref = (GstQtReference *) l->data;
13765 GValue struct_val = { 0, };
13767 ref->structure = gst_structure_new ("redirect",
13768 "new-location", G_TYPE_STRING, ref->location, NULL);
13770 if (ref->min_req_bitrate > 0) {
13771 gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13772 ref->min_req_bitrate, NULL);
13775 g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13776 g_value_set_boxed (&struct_val, ref->structure);
13777 gst_value_list_append_value (&list_val, &struct_val);
13778 g_value_unset (&struct_val);
13779 /* don't free anything here yet, since we need best->structure below */
13782 g_assert (best != NULL);
13783 s = gst_structure_copy (best->structure);
13785 if (g_list_length (references) > 1) {
13786 gst_structure_set_value (s, "locations", &list_val);
13789 g_value_unset (&list_val);
13791 for (l = references; l != NULL; l = l->next) {
13792 GstQtReference *ref = (GstQtReference *) l->data;
13794 gst_structure_free (ref->structure);
13795 g_free (ref->location);
13798 g_list_free (references);
13800 GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13801 msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13802 gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13803 qtdemux->posted_redirect = TRUE;
13806 /* look for redirect nodes, collect all redirect information and
13810 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13812 GNode *rmra, *rmda, *rdrf;
13814 rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13816 GList *redirects = NULL;
13818 rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13820 GstQtReference ref = { NULL, NULL, 0, 0 };
13821 GNode *rmdr, *rmvc;
13823 if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13824 ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13825 GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13826 ref.min_req_bitrate);
13829 if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13830 guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13831 guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13833 #ifndef GST_DISABLE_GST_DEBUG
13834 guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13836 guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13838 GST_LOG_OBJECT (qtdemux,
13839 "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13840 ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13841 bitmask, check_type);
13842 if (package == FOURCC_qtim && check_type == 0) {
13843 ref.min_req_qt_version = version;
13847 rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13853 ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13854 if (ref_len > 20) {
13855 ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13856 ref_data = (guint8 *) rdrf->data + 20;
13857 if (ref_type == FOURCC_alis) {
13858 guint record_len, record_version, fn_len;
13860 if (ref_len > 70) {
13861 /* MacOSX alias record, google for alias-layout.txt */
13862 record_len = QT_UINT16 (ref_data + 4);
13863 record_version = QT_UINT16 (ref_data + 4 + 2);
13864 fn_len = QT_UINT8 (ref_data + 50);
13865 if (record_len > 50 && record_version == 2 && fn_len > 0) {
13866 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13869 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13872 } else if (ref_type == FOURCC_url_) {
13873 ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13875 GST_DEBUG_OBJECT (qtdemux,
13876 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13877 GST_FOURCC_ARGS (ref_type));
13879 if (ref.location != NULL) {
13880 GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13882 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13884 GST_WARNING_OBJECT (qtdemux,
13885 "Failed to extract redirect location from rdrf atom");
13888 GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13892 /* look for others */
13893 rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13896 if (redirects != NULL) {
13897 qtdemux_process_redirects (qtdemux, redirects);
13903 static GstTagList *
13904 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13908 if (tags == NULL) {
13909 tags = gst_tag_list_new_empty ();
13910 gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13913 if (qtdemux->major_brand == FOURCC_mjp2)
13914 fmt = "Motion JPEG 2000";
13915 else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13917 else if (qtdemux->major_brand == FOURCC_qt__)
13919 else if (qtdemux->fragmented)
13922 fmt = "ISO MP4/M4A";
13924 GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13925 GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13927 gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13933 /* we have read the complete moov node now.
13934 * This function parses all of the relevant info, creates the traks and
13935 * prepares all data structures for playback
13938 qtdemux_parse_tree (GstQTDemux * qtdemux)
13945 guint64 creation_time;
13946 GstDateTime *datetime = NULL;
13949 /* make sure we have a usable taglist */
13950 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13952 mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13953 if (mvhd == NULL) {
13954 GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13955 return qtdemux_parse_redirects (qtdemux);
13958 version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13959 if (version == 1) {
13960 creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13961 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13962 qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13963 } else if (version == 0) {
13964 creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13965 qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13966 qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13968 GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13972 /* Moving qt creation time (secs since 1904) to unix time */
13973 if (creation_time != 0) {
13974 /* Try to use epoch first as it should be faster and more commonly found */
13975 if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13978 creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13979 /* some data cleansing sanity */
13980 g_get_current_time (&now);
13981 if (now.tv_sec + 24 * 3600 < creation_time) {
13982 GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13984 datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13987 GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13988 GDateTime *dt, *dt_local;
13990 dt = g_date_time_add_seconds (base_dt, creation_time);
13991 dt_local = g_date_time_to_local (dt);
13992 datetime = gst_date_time_new_from_g_date_time (dt_local);
13994 g_date_time_unref (base_dt);
13995 g_date_time_unref (dt);
13999 /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14000 gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14002 gst_date_time_unref (datetime);
14005 GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14006 GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14008 /* check for fragmented file and get some (default) data */
14009 mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14012 GstByteReader mehd_data;
14014 /* let track parsing or anyone know weird stuff might happen ... */
14015 qtdemux->fragmented = TRUE;
14017 /* compensate for total duration */
14018 mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14020 qtdemux_parse_mehd (qtdemux, &mehd_data);
14023 /* Update the movie segment duration, unless it was directly given to us
14024 * by upstream. Otherwise let it as is, as we don't want to mangle the
14025 * duration provided by upstream that may come e.g. from a MPD file. */
14026 if (!qtdemux->upstream_format_is_time) {
14027 GstClockTime duration;
14028 /* set duration in the segment info */
14029 gst_qtdemux_get_duration (qtdemux, &duration);
14030 qtdemux->segment.duration = duration;
14031 /* also do not exceed duration; stop is set that way post seek anyway,
14032 * and segment activation falls back to duration,
14033 * whereas loop only checks stop, so let's align this here as well */
14034 qtdemux->segment.stop = duration;
14037 /* parse all traks */
14038 trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14040 qtdemux_parse_trak (qtdemux, trak);
14041 /* iterate all siblings */
14042 trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14045 qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14048 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14050 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14052 GST_LOG_OBJECT (qtdemux, "No udta node found.");
14055 /* maybe also some tags in meta box */
14056 udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14058 GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14059 qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14061 GST_LOG_OBJECT (qtdemux, "No meta node found.");
14064 /* parse any protection system info */
14065 pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14067 GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14068 qtdemux_parse_pssh (qtdemux, pssh);
14069 pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14072 qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14077 /* taken from ffmpeg */
14079 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14091 len = (len << 7) | (c & 0x7f);
14100 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14101 gsize codec_data_size)
14103 GList *list = NULL;
14104 guint8 *p = codec_data;
14105 gint i, offset, num_packets;
14106 guint *length, last;
14108 GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14110 if (codec_data == NULL || codec_data_size == 0)
14113 /* start of the stream and vorbis audio or theora video, need to
14114 * send the codec_priv data as first three packets */
14115 num_packets = p[0] + 1;
14116 GST_DEBUG_OBJECT (qtdemux,
14117 "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14118 (guint) num_packets, codec_data_size);
14120 /* Let's put some limits, Don't think there even is a xiph codec
14121 * with more than 3-4 headers */
14122 if (G_UNLIKELY (num_packets > 16)) {
14123 GST_WARNING_OBJECT (qtdemux,
14124 "Unlikely number of xiph headers, most likely not valid");
14128 length = g_alloca (num_packets * sizeof (guint));
14132 /* first packets, read length values */
14133 for (i = 0; i < num_packets - 1; i++) {
14135 while (offset < codec_data_size) {
14136 length[i] += p[offset];
14137 if (p[offset++] != 0xff)
14142 if (offset + last > codec_data_size)
14145 /* last packet is the remaining size */
14146 length[i] = codec_data_size - offset - last;
14148 for (i = 0; i < num_packets; i++) {
14151 GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14153 if (offset + length[i] > codec_data_size)
14156 hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
14157 list = g_list_append (list, hdr);
14159 offset += length[i];
14168 g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14174 /* this can change the codec originally present in @list */
14176 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14177 QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14179 int len = QT_UINT32 (esds->data);
14180 guint8 *ptr = esds->data;
14181 guint8 *end = ptr + len;
14183 guint8 *data_ptr = NULL;
14185 guint8 object_type_id = 0;
14186 guint8 stream_type = 0;
14187 const char *codec_name = NULL;
14188 GstCaps *caps = NULL;
14190 GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14192 GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14194 while (ptr + 1 < end) {
14195 tag = QT_UINT8 (ptr);
14196 GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14198 len = read_descr_size (ptr, end, &ptr);
14199 GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14201 /* Check the stated amount of data is available for reading */
14202 if (len < 0 || ptr + len > end)
14206 case ES_DESCRIPTOR_TAG:
14207 GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14208 GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14211 case DECODER_CONFIG_DESC_TAG:{
14212 guint max_bitrate, avg_bitrate;
14214 object_type_id = QT_UINT8 (ptr);
14215 stream_type = QT_UINT8 (ptr + 1) >> 2;
14216 max_bitrate = QT_UINT32 (ptr + 5);
14217 avg_bitrate = QT_UINT32 (ptr + 9);
14218 GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14219 GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14220 GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14221 GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14222 GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14223 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14224 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14225 GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14227 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14228 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14229 avg_bitrate, NULL);
14234 case DECODER_SPECIFIC_INFO_TAG:
14235 GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14236 if (object_type_id == 0xe0 && len == 0x40) {
14242 GST_DEBUG_OBJECT (qtdemux,
14243 "Have VOBSUB palette. Creating palette event");
14244 /* move to decConfigDescr data and read palette */
14246 for (i = 0; i < 16; i++) {
14247 clut[i] = QT_UINT32 (data);
14251 s = gst_structure_new ("application/x-gst-dvd", "event",
14252 G_TYPE_STRING, "dvd-spu-clut-change",
14253 "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
14254 "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
14255 "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
14256 "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
14257 "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
14258 "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
14259 "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
14260 "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
14263 /* store event and trigger custom processing */
14264 stream->pending_event =
14265 gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
14267 /* Generic codec_data handler puts it on the caps */
14274 case SL_CONFIG_DESC_TAG:
14275 GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
14279 GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
14281 GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
14287 /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
14288 * in use, and should also be used to override some other parameters for some
14290 switch (object_type_id) {
14291 case 0x20: /* MPEG-4 */
14292 /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
14293 * profile_and_level_indication */
14294 if (data_ptr != NULL && data_len >= 5 &&
14295 GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
14296 gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
14297 data_ptr + 4, data_len - 4);
14299 break; /* Nothing special needed here */
14300 case 0x21: /* H.264 */
14301 codec_name = "H.264 / AVC";
14302 caps = gst_caps_new_simple ("video/x-h264",
14303 "stream-format", G_TYPE_STRING, "avc",
14304 "alignment", G_TYPE_STRING, "au", NULL);
14306 case 0x40: /* AAC (any) */
14307 case 0x66: /* AAC Main */
14308 case 0x67: /* AAC LC */
14309 case 0x68: /* AAC SSR */
14310 /* Override channels and rate based on the codec_data, as it's often
14312 /* Only do so for basic setup without HE-AAC extension */
14313 if (data_ptr && data_len == 2) {
14314 guint channels, rate;
14316 channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
14318 entry->n_channels = channels;
14320 rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
14322 entry->rate = rate;
14325 /* Set level and profile if possible */
14326 if (data_ptr != NULL && data_len >= 2) {
14327 gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
14328 data_ptr, data_len);
14330 const gchar *profile_str = NULL;
14333 guint8 *codec_data;
14334 gint rate_idx, profile;
14336 /* No codec_data, let's invent something.
14337 * FIXME: This is wrong for SBR! */
14339 GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
14341 buffer = gst_buffer_new_and_alloc (2);
14342 gst_buffer_map (buffer, &map, GST_MAP_WRITE);
14343 codec_data = map.data;
14346 gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14349 switch (object_type_id) {
14351 profile_str = "main";
14355 profile_str = "lc";
14359 profile_str = "ssr";
14367 codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14369 ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14371 gst_buffer_unmap (buffer, &map);
14372 gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14373 GST_TYPE_BUFFER, buffer, NULL);
14374 gst_buffer_unref (buffer);
14377 gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14378 G_TYPE_STRING, profile_str, NULL);
14382 case 0x60: /* MPEG-2, various profiles */
14388 codec_name = "MPEG-2 video";
14389 caps = gst_caps_new_simple ("video/mpeg",
14390 "mpegversion", G_TYPE_INT, 2,
14391 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14393 case 0x69: /* MPEG-2 BC audio */
14394 case 0x6B: /* MPEG-1 audio */
14395 caps = gst_caps_new_simple ("audio/mpeg",
14396 "mpegversion", G_TYPE_INT, 1, NULL);
14397 codec_name = "MPEG-1 audio";
14399 case 0x6A: /* MPEG-1 */
14400 codec_name = "MPEG-1 video";
14401 caps = gst_caps_new_simple ("video/mpeg",
14402 "mpegversion", G_TYPE_INT, 1,
14403 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14405 case 0x6C: /* MJPEG */
14407 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14409 codec_name = "Motion-JPEG";
14411 case 0x6D: /* PNG */
14413 gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14415 codec_name = "PNG still images";
14417 case 0x6E: /* JPEG2000 */
14418 codec_name = "JPEG-2000";
14419 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14421 case 0xA4: /* Dirac */
14422 codec_name = "Dirac";
14423 caps = gst_caps_new_empty_simple ("video/x-dirac");
14425 case 0xA5: /* AC3 */
14426 codec_name = "AC-3 audio";
14427 caps = gst_caps_new_simple ("audio/x-ac3",
14428 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14430 case 0xA9: /* AC3 */
14431 codec_name = "DTS audio";
14432 caps = gst_caps_new_simple ("audio/x-dts",
14433 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14436 if (stream_type == 0x05 && data_ptr) {
14438 parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
14441 GValue arr_val = G_VALUE_INIT;
14442 GValue buf_val = G_VALUE_INIT;
14445 /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
14446 codec_name = "Vorbis";
14447 caps = gst_caps_new_empty_simple ("audio/x-vorbis");
14448 g_value_init (&arr_val, GST_TYPE_ARRAY);
14449 g_value_init (&buf_val, GST_TYPE_BUFFER);
14450 for (tmp = headers; tmp; tmp = tmp->next) {
14451 g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
14452 gst_value_array_append_value (&arr_val, &buf_val);
14454 s = gst_caps_get_structure (caps, 0);
14455 gst_structure_take_value (s, "streamheader", &arr_val);
14456 g_value_unset (&buf_val);
14457 g_list_free (headers);
14464 case 0xE1: /* QCELP */
14465 /* QCELP, the codec_data is a riff tag (little endian) with
14466 * 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). */
14467 caps = gst_caps_new_empty_simple ("audio/qcelp");
14468 codec_name = "QCELP";
14474 /* If we have a replacement caps, then change our caps for this stream */
14476 gst_caps_unref (entry->caps);
14477 entry->caps = caps;
14480 if (codec_name && list)
14481 gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14482 GST_TAG_AUDIO_CODEC, codec_name, NULL);
14484 /* Add the codec_data attribute to caps, if we have it */
14488 buffer = gst_buffer_new_and_alloc (data_len);
14489 gst_buffer_fill (buffer, 0, data_ptr, data_len);
14491 GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14492 GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14494 gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14496 gst_buffer_unref (buffer);
14501 static inline GstCaps *
14502 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14506 char *s, fourstr[5];
14508 g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14509 for (i = 0; i < 4; i++) {
14510 if (!g_ascii_isalnum (fourstr[i]))
14513 s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14514 caps = gst_caps_new_empty_simple (s);
14519 #define _codec(name) \
14521 if (codec_name) { \
14522 *codec_name = g_strdup (name); \
14527 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14528 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14529 const guint8 * stsd_entry_data, gchar ** codec_name)
14531 GstCaps *caps = NULL;
14532 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14536 _codec ("PNG still images");
14537 caps = gst_caps_new_empty_simple ("image/png");
14540 _codec ("JPEG still images");
14542 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14545 case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14546 case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14547 case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14548 case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14549 _codec ("Motion-JPEG");
14551 gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14554 case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14555 _codec ("Motion-JPEG format B");
14556 caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14559 _codec ("JPEG-2000");
14560 /* override to what it should be according to spec, avoid palette_data */
14561 entry->bits_per_sample = 24;
14562 caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14565 _codec ("Sorensen video v.3");
14566 caps = gst_caps_new_simple ("video/x-svq",
14567 "svqversion", G_TYPE_INT, 3, NULL);
14569 case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14570 case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14571 _codec ("Sorensen video v.1");
14572 caps = gst_caps_new_simple ("video/x-svq",
14573 "svqversion", G_TYPE_INT, 1, NULL);
14575 case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14576 caps = gst_caps_new_empty_simple ("video/x-raw");
14577 gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14578 _codec ("Windows Raw RGB");
14579 stream->alignment = 32;
14585 bps = QT_UINT16 (stsd_entry_data + 82);
14588 format = GST_VIDEO_FORMAT_RGB15;
14591 format = GST_VIDEO_FORMAT_RGB16;
14594 format = GST_VIDEO_FORMAT_RGB;
14597 format = GST_VIDEO_FORMAT_ARGB;
14605 case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14606 format = GST_VIDEO_FORMAT_I420;
14608 case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14609 case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14610 format = GST_VIDEO_FORMAT_I420;
14613 case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14614 format = GST_VIDEO_FORMAT_UYVY;
14616 case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14617 format = GST_VIDEO_FORMAT_v308;
14619 case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14620 format = GST_VIDEO_FORMAT_v216;
14623 format = GST_VIDEO_FORMAT_v210;
14625 case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14626 format = GST_VIDEO_FORMAT_r210;
14628 /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14629 case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14630 format = GST_VIDEO_FORMAT_v410;
14633 /* Packed YUV 4:4:4:4 8 bit in 32 bits
14634 * but different order than AYUV
14635 case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14636 format = GST_VIDEO_FORMAT_v408;
14639 case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14640 case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14641 _codec ("MPEG-1 video");
14642 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14643 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14645 case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14646 case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14647 case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14648 case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14649 case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14650 case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14651 case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14652 case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14653 case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14654 case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14655 case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14656 case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14657 case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14658 case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14659 case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14660 case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14661 case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14662 case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14663 case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14664 case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14665 case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14666 case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14667 case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14668 case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14669 case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14670 case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14671 case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14672 case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14673 case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14674 case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14675 case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14676 case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14677 case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14678 case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14679 case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14680 case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14681 case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14682 case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14683 case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14684 case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14685 case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14686 case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14687 case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14688 case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14689 case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14690 case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14691 case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14692 _codec ("MPEG-2 video");
14693 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14694 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14696 case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14697 _codec ("GIF still images");
14698 caps = gst_caps_new_empty_simple ("image/gif");
14701 case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14703 case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14705 /* ffmpeg uses the height/width props, don't know why */
14706 caps = gst_caps_new_simple ("video/x-h263",
14707 "variant", G_TYPE_STRING, "itu", NULL);
14711 _codec ("MPEG-4 video");
14712 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14713 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14715 case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14716 case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14717 _codec ("Microsoft MPEG-4 4.3"); /* FIXME? */
14718 caps = gst_caps_new_simple ("video/x-msmpeg",
14719 "msmpegversion", G_TYPE_INT, 43, NULL);
14721 case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14723 caps = gst_caps_new_simple ("video/x-divx",
14724 "divxversion", G_TYPE_INT, 3, NULL);
14726 case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14727 case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14729 caps = gst_caps_new_simple ("video/x-divx",
14730 "divxversion", G_TYPE_INT, 4, NULL);
14732 case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14734 caps = gst_caps_new_simple ("video/x-divx",
14735 "divxversion", G_TYPE_INT, 5, NULL);
14738 case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14740 caps = gst_caps_new_simple ("video/x-ffv",
14741 "ffvversion", G_TYPE_INT, 1, NULL);
14744 case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14745 case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14750 case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14751 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14752 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14756 case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14757 _codec ("Cinepak");
14758 caps = gst_caps_new_empty_simple ("video/x-cinepak");
14760 case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14761 _codec ("Apple QuickDraw");
14762 caps = gst_caps_new_empty_simple ("video/x-qdrw");
14764 case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14765 _codec ("Apple video");
14766 caps = gst_caps_new_empty_simple ("video/x-apple-video");
14770 _codec ("H.264 / AVC");
14771 caps = gst_caps_new_simple ("video/x-h264",
14772 "stream-format", G_TYPE_STRING, "avc",
14773 "alignment", G_TYPE_STRING, "au", NULL);
14776 _codec ("H.264 / AVC");
14777 caps = gst_caps_new_simple ("video/x-h264",
14778 "stream-format", G_TYPE_STRING, "avc3",
14779 "alignment", G_TYPE_STRING, "au", NULL);
14783 _codec ("H.265 / HEVC");
14784 caps = gst_caps_new_simple ("video/x-h265",
14785 "stream-format", G_TYPE_STRING, "hvc1",
14786 "alignment", G_TYPE_STRING, "au", NULL);
14789 _codec ("H.265 / HEVC");
14790 caps = gst_caps_new_simple ("video/x-h265",
14791 "stream-format", G_TYPE_STRING, "hev1",
14792 "alignment", G_TYPE_STRING, "au", NULL);
14795 _codec ("Run-length encoding");
14796 caps = gst_caps_new_simple ("video/x-rle",
14797 "layout", G_TYPE_STRING, "quicktime", NULL);
14800 _codec ("Run-length encoding");
14801 caps = gst_caps_new_simple ("video/x-rle",
14802 "layout", G_TYPE_STRING, "microsoft", NULL);
14804 case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14805 case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14806 _codec ("Indeo Video 3");
14807 caps = gst_caps_new_simple ("video/x-indeo",
14808 "indeoversion", G_TYPE_INT, 3, NULL);
14810 case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14811 case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14812 _codec ("Intel Video 4");
14813 caps = gst_caps_new_simple ("video/x-indeo",
14814 "indeoversion", G_TYPE_INT, 4, NULL);
14818 case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14819 case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14820 case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14821 case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14822 case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14823 case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14824 _codec ("DV Video");
14825 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14826 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14828 case FOURCC_dv5n: /* DVCPRO50 NTSC */
14829 case FOURCC_dv5p: /* DVCPRO50 PAL */
14830 _codec ("DVCPro50 Video");
14831 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14832 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14834 case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14835 case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14836 _codec ("DVCProHD Video");
14837 caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14838 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14840 case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14841 _codec ("Apple Graphics (SMC)");
14842 caps = gst_caps_new_empty_simple ("video/x-smc");
14844 case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14846 caps = gst_caps_new_empty_simple ("video/x-vp3");
14848 case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14849 _codec ("VP6 Flash");
14850 caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14854 caps = gst_caps_new_empty_simple ("video/x-theora");
14855 /* theora uses one byte of padding in the data stream because it does not
14856 * allow 0 sized packets while theora does */
14857 entry->padding = 1;
14861 caps = gst_caps_new_empty_simple ("video/x-dirac");
14863 case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14864 _codec ("TIFF still images");
14865 caps = gst_caps_new_empty_simple ("image/tiff");
14867 case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14868 _codec ("Apple Intermediate Codec");
14869 caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14871 case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14872 _codec ("AVID DNxHD");
14873 caps = gst_caps_from_string ("video/x-dnxhd");
14877 _codec ("On2 VP8");
14878 caps = gst_caps_from_string ("video/x-vp8");
14881 _codec ("Google VP9");
14882 caps = gst_caps_from_string ("video/x-vp9");
14885 _codec ("Apple ProRes LT");
14887 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14891 _codec ("Apple ProRes HQ");
14893 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14897 _codec ("Apple ProRes");
14899 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14903 _codec ("Apple ProRes Proxy");
14905 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14909 _codec ("Apple ProRes 4444");
14911 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14915 _codec ("Apple ProRes 4444 XQ");
14917 gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14921 _codec ("GoPro CineForm");
14922 caps = gst_caps_from_string ("video/x-cineform");
14927 caps = gst_caps_new_simple ("video/x-wmv",
14928 "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14932 caps = gst_caps_new_empty_simple ("video/x-av1");
14934 case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14937 caps = _get_unknown_codec_name ("video", fourcc);
14942 if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14945 gst_video_info_init (&info);
14946 gst_video_info_set_format (&info, format, entry->width, entry->height);
14948 caps = gst_video_info_to_caps (&info);
14949 *codec_name = gst_pb_utils_get_codec_description (caps);
14951 /* enable clipping for raw video streams */
14952 stream->need_clip = TRUE;
14953 stream->alignment = 32;
14960 round_up_pow2 (guint n)
14972 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14973 QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14974 int len, gchar ** codec_name)
14977 const GstStructure *s;
14980 GstAudioFormat format = 0;
14983 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14985 depth = entry->bytes_per_packet * 8;
14988 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14990 /* 8-bit audio is unsigned */
14992 format = GST_AUDIO_FORMAT_U8;
14993 /* otherwise it's signed and big-endian just like 'twos' */
14995 endian = G_BIG_ENDIAN;
15002 endian = G_LITTLE_ENDIAN;
15005 format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15007 str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15011 caps = gst_caps_new_simple ("audio/x-raw",
15012 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15013 "layout", G_TYPE_STRING, "interleaved", NULL);
15014 stream->alignment = GST_ROUND_UP_8 (depth);
15015 stream->alignment = round_up_pow2 (stream->alignment);
15018 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
15019 _codec ("Raw 64-bit floating-point audio");
15020 caps = gst_caps_new_simple ("audio/x-raw",
15021 "format", G_TYPE_STRING, "F64BE",
15022 "layout", G_TYPE_STRING, "interleaved", NULL);
15023 stream->alignment = 8;
15025 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
15026 _codec ("Raw 32-bit floating-point audio");
15027 caps = gst_caps_new_simple ("audio/x-raw",
15028 "format", G_TYPE_STRING, "F32BE",
15029 "layout", G_TYPE_STRING, "interleaved", NULL);
15030 stream->alignment = 4;
15033 _codec ("Raw 24-bit PCM audio");
15034 /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15036 caps = gst_caps_new_simple ("audio/x-raw",
15037 "format", G_TYPE_STRING, "S24BE",
15038 "layout", G_TYPE_STRING, "interleaved", NULL);
15039 stream->alignment = 4;
15041 case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
15042 _codec ("Raw 32-bit PCM audio");
15043 caps = gst_caps_new_simple ("audio/x-raw",
15044 "format", G_TYPE_STRING, "S32BE",
15045 "layout", G_TYPE_STRING, "interleaved", NULL);
15046 stream->alignment = 4;
15048 case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
15049 _codec ("Raw 16-bit PCM audio");
15050 caps = gst_caps_new_simple ("audio/x-raw",
15051 "format", G_TYPE_STRING, "S16LE",
15052 "layout", G_TYPE_STRING, "interleaved", NULL);
15053 stream->alignment = 2;
15056 _codec ("Mu-law audio");
15057 caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15060 _codec ("A-law audio");
15061 caps = gst_caps_new_empty_simple ("audio/x-alaw");
15065 _codec ("Microsoft ADPCM");
15066 /* Microsoft ADPCM-ACM code 2 */
15067 caps = gst_caps_new_simple ("audio/x-adpcm",
15068 "layout", G_TYPE_STRING, "microsoft", NULL);
15072 _codec ("DVI/IMA ADPCM");
15073 caps = gst_caps_new_simple ("audio/x-adpcm",
15074 "layout", G_TYPE_STRING, "dvi", NULL);
15078 _codec ("DVI/Intel IMA ADPCM");
15079 /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15080 caps = gst_caps_new_simple ("audio/x-adpcm",
15081 "layout", G_TYPE_STRING, "quicktime", NULL);
15085 /* MPEG layer 3, CBR only (pre QT4.1) */
15087 _codec ("MPEG-1 layer 3");
15088 /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15089 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15090 "mpegversion", G_TYPE_INT, 1, NULL);
15092 case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15093 _codec ("MPEG-1 layer 2");
15095 caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15096 "mpegversion", G_TYPE_INT, 1, NULL);
15099 case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15100 _codec ("EAC-3 audio");
15101 caps = gst_caps_new_simple ("audio/x-eac3",
15102 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15103 entry->sampled = TRUE;
15105 case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15107 _codec ("AC-3 audio");
15108 caps = gst_caps_new_simple ("audio/x-ac3",
15109 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15110 entry->sampled = TRUE;
15112 case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15113 case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15114 _codec ("DTS audio");
15115 caps = gst_caps_new_simple ("audio/x-dts",
15116 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15117 entry->sampled = TRUE;
15119 case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15120 case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15121 _codec ("DTS-HD audio");
15122 caps = gst_caps_new_simple ("audio/x-dts",
15123 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15124 entry->sampled = TRUE;
15128 caps = gst_caps_new_simple ("audio/x-mace",
15129 "maceversion", G_TYPE_INT, 3, NULL);
15133 caps = gst_caps_new_simple ("audio/x-mace",
15134 "maceversion", G_TYPE_INT, 6, NULL);
15136 case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15138 caps = gst_caps_new_empty_simple ("application/ogg");
15140 case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15141 _codec ("DV audio");
15142 caps = gst_caps_new_empty_simple ("audio/x-dv");
15145 _codec ("MPEG-4 AAC audio");
15146 caps = gst_caps_new_simple ("audio/mpeg",
15147 "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15148 "stream-format", G_TYPE_STRING, "raw", NULL);
15150 case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15151 _codec ("QDesign Music");
15152 caps = gst_caps_new_empty_simple ("audio/x-qdm");
15155 _codec ("QDesign Music v.2");
15156 /* FIXME: QDesign music version 2 (no constant) */
15157 if (FALSE && data) {
15158 caps = gst_caps_new_simple ("audio/x-qdm2",
15159 "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15160 "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15161 "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15163 caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15167 _codec ("GSM audio");
15168 caps = gst_caps_new_empty_simple ("audio/x-gsm");
15171 _codec ("AMR audio");
15172 caps = gst_caps_new_empty_simple ("audio/AMR");
15175 _codec ("AMR-WB audio");
15176 caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15179 _codec ("Quicktime IMA ADPCM");
15180 caps = gst_caps_new_simple ("audio/x-adpcm",
15181 "layout", G_TYPE_STRING, "quicktime", NULL);
15184 _codec ("Apple lossless audio");
15185 caps = gst_caps_new_empty_simple ("audio/x-alac");
15188 _codec ("Free Lossless Audio Codec");
15189 caps = gst_caps_new_simple ("audio/x-flac",
15190 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15192 case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15193 _codec ("QualComm PureVoice");
15194 caps = gst_caps_from_string ("audio/qcelp");
15199 caps = gst_caps_new_empty_simple ("audio/x-wma");
15203 caps = gst_caps_new_empty_simple ("audio/x-opus");
15210 GstAudioFormat format;
15213 FLAG_IS_FLOAT = 0x1,
15214 FLAG_IS_BIG_ENDIAN = 0x2,
15215 FLAG_IS_SIGNED = 0x4,
15216 FLAG_IS_PACKED = 0x8,
15217 FLAG_IS_ALIGNED_HIGH = 0x10,
15218 FLAG_IS_NON_INTERLEAVED = 0x20
15220 _codec ("Raw LPCM audio");
15222 if (data && len >= 36) {
15223 depth = QT_UINT32 (data + 24);
15224 flags = QT_UINT32 (data + 28);
15225 width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15227 if ((flags & FLAG_IS_FLOAT) == 0) {
15232 if ((flags & FLAG_IS_ALIGNED_HIGH))
15235 format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15236 TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15237 G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15238 caps = gst_caps_new_simple ("audio/x-raw",
15239 "format", G_TYPE_STRING,
15241 GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15242 "UNKNOWN", "layout", G_TYPE_STRING,
15243 (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15244 "interleaved", NULL);
15245 stream->alignment = GST_ROUND_UP_8 (depth);
15246 stream->alignment = round_up_pow2 (stream->alignment);
15251 if (flags & FLAG_IS_BIG_ENDIAN)
15252 format = GST_AUDIO_FORMAT_F64BE;
15254 format = GST_AUDIO_FORMAT_F64LE;
15256 if (flags & FLAG_IS_BIG_ENDIAN)
15257 format = GST_AUDIO_FORMAT_F32BE;
15259 format = GST_AUDIO_FORMAT_F32LE;
15261 caps = gst_caps_new_simple ("audio/x-raw",
15262 "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15263 "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
15264 "non-interleaved" : "interleaved", NULL);
15265 stream->alignment = width / 8;
15269 case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
15273 caps = _get_unknown_codec_name ("audio", fourcc);
15279 GstCaps *templ_caps =
15280 gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
15281 GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
15282 gst_caps_unref (caps);
15283 gst_caps_unref (templ_caps);
15284 caps = intersection;
15287 /* enable clipping for raw audio streams */
15288 s = gst_caps_get_structure (caps, 0);
15289 name = gst_structure_get_name (s);
15290 if (g_str_has_prefix (name, "audio/x-raw")) {
15291 stream->need_clip = TRUE;
15292 stream->max_buffer_size = 4096 * entry->bytes_per_frame;
15293 GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
15299 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15300 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15301 const guint8 * stsd_entry_data, gchar ** codec_name)
15305 GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15309 _codec ("DVD subtitle");
15310 caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
15311 stream->need_process = TRUE;
15314 _codec ("Quicktime timed text");
15317 _codec ("3GPP timed text");
15319 caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
15321 /* actual text piece needs to be extracted */
15322 stream->need_process = TRUE;
15325 _codec ("XML subtitles");
15326 caps = gst_caps_new_empty_simple ("application/ttml+xml");
15329 _codec ("CEA 608 Closed Caption");
15331 gst_caps_new_simple ("closedcaption/x-cea-608", "format",
15332 G_TYPE_STRING, "cc_data", NULL);
15333 stream->need_process = TRUE;
15336 _codec ("CEA 708 Closed Caption");
15338 gst_caps_new_simple ("closedcaption/x-cea-708", "format",
15339 G_TYPE_STRING, "cdp", NULL);
15340 stream->need_process = TRUE;
15345 caps = _get_unknown_codec_name ("text", fourcc);
15353 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15354 QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15355 const guint8 * stsd_entry_data, gchar ** codec_name)
15361 _codec ("MPEG 1 video");
15362 caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15363 "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15373 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
15374 const gchar * system_id)
15378 if (!qtdemux->protection_system_ids)
15379 qtdemux->protection_system_ids =
15380 g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
15381 /* Check whether we already have an entry for this system ID. */
15382 for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
15383 const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
15384 if (g_ascii_strcasecmp (system_id, id) == 0) {
15388 GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
15389 g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,