138002db4df3d00137c321417cb61ee27a482ce6
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-good / gst / isomp4 / qtdemux.c
1 /* GStreamer
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
13  *
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.
18  *
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.
23  *
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.
28  */
29
30 /**
31  * SECTION:element-qtdemux
32  * @title: qtdemux
33  *
34  * Demuxes a .mov file into raw or compressed audio and/or video streams.
35  *
36  * This element supports both push and pull-based scheduling, depending on the
37  * capabilities of the upstream elements.
38  *
39  * ## Example launch line
40  * |[
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.
46  *
47  */
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include <glib/gi18n-lib.h>
54
55 #include <glib/gprintf.h>
56 #include <gst/base/base.h>
57 #include <gst/tag/tag.h>
58 #include <gst/audio/audio.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
61
62 #include "gstisomp4elements.h"
63 #include "qtatomparser.h"
64 #include "qtdemux_types.h"
65 #include "qtdemux_dump.h"
66 #include "fourcc.h"
67 #include "descriptors.h"
68 #include "qtdemux_lang.h"
69 #include "qtdemux.h"
70 #include "qtpalette.h"
71 #include "qtdemux_tags.h"
72 #include "qtdemux_tree.h"
73 #include "qtdemux-webvtt.h"
74
75 #include <stdlib.h>
76 #include <string.h>
77
78 #include <math.h>
79 #include <gst/math-compat.h>
80
81 #ifdef HAVE_ZLIB
82 #include <zlib.h>
83 #endif
84
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (32*1024*1024)
87
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
90
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
98
99 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
100
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
102
103 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
104 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
105 #define QTDEMUX_NTH_STREAM(demux,idx) \
106    QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
107 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
108    QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
109
110 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
111
112 GST_DEBUG_CATEGORY (qtdemux_debug);
113 #define GST_CAT_DEFAULT qtdemux_debug
114
115 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
116 typedef struct _QtDemuxAavdEncryptionInfo QtDemuxAavdEncryptionInfo;
117
118 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
119 typedef struct _QtDemuxSphericalMetadata QtDemuxSphericalMetadata;
120
121 struct _QtDemuxSphericalMetadata
122 {
123   gboolean is_spherical;
124   gboolean is_stitched;
125   char *stitching_software;
126   char *projection_type;
127   char *stereo_mode;
128   int source_count;
129   int init_view_heading;
130   int init_view_pitch;
131   int init_view_roll;
132   int timestamp;
133   int full_pano_width_pixels;
134   int full_pano_height_pixels;
135   int cropped_area_image_width;
136   int cropped_area_image_height;
137   int cropped_area_left;
138   int cropped_area_top;
139   QTDEMUX_AMBISONIC_TYPE ambisonic_type;
140   QTDEMUX_AMBISONIC_FORMAT ambisonic_format;
141   QTDEMUX_AMBISONIC_ORDER ambisonic_order;
142 };
143
144 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
145
146 /* Macros for converting to/from timescale */
147 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
148 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
149
150 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
151 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
152
153 /* timestamp is the DTS */
154 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
155 /* timestamp + offset + cslg_shift is the outgoing PTS */
156 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
157 /* timestamp + offset is the PTS used for internal seek calculations */
158 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
159 /* timestamp + duration - dts is the duration */
160 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
161
162 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
163
164 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
165 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
166     GST_TRACE("Locking from thread %p", g_thread_self()); \
167     g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
168     GST_TRACE("Locked from thread %p", g_thread_self()); \
169  } G_STMT_END
170
171 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
172     GST_TRACE("Unlocking from thread %p", g_thread_self()); \
173     g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
174  } G_STMT_END
175
176 /*
177  * Quicktime has tracks and segments. A track is a continuous piece of
178  * multimedia content. The track is not always played from start to finish but
179  * instead, pieces of the track are 'cut out' and played in sequence. This is
180  * what the segments do.
181  *
182  * Inside the track we have keyframes (K) and delta frames. The track has its
183  * own timing, which starts from 0 and extends to end. The position in the track
184  * is called the media_time.
185  *
186  * The segments now describe the pieces that should be played from this track
187  * and are basically tuples of media_time/duration/rate entries. We can have
188  * multiple segments and they are all played after one another. An example:
189  *
190  * segment 1: media_time: 1 second, duration: 1 second, rate 1
191  * segment 2: media_time: 3 second, duration: 2 second, rate 2
192  *
193  * To correctly play back this track, one must play: 1 second of media starting
194  * from media_time 1 followed by 2 seconds of media starting from media_time 3
195  * at a rate of 2.
196  *
197  * Each of the segments will be played at a specific time, the first segment at
198  * time 0, the second one after the duration of the first one, etc.. Note that
199  * the time in resulting playback is not identical to the media_time of the
200  * track anymore.
201  *
202  * Visually, assuming the track has 4 second of media_time:
203  *
204  *                (a)                   (b)          (c)              (d)
205  *         .-----------------------------------------------------------.
206  * track:  | K.....K.........K........K.......K.......K...........K... |
207  *         '-----------------------------------------------------------'
208  *         0              1              2              3              4
209  *           .------------^              ^   .----------^              ^
210  *          /              .-------------'  /       .------------------'
211  *         /              /          .-----'       /
212  *         .--------------.         .--------------.
213  *         | segment 1    |         | segment 2    |
214  *         '--------------'         '--------------'
215  *
216  * The challenge here is to cut out the right pieces of the track for each of
217  * the playback segments. This fortunately can easily be done with the SEGMENT
218  * events of GStreamer.
219  *
220  * For playback of segment 1, we need to provide the decoder with the keyframe
221  * (a), in the above figure, but we must instruct it only to output the decoded
222  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
223  * position set to the time of the segment: 0.
224  *
225  * We then proceed to push data from keyframe (a) to frame (b). The decoder
226  * decodes but clips all before media_time 1.
227  *
228  * After finishing a segment, we push out a new SEGMENT event with the clipping
229  * boundaries of the new data.
230  *
231  * This is a good usecase for the GStreamer accumulated SEGMENT events.
232  */
233
234 struct _QtDemuxSegment
235 {
236   /* global time and duration, all gst time */
237   GstClockTime time;
238   GstClockTime stop_time;
239   GstClockTime duration;
240   /* media time of trak, all gst time */
241   GstClockTime media_start;
242   GstClockTime media_stop;
243   gdouble rate;
244   /* Media start time in trak timescale units */
245   guint32 trak_media_start;
246 };
247
248 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
249
250 /* Used with fragmented MP4 files (mfra atom) */
251 struct _QtDemuxRandomAccessEntry
252 {
253   GstClockTime ts;
254   guint64 moof_offset;
255 };
256
257
258 /* Contains properties and cryptographic info for a set of samples from a
259  * track protected using Common Encryption (cenc) */
260 struct _QtDemuxCencSampleSetInfo
261 {
262   GstStructure *default_properties;
263
264   /* @crypto_info holds one GstStructure per sample */
265   GPtrArray *crypto_info;
266 };
267
268 struct _QtDemuxAavdEncryptionInfo
269 {
270   GstStructure *default_properties;
271 };
272
273 static const gchar *
274 qt_demux_state_string (enum QtDemuxState state)
275 {
276   switch (state) {
277     case QTDEMUX_STATE_INITIAL:
278       return "<INITIAL>";
279     case QTDEMUX_STATE_HEADER:
280       return "<HEADER>";
281     case QTDEMUX_STATE_MOVIE:
282       return "<MOVIE>";
283     case QTDEMUX_STATE_BUFFER_MDAT:
284       return "<BUFFER_MDAT>";
285     default:
286       return "<UNKNOWN>";
287   }
288 }
289
290 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
291
292 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
293
294 static GstStaticPadTemplate gst_qtdemux_sink_template =
295     GST_STATIC_PAD_TEMPLATE ("sink",
296     GST_PAD_SINK,
297     GST_PAD_ALWAYS,
298     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
299         "application/x-3gp")
300     );
301
302 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
303 GST_STATIC_PAD_TEMPLATE ("video_%u",
304     GST_PAD_SRC,
305     GST_PAD_SOMETIMES,
306     GST_STATIC_CAPS_ANY);
307
308 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
309 GST_STATIC_PAD_TEMPLATE ("audio_%u",
310     GST_PAD_SRC,
311     GST_PAD_SOMETIMES,
312     GST_STATIC_CAPS_ANY);
313
314 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
315 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
316     GST_PAD_SRC,
317     GST_PAD_SOMETIMES,
318     GST_STATIC_CAPS_ANY);
319
320 static GstStaticPadTemplate gst_qtdemux_metasrc_template =
321 GST_STATIC_PAD_TEMPLATE ("meta_%u",
322     GST_PAD_SRC,
323     GST_PAD_SOMETIMES,
324     GST_STATIC_CAPS_ANY);
325
326 #define gst_qtdemux_parent_class parent_class
327 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
328 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qtdemux, "qtdemux",
329     GST_RANK_PRIMARY, GST_TYPE_QTDEMUX, isomp4_element_init (plugin));
330
331 static void gst_qtdemux_dispose (GObject * object);
332 static void gst_qtdemux_finalize (GObject * object);
333
334 static guint32
335 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
336     GstClockTime media_time);
337 static guint32
338 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
339     QtDemuxStream * str, gint64 media_offset);
340
341 #if 0
342 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
343 static GstIndex *gst_qtdemux_get_index (GstElement * element);
344 #endif
345 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
346     GstStateChange transition);
347 static void gst_qtdemux_set_context (GstElement * element,
348     GstContext * context);
349 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
350 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
351     GstObject * parent, GstPadMode mode, gboolean active);
352
353 static void gst_qtdemux_loop (GstPad * pad);
354 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
355     GstBuffer * inbuf);
356 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
357     GstEvent * event);
358 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
359     GstQuery * query);
360 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
361 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
362     QtDemuxStream * stream);
363 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
364     QtDemuxStream * stream);
365 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
366     gboolean force);
367
368 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
369
370 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
371     const guint8 * buffer, guint length);
372 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
373     const guint8 * buffer, guint length);
374 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
375
376 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
377     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
378     GstTagList * list);
379 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
380     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
381     const guint8 * stsd_entry_data, gchar ** codec_name);
382 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
383     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
384     const guint8 * data, int len, gchar ** codec_name);
385 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
386     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
387     gchar ** codec_name);
388 static GstCaps *qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
389     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
390     gchar ** codec_name);
391 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
392     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
393     const guint8 * stsd_entry_data, gchar ** codec_name);
394
395 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
396     QtDemuxStream * stream, guint32 n);
397 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
398 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
399 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
400 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
401 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
402 static void qtdemux_do_allocation (QtDemuxStream * stream,
403     GstQTDemux * qtdemux);
404 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
405     QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
406 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
407     QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
408     GstClockTime * _start, GstClockTime * _stop);
409 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
410     QtDemuxStream * stream, gint segment_index, GstClockTime pos);
411
412 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
413 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
414
415 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
416
417 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
418     QtDemuxStream * stream, guint sample_index);
419 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
420     const gchar * id);
421 static void qtdemux_gst_structure_free (GstStructure * gststructure);
422 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
423 static void qtdemux_clear_protection_events_on_all_streams (GstQTDemux *
424     qtdemux);
425
426 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
427 static void gst_tag_register_spherical_tags (void);
428 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
429
430 static void
431 gst_qtdemux_class_init (GstQTDemuxClass * klass)
432 {
433   GObjectClass *gobject_class;
434   GstElementClass *gstelement_class;
435
436   gobject_class = (GObjectClass *) klass;
437   gstelement_class = (GstElementClass *) klass;
438
439   parent_class = g_type_class_peek_parent (klass);
440
441   gobject_class->dispose = gst_qtdemux_dispose;
442   gobject_class->finalize = gst_qtdemux_finalize;
443
444   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
445 #if 0
446   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
447   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
448 #endif
449   gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
450
451   gst_tag_register_musicbrainz_tags ();
452
453 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
454   gst_tag_register_spherical_tags ();
455 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
456
457   gst_element_class_add_static_pad_template (gstelement_class,
458       &gst_qtdemux_sink_template);
459   gst_element_class_add_static_pad_template (gstelement_class,
460       &gst_qtdemux_videosrc_template);
461   gst_element_class_add_static_pad_template (gstelement_class,
462       &gst_qtdemux_audiosrc_template);
463   gst_element_class_add_static_pad_template (gstelement_class,
464       &gst_qtdemux_subsrc_template);
465   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
466       "Codec/Demuxer",
467       "Demultiplex a QuickTime file into audio and video streams",
468       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
469
470   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
471   gst_riff_init ();
472 }
473
474 static void
475 gst_qtdemux_init (GstQTDemux * qtdemux)
476 {
477   qtdemux->sinkpad =
478       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
479   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
480   gst_pad_set_activatemode_function (qtdemux->sinkpad,
481       qtdemux_sink_activate_mode);
482   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
483   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
484   gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
485   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
486
487   qtdemux->adapter = gst_adapter_new ();
488   g_queue_init (&qtdemux->protection_event_queue);
489   qtdemux->flowcombiner = gst_flow_combiner_new ();
490   g_mutex_init (&qtdemux->expose_lock);
491
492   qtdemux->active_streams = g_ptr_array_new_with_free_func
493       ((GDestroyNotify) gst_qtdemux_stream_unref);
494   qtdemux->old_streams = g_ptr_array_new_with_free_func
495       ((GDestroyNotify) gst_qtdemux_stream_unref);
496
497 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
498   qtdemux->spherical_metadata = (QtDemuxSphericalMetadata *)
499       malloc (sizeof (QtDemuxSphericalMetadata));
500
501   if (qtdemux->spherical_metadata) {
502     qtdemux->spherical_metadata->is_spherical = FALSE;
503     qtdemux->spherical_metadata->is_stitched = FALSE;
504     qtdemux->spherical_metadata->stitching_software = NULL;
505     qtdemux->spherical_metadata->projection_type = NULL;
506     qtdemux->spherical_metadata->stereo_mode = NULL;
507     qtdemux->spherical_metadata->source_count = 0;
508     qtdemux->spherical_metadata->init_view_heading = 0;
509     qtdemux->spherical_metadata->init_view_pitch = 0;
510     qtdemux->spherical_metadata->init_view_roll = 0;
511     qtdemux->spherical_metadata->timestamp = 0;
512     qtdemux->spherical_metadata->full_pano_width_pixels = 0;
513     qtdemux->spherical_metadata->full_pano_height_pixels = 0;
514     qtdemux->spherical_metadata->cropped_area_image_width = 0;
515     qtdemux->spherical_metadata->cropped_area_image_height = 0;
516     qtdemux->spherical_metadata->cropped_area_left = 0;
517     qtdemux->spherical_metadata->cropped_area_top = 0;
518     qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
519     qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_UNKNOWN;
520     qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_UNKNOWN;
521   }
522 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
523
524   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
525
526   gst_qtdemux_reset (qtdemux, TRUE);
527 }
528
529 static void
530 gst_qtdemux_finalize (GObject * object)
531 {
532   GstQTDemux *qtdemux = GST_QTDEMUX (object);
533
534   g_free (qtdemux->redirect_location);
535
536   G_OBJECT_CLASS (parent_class)->finalize (object);
537 }
538
539 static void
540 gst_qtdemux_dispose (GObject * object)
541 {
542   GstQTDemux *qtdemux = GST_QTDEMUX (object);
543
544 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
545   if (qtdemux->spherical_metadata) {
546     if (qtdemux->spherical_metadata->stitching_software)
547       free(qtdemux->spherical_metadata->stitching_software);
548     if (qtdemux->spherical_metadata->projection_type)
549       free(qtdemux->spherical_metadata->projection_type);
550     if (qtdemux->spherical_metadata->stereo_mode)
551       free(qtdemux->spherical_metadata->stereo_mode);
552
553     free(qtdemux->spherical_metadata);
554     qtdemux->spherical_metadata = NULL;
555   }
556 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
557
558   if (qtdemux->adapter) {
559     g_object_unref (G_OBJECT (qtdemux->adapter));
560     qtdemux->adapter = NULL;
561   }
562   gst_tag_list_unref (qtdemux->tag_list);
563   gst_flow_combiner_free (qtdemux->flowcombiner);
564   g_queue_clear_full (&qtdemux->protection_event_queue,
565       (GDestroyNotify) gst_event_unref);
566
567   g_free (qtdemux->cenc_aux_info_sizes);
568   qtdemux->cenc_aux_info_sizes = NULL;
569   g_mutex_clear (&qtdemux->expose_lock);
570
571   g_ptr_array_free (qtdemux->active_streams, TRUE);
572   g_ptr_array_free (qtdemux->old_streams, TRUE);
573
574   G_OBJECT_CLASS (parent_class)->dispose (object);
575 }
576
577 static void
578 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
579 {
580   if (qtdemux->redirect_location) {
581     GST_ELEMENT_ERROR_WITH_DETAILS (qtdemux, STREAM, DEMUX,
582         (_("This file contains no playable streams.")),
583         ("no known streams found, a redirect message has been posted"),
584         ("redirect-location", G_TYPE_STRING, qtdemux->redirect_location, NULL));
585   } else {
586     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
587         (_("This file contains no playable streams.")),
588         ("no known streams found"));
589   }
590 }
591
592 static GstBuffer *
593 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
594 {
595   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
596       mem, size, 0, size, mem, free_func);
597 }
598
599 static GstFlowReturn
600 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
601     GstBuffer ** buf)
602 {
603   GstFlowReturn flow;
604   GstMapInfo map;
605   gsize bsize;
606
607   if (G_UNLIKELY (size == 0)) {
608     GstFlowReturn ret;
609     GstBuffer *tmp = NULL;
610
611     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
612     if (ret != GST_FLOW_OK)
613       return ret;
614
615     gst_buffer_map (tmp, &map, GST_MAP_READ);
616     size = QT_UINT32 (map.data);
617     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
618
619     gst_buffer_unmap (tmp, &map);
620     gst_buffer_unref (tmp);
621   }
622
623   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
624   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
625     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
626       /* we're pulling header but already got most interesting bits,
627        * so never mind the rest (e.g. tags) (that much) */
628       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
629           size);
630       return GST_FLOW_EOS;
631     } else {
632       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
633           (_("This file is invalid and cannot be played.")),
634           ("atom has bogus size %" G_GUINT64_FORMAT, size));
635       return GST_FLOW_ERROR;
636     }
637   }
638
639   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
640
641   if (G_UNLIKELY (flow != GST_FLOW_OK))
642     return flow;
643
644   bsize = gst_buffer_get_size (*buf);
645   /* Catch short reads - we don't want any partial atoms */
646   if (G_UNLIKELY (bsize < size)) {
647     GST_WARNING_OBJECT (qtdemux,
648         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
649     gst_buffer_unref (*buf);
650     *buf = NULL;
651     return GST_FLOW_EOS;
652   }
653
654   return flow;
655 }
656
657 #if 1
658 static gboolean
659 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
660     GstFormat src_format, gint64 src_value, GstFormat dest_format,
661     gint64 * dest_value)
662 {
663   gboolean res = TRUE;
664   QtDemuxStream *stream = gst_pad_get_element_private (pad);
665   gint32 index;
666
667   if (stream->subtype != FOURCC_vide) {
668     res = FALSE;
669     goto done;
670   }
671
672   switch (src_format) {
673     case GST_FORMAT_TIME:
674       switch (dest_format) {
675         case GST_FORMAT_BYTES:{
676           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
677           if (-1 == index) {
678             res = FALSE;
679             goto done;
680           }
681
682           *dest_value = stream->samples[index].offset;
683
684           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
685               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
686               GST_TIME_ARGS (src_value), *dest_value);
687           break;
688         }
689         default:
690           res = FALSE;
691           break;
692       }
693       break;
694     case GST_FORMAT_BYTES:
695       switch (dest_format) {
696         case GST_FORMAT_TIME:{
697           index =
698               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
699               stream, src_value);
700
701           if (-1 == index) {
702             res = FALSE;
703             goto done;
704           }
705
706           *dest_value =
707               QTSTREAMTIME_TO_GSTTIME (stream,
708               stream->samples[index].timestamp);
709           GST_DEBUG_OBJECT (qtdemux,
710               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
711               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
712           break;
713         }
714         default:
715           res = FALSE;
716           break;
717       }
718       break;
719     default:
720       res = FALSE;
721       break;
722   }
723
724 done:
725   return res;
726 }
727 #endif
728
729 static gboolean
730 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
731 {
732   gboolean res = FALSE;
733
734   *duration = GST_CLOCK_TIME_NONE;
735
736   if (qtdemux->duration != 0 &&
737       qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
738     *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
739     res = TRUE;
740   } else {
741     *duration = GST_CLOCK_TIME_NONE;
742   }
743
744   return res;
745 }
746
747 static gboolean
748 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
749     GstQuery * query)
750 {
751   gboolean res = FALSE;
752   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
753
754   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
755
756   switch (GST_QUERY_TYPE (query)) {
757     case GST_QUERY_POSITION:{
758       GstFormat fmt;
759
760       gst_query_parse_position (query, &fmt, NULL);
761       if (fmt == GST_FORMAT_TIME
762           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
763         gst_query_set_position (query, GST_FORMAT_TIME,
764             qtdemux->segment.position);
765         res = TRUE;
766       }
767     }
768       break;
769     case GST_QUERY_DURATION:{
770       GstFormat fmt;
771
772       gst_query_parse_duration (query, &fmt, NULL);
773       if (fmt == GST_FORMAT_TIME) {
774         /* First try to query upstream */
775         res = gst_pad_query_default (pad, parent, query);
776         if (!res) {
777           GstClockTime duration;
778           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
779             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
780             res = TRUE;
781           }
782         }
783       }
784       break;
785     }
786     case GST_QUERY_CONVERT:{
787       GstFormat src_fmt, dest_fmt;
788       gint64 src_value, dest_value = 0;
789
790       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
791
792       res = gst_qtdemux_src_convert (qtdemux, pad,
793           src_fmt, src_value, dest_fmt, &dest_value);
794       if (res)
795         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
796
797       break;
798     }
799     case GST_QUERY_FORMATS:
800       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
801       res = TRUE;
802       break;
803     case GST_QUERY_SEEKING:{
804       GstFormat fmt;
805       gboolean seekable;
806
807       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
808
809       if (fmt == GST_FORMAT_BYTES) {
810         /* We always refuse BYTES seeks from downstream */
811         break;
812       }
813
814       /* try upstream first */
815       res = gst_pad_query_default (pad, parent, query);
816
817       if (!res) {
818         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
819         if (fmt == GST_FORMAT_TIME) {
820           GstClockTime duration;
821
822           gst_qtdemux_get_duration (qtdemux, &duration);
823           seekable = TRUE;
824           if (!qtdemux->pullbased) {
825             GstQuery *q;
826
827             /* we might be able with help from upstream */
828             seekable = FALSE;
829             q = gst_query_new_seeking (GST_FORMAT_BYTES);
830             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
831               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
832               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
833             }
834             gst_query_unref (q);
835           }
836           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
837           res = TRUE;
838         }
839       }
840       break;
841     }
842     case GST_QUERY_SEGMENT:
843     {
844       GstFormat format;
845       gint64 start, stop;
846
847       format = qtdemux->segment.format;
848
849       start =
850           gst_segment_to_stream_time (&qtdemux->segment, format,
851           qtdemux->segment.start);
852       if ((stop = qtdemux->segment.stop) == -1)
853         stop = qtdemux->segment.duration;
854       else
855         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
856
857       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
858       res = TRUE;
859       break;
860     }
861     default:
862       res = gst_pad_query_default (pad, parent, query);
863       break;
864   }
865
866   return res;
867 }
868
869 static void
870 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
871 {
872   if (G_LIKELY (stream->pad)) {
873     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
874         GST_DEBUG_PAD_NAME (stream->pad));
875
876     if (!gst_tag_list_is_empty (stream->stream_tags)) {
877       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
878           stream->stream_tags);
879       gst_pad_push_event (stream->pad,
880           gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
881 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
882       /* post message qtdemux tag (for early recive application) */
883       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
884             gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
885                   gst_tag_list_copy (stream->stream_tags)));
886 #endif
887     }
888
889     if (G_UNLIKELY (stream->send_global_tags)) {
890       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
891           qtdemux->tag_list);
892       gst_pad_push_event (stream->pad,
893           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
894       stream->send_global_tags = FALSE;
895     }
896   }
897 }
898
899 /* push event on all source pads; takes ownership of the event */
900 static void
901 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
902 {
903   gboolean has_valid_stream = FALSE;
904   GstEventType etype = GST_EVENT_TYPE (event);
905   guint i;
906
907   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
908       GST_EVENT_TYPE_NAME (event));
909
910   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
911     GstPad *pad;
912     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
913     GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
914
915     if ((pad = stream->pad)) {
916       has_valid_stream = TRUE;
917
918       if (etype == GST_EVENT_EOS) {
919         /* let's not send twice */
920         if (stream->sent_eos)
921           continue;
922         stream->sent_eos = TRUE;
923       }
924
925       gst_pad_push_event (pad, gst_event_ref (event));
926     }
927   }
928
929   gst_event_unref (event);
930
931   /* if it is EOS and there are no pads, post an error */
932   if (!has_valid_stream && etype == GST_EVENT_EOS) {
933     gst_qtdemux_post_no_playable_stream_error (qtdemux);
934   }
935 }
936
937 typedef struct
938 {
939   guint64 media_time;
940 } FindData;
941
942 static gint
943 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
944 {
945   if ((gint64) s1->timestamp > *media_time)
946     return 1;
947   if ((gint64) s1->timestamp == *media_time)
948     return 0;
949
950   return -1;
951 }
952
953 /* find the index of the sample that includes the data for @media_time using a
954  * binary search.  Only to be called in optimized cases of linear search below.
955  *
956  * Returns the index of the sample with the corresponding *DTS*.
957  */
958 static guint32
959 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
960     guint64 media_time)
961 {
962   QtDemuxSample *result;
963   guint32 index;
964
965   /* convert media_time to mov format */
966   media_time =
967       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
968
969   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
970       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
971       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
972
973   if (G_LIKELY (result))
974     index = result - str->samples;
975   else
976     index = 0;
977
978   return index;
979 }
980
981
982
983 /* find the index of the sample that includes the data for @media_offset using a
984  * linear search
985  *
986  * Returns the index of the sample.
987  */
988 static guint32
989 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
990     QtDemuxStream * str, gint64 media_offset)
991 {
992   QtDemuxSample *result = str->samples;
993   guint32 index = 0;
994
995   if (result == NULL || str->n_samples == 0)
996     return -1;
997
998   if (media_offset == result->offset)
999     return index;
1000
1001   result++;
1002   while (index < str->n_samples - 1) {
1003     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1004       goto parse_failed;
1005
1006     if (media_offset < result->offset)
1007       break;
1008
1009     index++;
1010     result++;
1011   }
1012   return index;
1013
1014   /* ERRORS */
1015 parse_failed:
1016   {
1017     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1018     return -1;
1019   }
1020 }
1021
1022 /* find the index of the sample that includes the data for @media_time using a
1023  * linear search, and keeping in mind that not all samples may have been parsed
1024  * yet.  If possible, it will delegate to binary search.
1025  *
1026  * Returns the index of the sample.
1027  */
1028 static guint32
1029 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1030     GstClockTime media_time)
1031 {
1032   guint32 index = 0;
1033   guint64 mov_time;
1034   QtDemuxSample *sample;
1035
1036   /* convert media_time to mov format */
1037   mov_time =
1038       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1039
1040   sample = str->samples;
1041   if (mov_time == sample->timestamp + sample->pts_offset)
1042     return index;
1043
1044   /* use faster search if requested time in already parsed range */
1045   sample = str->samples + str->stbl_index;
1046   if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1047     index = gst_qtdemux_find_index (qtdemux, str, media_time);
1048     sample = str->samples + index;
1049   } else {
1050     while (index < str->n_samples - 1) {
1051       if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1052         goto parse_failed;
1053
1054       sample = str->samples + index + 1;
1055       if (mov_time < sample->timestamp) {
1056         sample = str->samples + index;
1057         break;
1058       }
1059
1060       index++;
1061     }
1062   }
1063
1064   /* sample->timestamp is now <= media_time, need to find the corresponding
1065    * PTS now by looking backwards */
1066   while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1067     index--;
1068     sample = str->samples + index;
1069   }
1070
1071   return index;
1072
1073   /* ERRORS */
1074 parse_failed:
1075   {
1076     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1077     return -1;
1078   }
1079 }
1080
1081 /* find the index of the keyframe needed to decode the sample at @index
1082  * of stream @str, or of a subsequent keyframe (depending on @next)
1083  *
1084  * Returns the index of the keyframe.
1085  */
1086 static guint32
1087 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1088     guint32 index, gboolean next)
1089 {
1090   guint32 new_index = index;
1091
1092   if (index >= str->n_samples) {
1093     new_index = str->n_samples;
1094     goto beach;
1095   }
1096
1097   /* all keyframes, return index */
1098   if (str->all_keyframe) {
1099     new_index = index;
1100     goto beach;
1101   }
1102
1103   /* else search until we have a keyframe */
1104   while (new_index < str->n_samples) {
1105     if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1106       goto parse_failed;
1107
1108     if (str->samples[new_index].keyframe)
1109       break;
1110
1111     if (new_index == 0)
1112       break;
1113
1114     if (next)
1115       new_index++;
1116     else
1117       new_index--;
1118   }
1119
1120   if (new_index == str->n_samples) {
1121     GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1122     new_index = -1;
1123   }
1124
1125 beach:
1126   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1127       "gave %u", next ? "after" : "before", index, new_index);
1128
1129   return new_index;
1130
1131   /* ERRORS */
1132 parse_failed:
1133   {
1134     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1135     return -1;
1136   }
1137 }
1138
1139 /* find the segment for @time_position for @stream
1140  *
1141  * Returns the index of the segment containing @time_position.
1142  * Returns the last segment and sets the @eos variable to TRUE
1143  * if the time is beyond the end. @eos may be NULL
1144  */
1145 static guint32
1146 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1147     GstClockTime time_position)
1148 {
1149   gint i;
1150   guint32 seg_idx;
1151
1152   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1153       GST_TIME_ARGS (time_position));
1154
1155   seg_idx = -1;
1156   for (i = 0; i < stream->n_segments; i++) {
1157     QtDemuxSegment *segment = &stream->segments[i];
1158
1159     GST_LOG_OBJECT (stream->pad,
1160         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1161         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1162
1163     /* For the last segment we include stop_time in the last segment */
1164     if (i < stream->n_segments - 1) {
1165       if (segment->time <= time_position && time_position < segment->stop_time) {
1166         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1167         seg_idx = i;
1168         break;
1169       }
1170     } else {
1171       /* Last segment always matches */
1172       seg_idx = i;
1173       break;
1174     }
1175   }
1176   return seg_idx;
1177 }
1178
1179 /* move the stream @str to the sample position @index.
1180  *
1181  * Updates @str->sample_index and marks discontinuity if needed.
1182  */
1183 static void
1184 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1185     guint32 index)
1186 {
1187   /* no change needed */
1188   if (index == str->sample_index)
1189     return;
1190
1191   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1192       str->n_samples);
1193
1194   /* position changed, we have a discont */
1195   str->sample_index = index;
1196   str->offset_in_sample = 0;
1197   /* Each time we move in the stream we store the position where we are
1198    * starting from */
1199   str->from_sample = index;
1200   str->discont = TRUE;
1201 }
1202
1203 static void
1204 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1205     gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1206 {
1207   guint64 min_offset;
1208   gint64 min_byte_offset = -1;
1209   guint i;
1210
1211   min_offset = next ? G_MAXUINT64 : desired_time;
1212
1213   /* for each stream, find the index of the sample in the segment
1214    * and move back to the previous keyframe. */
1215   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1216     QtDemuxStream *str;
1217     guint32 index, kindex;
1218     guint32 seg_idx;
1219     GstClockTime media_start;
1220     GstClockTime media_time;
1221     GstClockTime seg_time;
1222     QtDemuxSegment *seg;
1223     gboolean empty_segment = FALSE;
1224
1225     str = QTDEMUX_NTH_STREAM (qtdemux, i);
1226
1227     if (CUR_STREAM (str)->sparse && !use_sparse)
1228       continue;
1229
1230     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1231     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1232
1233     /* get segment and time in the segment */
1234     seg = &str->segments[seg_idx];
1235     seg_time = (desired_time - seg->time) * seg->rate;
1236
1237     while (QTSEGMENT_IS_EMPTY (seg)) {
1238       seg_time = 0;
1239       empty_segment = TRUE;
1240       GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1241           seg_idx);
1242       seg_idx++;
1243       if (seg_idx == str->n_segments)
1244         break;
1245       seg = &str->segments[seg_idx];
1246     }
1247
1248     if (seg_idx == str->n_segments) {
1249       /* FIXME track shouldn't have the last segment as empty, but if it
1250        * happens we better handle it */
1251       continue;
1252     }
1253
1254     /* get the media time in the segment */
1255     media_start = seg->media_start + seg_time;
1256
1257     /* get the index of the sample with media time */
1258     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1259     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1260         " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1261         GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1262         empty_segment);
1263
1264     /* shift to next frame if we are looking for next keyframe */
1265     if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1266         && index < str->stbl_index)
1267       index++;
1268
1269     if (!empty_segment) {
1270       /* find previous or next keyframe */
1271       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1272
1273       /* if looking for next one, we will settle for one before if none found after */
1274       if (next && kindex == -1)
1275         kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1276
1277       /* Update the requested time whenever a keyframe was found, to make it
1278        * accurate and avoid having the first buffer fall outside of the segment
1279        */
1280       if (kindex != -1) {
1281         index = kindex;
1282
1283         /* get timestamp of keyframe */
1284         media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1285         GST_DEBUG_OBJECT (qtdemux,
1286             "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1287             G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1288             str->samples[kindex].offset);
1289
1290         /* keyframes in the segment get a chance to change the
1291          * desired_offset. keyframes out of the segment are
1292          * ignored. */
1293         if (media_time >= seg->media_start) {
1294           GstClockTime seg_time;
1295
1296           /* this keyframe is inside the segment, convert back to
1297            * segment time */
1298           seg_time = (media_time - seg->media_start) + seg->time;
1299
1300           /* Adjust the offset based on the earliest suitable keyframe found,
1301            * based on which GST_SEEK_FLAG_SNAP_* is present (indicated by 'next').
1302            * For SNAP_BEFORE we look for the earliest keyframe before desired_time,
1303            * and in case of SNAP_AFTER - for the closest one after it. */
1304           if (seg_time < min_offset)
1305             min_offset = seg_time;
1306         }
1307       }
1308     }
1309
1310     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1311       min_byte_offset = str->samples[index].offset;
1312   }
1313
1314   if (key_time)
1315     *key_time = min_offset;
1316   if (key_offset)
1317     *key_offset = min_byte_offset;
1318 }
1319
1320 static gboolean
1321 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1322     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1323 {
1324   gboolean res;
1325
1326   g_return_val_if_fail (format != NULL, FALSE);
1327   g_return_val_if_fail (cur != NULL, FALSE);
1328   g_return_val_if_fail (stop != NULL, FALSE);
1329
1330   if (*format == GST_FORMAT_TIME)
1331     return TRUE;
1332
1333   res = TRUE;
1334   if (cur_type != GST_SEEK_TYPE_NONE)
1335     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1336   if (res && stop_type != GST_SEEK_TYPE_NONE)
1337     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1338
1339   if (res)
1340     *format = GST_FORMAT_TIME;
1341
1342   return res;
1343 }
1344
1345 /* perform seek in push based mode:
1346    find BYTE position to move to based on time and delegate to upstream
1347 */
1348 static gboolean
1349 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1350 {
1351   gdouble rate;
1352   GstFormat format;
1353   GstSeekFlags flags;
1354   GstSeekType cur_type, stop_type;
1355   gint64 cur, stop, key_cur;
1356   gboolean res;
1357   gint64 byte_cur;
1358   gint64 original_stop;
1359   guint32 seqnum;
1360
1361   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1362
1363   gst_event_parse_seek (event, &rate, &format, &flags,
1364       &cur_type, &cur, &stop_type, &stop);
1365   seqnum = gst_event_get_seqnum (event);
1366
1367   /* Directly send the instant-rate-change event here before taking the
1368    * stream-lock so that it can be applied as soon as possible */
1369   if (flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE) {
1370     GstEvent *ev;
1371
1372     /* instant rate change only supported if direction does not change. All
1373      * other requirements are already checked before creating the seek event
1374      * but let's double-check here to be sure */
1375     if ((qtdemux->segment.rate > 0 && rate < 0) ||
1376         (qtdemux->segment.rate < 0 && rate > 0) ||
1377         cur_type != GST_SEEK_TYPE_NONE ||
1378         stop_type != GST_SEEK_TYPE_NONE || (flags & GST_SEEK_FLAG_FLUSH)) {
1379       GST_ERROR_OBJECT (qtdemux,
1380           "Instant rate change seeks only supported in the "
1381           "same direction, without flushing and position change");
1382       return FALSE;
1383     }
1384
1385     ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1386         (GstSegmentFlags) flags);
1387     gst_event_set_seqnum (ev, seqnum);
1388     gst_qtdemux_push_event (qtdemux, ev);
1389     return TRUE;
1390   }
1391
1392   /* only forward streaming and seeking is possible */
1393   if (rate <= 0)
1394     goto unsupported_seek;
1395
1396   /* convert to TIME if needed and possible */
1397   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1398           stop_type, &stop))
1399     goto no_format;
1400
1401   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1402    * the original stop position to use when upstream pushes the new segment
1403    * for this seek */
1404   original_stop = stop;
1405   stop = -1;
1406
1407   /* find reasonable corresponding BYTE position,
1408    * also try to mind about keyframes, since we can not go back a bit for them
1409    * later on */
1410   /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1411    * mostly just work, but let's not yet boldly go there  ... */
1412   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1413
1414   if (byte_cur == -1)
1415     goto abort_seek;
1416
1417   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1418       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1419       stop);
1420
1421   GST_OBJECT_LOCK (qtdemux);
1422   qtdemux->seek_offset = byte_cur;
1423   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1424     qtdemux->push_seek_start = cur;
1425   } else {
1426     qtdemux->push_seek_start = key_cur;
1427   }
1428
1429   if (stop_type == GST_SEEK_TYPE_NONE) {
1430     qtdemux->push_seek_stop = qtdemux->segment.stop;
1431   } else {
1432     qtdemux->push_seek_stop = original_stop;
1433   }
1434   GST_OBJECT_UNLOCK (qtdemux);
1435
1436   qtdemux->segment_seqnum = seqnum;
1437   /* BYTE seek event */
1438   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1439       stop_type, stop);
1440   gst_event_set_seqnum (event, seqnum);
1441   res = gst_pad_push_event (qtdemux->sinkpad, event);
1442
1443   return res;
1444
1445   /* ERRORS */
1446 abort_seek:
1447   {
1448     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1449         "seek aborted.");
1450     return FALSE;
1451   }
1452 unsupported_seek:
1453   {
1454     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1455     return FALSE;
1456   }
1457 no_format:
1458   {
1459     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1460     return FALSE;
1461   }
1462 }
1463
1464 /* perform the seek.
1465  *
1466  * We set all segment_indexes in the streams to unknown and
1467  * adjust the time_position to the desired position. this is enough
1468  * to trigger a segment switch in the streaming thread to start
1469  * streaming from the desired position.
1470  *
1471  * Keyframe seeking is a little more complicated when dealing with
1472  * segments. Ideally we want to move to the previous keyframe in
1473  * the segment but there might not be a keyframe in the segment. In
1474  * fact, none of the segments could contain a keyframe. We take a
1475  * practical approach: seek to the previous keyframe in the segment,
1476  * if there is none, seek to the beginning of the segment.
1477  *
1478  * Called with STREAM_LOCK
1479  */
1480 static gboolean
1481 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1482     guint32 seqnum, GstSeekFlags flags)
1483 {
1484   gint64 desired_offset;
1485   guint i;
1486
1487   desired_offset = segment->position;
1488
1489   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1490       GST_TIME_ARGS (desired_offset));
1491
1492   /* may not have enough fragmented info to do this adjustment,
1493    * and we can't scan (and probably should not) at this time with
1494    * possibly flushing upstream */
1495   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1496     gint64 min_offset;
1497     gboolean next, before, after;
1498
1499     before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1500     after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1501     next = after && !before;
1502     if (segment->rate < 0)
1503       next = !next;
1504
1505     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1506         NULL);
1507     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1508         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1509     desired_offset = min_offset;
1510   }
1511
1512   /* and set all streams to the final position */
1513   GST_OBJECT_LOCK (qtdemux);
1514   gst_flow_combiner_reset (qtdemux->flowcombiner);
1515   GST_OBJECT_UNLOCK (qtdemux);
1516   qtdemux->segment_seqnum = seqnum;
1517   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1518     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1519
1520     stream->time_position = desired_offset;
1521     stream->accumulated_base = 0;
1522     stream->sample_index = -1;
1523     stream->offset_in_sample = 0;
1524     stream->segment_index = -1;
1525     stream->sent_eos = FALSE;
1526     stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
1527
1528     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1529       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1530   }
1531   segment->position = desired_offset;
1532   if (segment->rate >= 0) {
1533     segment->start = desired_offset;
1534     /* We need to update time as we update start in that direction */
1535     segment->time = desired_offset;
1536
1537     /* we stop at the end */
1538     if (segment->stop == -1)
1539       segment->stop = segment->duration;
1540   } else {
1541     segment->stop = desired_offset;
1542   }
1543
1544   if (qtdemux->fragmented)
1545     qtdemux->fragmented_seek_pending = TRUE;
1546
1547   return TRUE;
1548 }
1549
1550 /* do a seek in pull based mode */
1551 static gboolean
1552 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1553 {
1554   gdouble rate = 1.0;
1555   GstFormat format;
1556   GstSeekFlags flags;
1557   GstSeekType cur_type, stop_type;
1558   gint64 cur, stop;
1559   gboolean flush, instant_rate_change;
1560   gboolean update;
1561   GstSegment seeksegment;
1562   guint32 seqnum = GST_SEQNUM_INVALID;
1563   GstEvent *flush_event;
1564   gboolean ret;
1565
1566   GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1567
1568   gst_event_parse_seek (event, &rate, &format, &flags,
1569       &cur_type, &cur, &stop_type, &stop);
1570   seqnum = gst_event_get_seqnum (event);
1571
1572   /* we have to have a format as the segment format. Try to convert
1573    * if not. */
1574   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1575           stop_type, &stop))
1576     goto no_format;
1577
1578   GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1579
1580   flush = ! !(flags & GST_SEEK_FLAG_FLUSH);
1581   instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1582
1583   /* Directly send the instant-rate-change event here before taking the
1584    * stream-lock so that it can be applied as soon as possible */
1585   if (instant_rate_change) {
1586     GstEvent *ev;
1587
1588     /* instant rate change only supported if direction does not change. All
1589      * other requirements are already checked before creating the seek event
1590      * but let's double-check here to be sure */
1591     if ((qtdemux->segment.rate > 0 && rate < 0) ||
1592         (qtdemux->segment.rate < 0 && rate > 0) ||
1593         cur_type != GST_SEEK_TYPE_NONE ||
1594         stop_type != GST_SEEK_TYPE_NONE || flush) {
1595       GST_ERROR_OBJECT (qtdemux,
1596           "Instant rate change seeks only supported in the "
1597           "same direction, without flushing and position change");
1598       return FALSE;
1599     }
1600
1601     ev = gst_event_new_instant_rate_change (rate / qtdemux->segment.rate,
1602         (GstSegmentFlags) flags);
1603     gst_event_set_seqnum (ev, seqnum);
1604     gst_qtdemux_push_event (qtdemux, ev);
1605     return TRUE;
1606   }
1607
1608   /* stop streaming, either by flushing or by pausing the task */
1609   if (flush) {
1610     flush_event = gst_event_new_flush_start ();
1611     if (seqnum != GST_SEQNUM_INVALID)
1612       gst_event_set_seqnum (flush_event, seqnum);
1613     /* unlock upstream pull_range */
1614     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1615     /* make sure out loop function exits */
1616     gst_qtdemux_push_event (qtdemux, flush_event);
1617   } else {
1618     /* non flushing seek, pause the task */
1619     gst_pad_pause_task (qtdemux->sinkpad);
1620   }
1621
1622   /* wait for streaming to finish */
1623   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1624
1625   /* copy segment, we need this because we still need the old
1626    * segment when we close the current segment. */
1627   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1628
1629   /* configure the segment with the seek variables */
1630   GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1631   if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1632           cur_type, cur, stop_type, stop, &update)) {
1633     ret = FALSE;
1634     GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1635   } else {
1636     /* now do the seek */
1637     ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1638   }
1639
1640   /* prepare for streaming again */
1641   if (flush) {
1642     flush_event = gst_event_new_flush_stop (TRUE);
1643     if (seqnum != GST_SEQNUM_INVALID)
1644       gst_event_set_seqnum (flush_event, seqnum);
1645
1646     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1647     gst_qtdemux_push_event (qtdemux, flush_event);
1648   }
1649
1650   /* commit the new segment */
1651   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1652
1653   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1654     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1655         qtdemux->segment.format, qtdemux->segment.position);
1656     if (seqnum != GST_SEQNUM_INVALID)
1657       gst_message_set_seqnum (msg, seqnum);
1658     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1659   }
1660
1661   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1662   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1663       qtdemux->sinkpad, NULL);
1664
1665   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1666
1667   return ret;
1668
1669   /* ERRORS */
1670 no_format:
1671   {
1672     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1673     return FALSE;
1674   }
1675 }
1676
1677 static gboolean
1678 qtdemux_ensure_index (GstQTDemux * qtdemux)
1679 {
1680   guint i;
1681
1682   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1683
1684   /* Build complete index */
1685   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1686     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1687
1688     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1689       GST_LOG_OBJECT (qtdemux,
1690           "Building complete index of track-id %u for seeking failed!",
1691           stream->track_id);
1692       return FALSE;
1693     }
1694   }
1695
1696   return TRUE;
1697 }
1698
1699 static gboolean
1700 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1701     GstEvent * event)
1702 {
1703   gboolean res = TRUE;
1704   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1705
1706   switch (GST_EVENT_TYPE (event)) {
1707     case GST_EVENT_RECONFIGURE:
1708       GST_OBJECT_LOCK (qtdemux);
1709       gst_flow_combiner_reset (qtdemux->flowcombiner);
1710       GST_OBJECT_UNLOCK (qtdemux);
1711       res = gst_pad_event_default (pad, parent, event);
1712       break;
1713     case GST_EVENT_SEEK:
1714     {
1715       GstSeekFlags flags = 0;
1716       GstFormat seek_format;
1717       gboolean instant_rate_change;
1718
1719 #ifndef GST_DISABLE_GST_DEBUG
1720       GstClockTime ts = gst_util_get_timestamp ();
1721 #endif
1722       guint32 seqnum = gst_event_get_seqnum (event);
1723
1724       qtdemux->received_seek = TRUE;
1725
1726       gst_event_parse_seek (event, NULL, &seek_format, &flags, NULL, NULL, NULL,
1727           NULL);
1728       instant_rate_change = ! !(flags & GST_SEEK_FLAG_INSTANT_RATE_CHANGE);
1729
1730       if (seqnum == qtdemux->segment_seqnum) {
1731         GST_LOG_OBJECT (pad,
1732             "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1733         gst_event_unref (event);
1734         return TRUE;
1735       }
1736
1737       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1738         /* seek should be handled by upstream, we might need to re-download fragments */
1739         GST_DEBUG_OBJECT (qtdemux,
1740             "let upstream handle seek for fragmented playback");
1741         goto upstream;
1742       }
1743
1744       if (seek_format == GST_FORMAT_BYTES) {
1745         GST_DEBUG_OBJECT (pad, "Rejecting seek request in bytes format");
1746         gst_event_unref (event);
1747         return FALSE;
1748       }
1749
1750       gst_event_parse_seek_trickmode_interval (event,
1751           &qtdemux->trickmode_interval);
1752
1753       /* Build complete index for seeking;
1754        * if not a fragmented file at least and we're really doing a seek,
1755        * not just an instant-rate-change */
1756       if (!qtdemux->fragmented && !instant_rate_change) {
1757         if (!qtdemux_ensure_index (qtdemux))
1758           goto index_failed;
1759       }
1760 #ifndef GST_DISABLE_GST_DEBUG
1761       ts = gst_util_get_timestamp () - ts;
1762       GST_INFO_OBJECT (qtdemux,
1763           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1764 #endif
1765       if (qtdemux->pullbased) {
1766         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1767       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1768         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1769         res = TRUE;
1770       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1771           && QTDEMUX_N_STREAMS (qtdemux)
1772           && !qtdemux->fragmented) {
1773         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1774       } else {
1775         GST_DEBUG_OBJECT (qtdemux,
1776             "ignoring seek in push mode in current state");
1777         res = FALSE;
1778       }
1779       gst_event_unref (event);
1780     }
1781       break;
1782     default:
1783     upstream:
1784       res = gst_pad_event_default (pad, parent, event);
1785       break;
1786   }
1787
1788 done:
1789   return res;
1790
1791   /* ERRORS */
1792 index_failed:
1793   {
1794     GST_ERROR_OBJECT (qtdemux, "Index failed");
1795     gst_event_unref (event);
1796     res = FALSE;
1797     goto done;
1798   }
1799 }
1800
1801 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1802  *
1803  * If @fw is false, the coding order is explored backwards.
1804  *
1805  * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1806  * sample is found for that track.
1807  *
1808  * The stream and sample index of the sample with the minimum offset in the direction explored
1809  * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1810  *
1811  * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1812  * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1813  * @_stream and @_index. */
1814 static void
1815 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1816     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1817 {
1818   gint i, index;
1819   gint64 time, min_time;
1820   QtDemuxStream *stream;
1821   gint iter;
1822
1823   min_time = -1;
1824   stream = NULL;
1825   index = -1;
1826
1827   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1828     QtDemuxStream *str;
1829     gint inc;
1830     gboolean set_sample;
1831
1832     str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1833     set_sample = !set;
1834
1835     if (fw) {
1836       i = 0;
1837       inc = 1;
1838     } else {
1839       i = str->n_samples - 1;
1840       inc = -1;
1841     }
1842
1843     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1844       if (str->samples[i].size == 0)
1845         continue;
1846
1847       if (fw && (str->samples[i].offset < byte_pos))
1848         continue;
1849
1850       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1851         continue;
1852
1853       /* move stream to first available sample */
1854       if (set) {
1855         gst_qtdemux_move_stream (qtdemux, str, i);
1856         set_sample = TRUE;
1857       }
1858
1859       /* avoid index from sparse streams since they might be far away */
1860       if (!CUR_STREAM (str)->sparse) {
1861         /* determine min/max time */
1862         time = QTSAMPLE_PTS (str, &str->samples[i]);
1863         if (min_time == -1 || (!fw && time > min_time) ||
1864             (fw && time < min_time)) {
1865           min_time = time;
1866         }
1867
1868         /* determine stream with leading sample, to get its position */
1869         if (!stream ||
1870             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1871             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1872           stream = str;
1873           index = i;
1874         }
1875       }
1876       break;
1877     }
1878
1879     /* no sample for this stream, mark eos */
1880     if (!set_sample)
1881       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1882   }
1883
1884   if (_time)
1885     *_time = min_time;
1886   if (_stream)
1887     *_stream = stream;
1888   if (_index)
1889     *_index = index;
1890 }
1891
1892 /* Copied from mpegtsbase code */
1893 /* FIXME: replace this function when we add new util function for stream-id creation */
1894 static gchar *
1895 _get_upstream_id (GstQTDemux * demux)
1896 {
1897   gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
1898
1899   if (!upstream_id) {
1900     /* Try to create one from the upstream URI, else use a randome number */
1901     GstQuery *query;
1902     gchar *uri = NULL;
1903
1904     /* Try to generate one from the URI query and
1905      * if it fails take a random number instead */
1906     query = gst_query_new_uri ();
1907     if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
1908       gst_query_parse_uri (query, &uri);
1909     }
1910
1911     if (uri) {
1912       GChecksum *cs;
1913
1914       /* And then generate an SHA256 sum of the URI */
1915       cs = g_checksum_new (G_CHECKSUM_SHA256);
1916       g_checksum_update (cs, (const guchar *) uri, strlen (uri));
1917       g_free (uri);
1918       upstream_id = g_strdup (g_checksum_get_string (cs));
1919       g_checksum_free (cs);
1920     } else {
1921       /* Just get some random number if the URI query fails */
1922       GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
1923           "implementing a deterministic way of creating a stream-id");
1924       upstream_id =
1925           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
1926           g_random_int (), g_random_int ());
1927     }
1928
1929     gst_query_unref (query);
1930   }
1931   return upstream_id;
1932 }
1933
1934 static QtDemuxStream *
1935 _create_stream (GstQTDemux * demux, guint32 track_id)
1936 {
1937   QtDemuxStream *stream;
1938   gchar *upstream_id;
1939
1940   stream = g_new0 (QtDemuxStream, 1);
1941   stream->demux = demux;
1942   stream->track_id = track_id;
1943   upstream_id = _get_upstream_id (demux);
1944   stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
1945   g_free (upstream_id);
1946   /* new streams always need a discont */
1947   stream->discont = TRUE;
1948   /* we enable clipping for raw audio/video streams */
1949   stream->need_clip = FALSE;
1950   stream->process_func = NULL;
1951   stream->segment_index = -1;
1952   stream->time_position = 0;
1953   stream->sample_index = -1;
1954   stream->offset_in_sample = 0;
1955   stream->new_stream = TRUE;
1956   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1957   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1958   stream->protected = FALSE;
1959   stream->protection_scheme_type = 0;
1960   stream->protection_scheme_version = 0;
1961   stream->protection_scheme_info = NULL;
1962   stream->n_samples_moof = 0;
1963   stream->duration_moof = 0;
1964   stream->duration_last_moof = 0;
1965   stream->alignment = 1;
1966   stream->stream_tags = gst_tag_list_new_empty ();
1967   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
1968   g_queue_init (&stream->protection_scheme_event_queue);
1969   stream->ref_count = 1;
1970   /* consistent default for push based mode */
1971   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1972   return stream;
1973 }
1974
1975 static gboolean
1976 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1977 {
1978   GstStructure *structure;
1979   const gchar *variant;
1980   const GstCaps *mediacaps = NULL;
1981
1982   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1983
1984   structure = gst_caps_get_structure (caps, 0);
1985   variant = gst_structure_get_string (structure, "variant");
1986
1987   if (variant && strcmp (variant, "mse-bytestream") == 0) {
1988     demux->variant = VARIANT_MSE_BYTESTREAM;
1989   }
1990
1991   if (variant && strcmp (variant, "mss-fragmented") == 0) {
1992     QtDemuxStream *stream;
1993     const GValue *value;
1994
1995     demux->fragmented = TRUE;
1996     demux->variant = VARIANT_MSS_FRAGMENTED;
1997
1998     if (QTDEMUX_N_STREAMS (demux) > 1) {
1999       /* can't do this, we can only renegotiate for another mss format */
2000       return FALSE;
2001     }
2002
2003     value = gst_structure_get_value (structure, "media-caps");
2004     /* create stream */
2005     if (value) {
2006       const GValue *timescale_v;
2007
2008       /* TODO update when stream changes during playback */
2009
2010       if (QTDEMUX_N_STREAMS (demux) == 0) {
2011         stream = _create_stream (demux, 1);
2012         g_ptr_array_add (demux->active_streams, stream);
2013         /* mss has no stsd/stsd entry, use id 0 as default */
2014         stream->stsd_entries_length = 1;
2015         stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2016         stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2017       } else {
2018         stream = QTDEMUX_NTH_STREAM (demux, 0);
2019       }
2020
2021       timescale_v = gst_structure_get_value (structure, "timescale");
2022       if (timescale_v) {
2023         stream->timescale = g_value_get_uint64 (timescale_v);
2024       } else {
2025         /* default mss timescale */
2026         stream->timescale = 10000000;
2027       }
2028       demux->timescale = stream->timescale;
2029
2030       mediacaps = gst_value_get_caps (value);
2031       if (!CUR_STREAM (stream)->caps
2032           || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2033         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2034             mediacaps);
2035         stream->new_caps = TRUE;
2036       }
2037       gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2038       structure = gst_caps_get_structure (mediacaps, 0);
2039       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2040         stream->subtype = FOURCC_vide;
2041
2042         gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2043         gst_structure_get_int (structure, "height",
2044             &CUR_STREAM (stream)->height);
2045         gst_structure_get_fraction (structure, "framerate",
2046             &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2047       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2048         gint rate = 0;
2049         stream->subtype = FOURCC_soun;
2050         gst_structure_get_int (structure, "channels",
2051             &CUR_STREAM (stream)->n_channels);
2052         gst_structure_get_int (structure, "rate", &rate);
2053         CUR_STREAM (stream)->rate = rate;
2054       } else if (gst_structure_has_name (structure, "application/x-cenc")) {
2055         if (gst_structure_has_field (structure, "original-media-type")) {
2056           const gchar *media_type =
2057               gst_structure_get_string (structure, "original-media-type");
2058           if (g_str_has_prefix (media_type, "video")) {
2059             stream->subtype = FOURCC_vide;
2060           } else if (g_str_has_prefix (media_type, "audio")) {
2061             stream->subtype = FOURCC_soun;
2062           }
2063         }
2064       }
2065     }
2066     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2067   }
2068
2069   return TRUE;
2070 }
2071
2072 static void
2073 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2074 {
2075   gint i;
2076
2077   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2078
2079   if (hard || qtdemux->upstream_format_is_time) {
2080     qtdemux->state = QTDEMUX_STATE_INITIAL;
2081     qtdemux->neededbytes = 16;
2082     qtdemux->todrop = 0;
2083     qtdemux->pullbased = FALSE;
2084     g_clear_pointer (&qtdemux->redirect_location, g_free);
2085     qtdemux->first_mdat = -1;
2086     qtdemux->header_size = 0;
2087     qtdemux->mdatoffset = -1;
2088     qtdemux->restoredata_offset = -1;
2089     if (qtdemux->mdatbuffer)
2090       gst_buffer_unref (qtdemux->mdatbuffer);
2091     if (qtdemux->restoredata_buffer)
2092       gst_buffer_unref (qtdemux->restoredata_buffer);
2093     qtdemux->mdatbuffer = NULL;
2094     qtdemux->restoredata_buffer = NULL;
2095     qtdemux->mdatleft = 0;
2096     qtdemux->mdatsize = 0;
2097     if (qtdemux->comp_brands)
2098       gst_buffer_unref (qtdemux->comp_brands);
2099     qtdemux->comp_brands = NULL;
2100     qtdemux->last_moov_offset = -1;
2101     if (qtdemux->moov_node_compressed) {
2102       g_node_destroy (qtdemux->moov_node_compressed);
2103       if (qtdemux->moov_node)
2104         g_free (qtdemux->moov_node->data);
2105     }
2106     qtdemux->moov_node_compressed = NULL;
2107     if (qtdemux->moov_node)
2108       g_node_destroy (qtdemux->moov_node);
2109     qtdemux->moov_node = NULL;
2110     if (qtdemux->tag_list)
2111       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2112     qtdemux->tag_list = gst_tag_list_new_empty ();
2113     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2114 #if 0
2115     if (qtdemux->element_index)
2116       gst_object_unref (qtdemux->element_index);
2117     qtdemux->element_index = NULL;
2118 #endif
2119     qtdemux->major_brand = 0;
2120     qtdemux->upstream_format_is_time = FALSE;
2121     qtdemux->upstream_seekable = FALSE;
2122     qtdemux->upstream_size = 0;
2123
2124     qtdemux->fragment_start = -1;
2125     qtdemux->fragment_start_offset = -1;
2126     qtdemux->duration = 0;
2127     qtdemux->moof_offset = 0;
2128     qtdemux->chapters_track_id = 0;
2129     qtdemux->have_group_id = FALSE;
2130     qtdemux->group_id = G_MAXUINT;
2131
2132     g_queue_clear_full (&qtdemux->protection_event_queue,
2133         (GDestroyNotify) gst_event_unref);
2134
2135     qtdemux->received_seek = FALSE;
2136     qtdemux->first_moof_already_parsed = FALSE;
2137   }
2138   qtdemux->offset = 0;
2139   gst_adapter_clear (qtdemux->adapter);
2140   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2141   qtdemux->need_segment = TRUE;
2142
2143   if (hard) {
2144     qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2145     qtdemux->trickmode_interval = 0;
2146     g_ptr_array_set_size (qtdemux->active_streams, 0);
2147     g_ptr_array_set_size (qtdemux->old_streams, 0);
2148     qtdemux->n_video_streams = 0;
2149     qtdemux->n_audio_streams = 0;
2150     qtdemux->n_sub_streams = 0;
2151     qtdemux->n_meta_streams = 0;
2152     qtdemux->exposed = FALSE;
2153     qtdemux->fragmented = FALSE;
2154     qtdemux->variant = VARIANT_NONE;
2155     gst_caps_replace (&qtdemux->media_caps, NULL);
2156     qtdemux->timescale = 0;
2157     qtdemux->got_moov = FALSE;
2158     qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
2159     qtdemux->cenc_aux_info_offset = 0;
2160     g_free (qtdemux->cenc_aux_info_sizes);
2161     qtdemux->cenc_aux_info_sizes = NULL;
2162     qtdemux->cenc_aux_sample_count = 0;
2163     if (qtdemux->protection_system_ids) {
2164       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2165       qtdemux->protection_system_ids = NULL;
2166     }
2167     qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2168         && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2169         GST_BIN_FLAG_STREAMS_AWARE);
2170
2171     if (qtdemux->preferred_protection_system_id) {
2172       g_free (qtdemux->preferred_protection_system_id);
2173       qtdemux->preferred_protection_system_id = NULL;
2174     }
2175   } else if (qtdemux->variant == VARIANT_MSS_FRAGMENTED) {
2176     gst_flow_combiner_reset (qtdemux->flowcombiner);
2177     g_ptr_array_foreach (qtdemux->active_streams,
2178         (GFunc) gst_qtdemux_stream_clear, NULL);
2179   } else {
2180     gst_flow_combiner_reset (qtdemux->flowcombiner);
2181     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2182       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2183       stream->sent_eos = FALSE;
2184       stream->time_position = 0;
2185       stream->accumulated_base = 0;
2186       stream->last_keyframe_dts = GST_CLOCK_TIME_NONE;
2187     }
2188   }
2189 }
2190
2191 static void
2192 qtdemux_clear_protection_events_on_all_streams (GstQTDemux * qtdemux)
2193 {
2194   for (unsigned i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2195     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2196     g_queue_clear_full (&stream->protection_scheme_event_queue,
2197         (GDestroyNotify) gst_event_unref);
2198   }
2199 }
2200
2201 /* Maps the @segment to the qt edts internal segments and pushes
2202  * the corresponding segment event.
2203  *
2204  * If it ends up being at a empty segment, a gap will be pushed and the next
2205  * edts segment will be activated in sequence.
2206  *
2207  * To be used in push-mode only */
2208 static void
2209 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2210 {
2211   gint i, iter;
2212
2213   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2214     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2215
2216     stream->time_position = segment->start;
2217
2218     /* in push mode we should be guaranteed that we will have empty segments
2219      * at the beginning and then one segment after, other scenarios are not
2220      * supported and are discarded when parsing the edts */
2221     for (i = 0; i < stream->n_segments; i++) {
2222       if (stream->segments[i].stop_time > segment->start) {
2223         /* push the empty segment and move to the next one */
2224         gst_qtdemux_activate_segment (qtdemux, stream, i,
2225             stream->time_position);
2226         if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2227           gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2228               stream->time_position);
2229
2230           /* accumulate previous segments */
2231           if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2232             stream->accumulated_base +=
2233                 (stream->segment.stop -
2234                 stream->segment.start) / ABS (stream->segment.rate);
2235           continue;
2236         }
2237
2238         g_assert (i == stream->n_segments - 1);
2239       }
2240     }
2241   }
2242 }
2243
2244 static void
2245 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2246     GPtrArray * src)
2247 {
2248   guint i;
2249   guint len;
2250
2251   len = src->len;
2252
2253   if (len == 0)
2254     return;
2255
2256   for (i = 0; i < len; i++) {
2257     QtDemuxStream *stream = g_ptr_array_index (src, i);
2258
2259 #ifndef GST_DISABLE_GST_DEBUG
2260     GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2261         stream, GST_STR_NULL (stream->stream_id), dest);
2262 #endif
2263     g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2264   }
2265
2266   g_ptr_array_set_size (src, 0);
2267 }
2268
2269 static gboolean
2270 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2271     GstEvent * event)
2272 {
2273   GstQTDemux *demux = GST_QTDEMUX (parent);
2274   gboolean res = TRUE;
2275
2276   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2277
2278   switch (GST_EVENT_TYPE (event)) {
2279     case GST_EVENT_SEGMENT:
2280     {
2281       gint64 offset = 0;
2282       QtDemuxStream *stream;
2283       gint idx;
2284       GstSegment segment;
2285
2286       /* some debug output */
2287       gst_event_copy_segment (event, &segment);
2288       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2289           &segment);
2290
2291       if (segment.format == GST_FORMAT_TIME) {
2292         demux->upstream_format_is_time = TRUE;
2293         demux->segment_seqnum = gst_event_get_seqnum (event);
2294       } else {
2295         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2296             "not in time format");
2297
2298         /* chain will send initial newsegment after pads have been added */
2299         if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2300           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2301           goto exit;
2302         }
2303       }
2304
2305       /* check if this matches a time seek we received previously
2306        * FIXME for backwards compatibility reasons we use the
2307        * seek_offset here to compare. In the future we might want to
2308        * change this to use the seqnum as it uniquely should identify
2309        * the segment that corresponds to the seek. */
2310       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2311           ", received segment offset %" G_GINT64_FORMAT,
2312           demux->seek_offset, segment.start);
2313       if (segment.format == GST_FORMAT_BYTES
2314           && demux->seek_offset == segment.start) {
2315         GST_OBJECT_LOCK (demux);
2316         offset = segment.start;
2317
2318         segment.format = GST_FORMAT_TIME;
2319         segment.start = demux->push_seek_start;
2320         segment.stop = demux->push_seek_stop;
2321         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2322             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2323             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2324         GST_OBJECT_UNLOCK (demux);
2325       }
2326
2327       /* we only expect a BYTE segment, e.g. following a seek */
2328       if (segment.format == GST_FORMAT_BYTES) {
2329         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2330           offset = segment.start;
2331
2332           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2333               NULL, (gint64 *) & segment.start);
2334           if ((gint64) segment.start < 0)
2335             segment.start = 0;
2336         }
2337         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2338           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2339               NULL, (gint64 *) & segment.stop);
2340           /* keyframe seeking should already arrange for start >= stop,
2341            * but make sure in other rare cases */
2342           segment.stop = MAX (segment.stop, segment.start);
2343         }
2344       } else if (segment.format == GST_FORMAT_TIME) {
2345         /* push all data on the adapter before starting this
2346          * new segment */
2347         gst_qtdemux_process_adapter (demux, TRUE);
2348       } else {
2349         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2350         goto exit;
2351       }
2352
2353       /* We shouldn't modify upstream driven TIME FORMAT segment */
2354       if (!demux->upstream_format_is_time) {
2355         /* accept upstream's notion of segment and distribute along */
2356         segment.format = GST_FORMAT_TIME;
2357         segment.position = segment.time = segment.start;
2358         segment.duration = demux->segment.duration;
2359         segment.base = gst_segment_to_running_time (&demux->segment,
2360             GST_FORMAT_TIME, demux->segment.position);
2361       }
2362
2363       gst_segment_copy_into (&segment, &demux->segment);
2364       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2365
2366       /* map segment to internal qt segments and push on each stream */
2367       if (QTDEMUX_N_STREAMS (demux)) {
2368         demux->need_segment = TRUE;
2369         gst_qtdemux_check_send_pending_segment (demux);
2370       }
2371
2372       /* clear leftover in current segment, if any */
2373       gst_adapter_clear (demux->adapter);
2374
2375       /* set up streaming thread */
2376       demux->offset = offset;
2377       if (demux->upstream_format_is_time) {
2378         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2379             "set values to restart reading from a new atom");
2380         demux->neededbytes = 16;
2381         demux->todrop = 0;
2382       } else {
2383         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2384             NULL);
2385         if (stream) {
2386           demux->todrop = stream->samples[idx].offset - offset;
2387           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2388         } else {
2389           /* set up for EOS */
2390           demux->neededbytes = -1;
2391           demux->todrop = 0;
2392         }
2393       }
2394     exit:
2395       gst_event_unref (event);
2396       res = TRUE;
2397       goto drop;
2398     }
2399     case GST_EVENT_FLUSH_START:
2400     {
2401       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2402         gst_event_unref (event);
2403         goto drop;
2404       }
2405       QTDEMUX_EXPOSE_LOCK (demux);
2406       res = gst_pad_event_default (demux->sinkpad, parent, event);
2407       QTDEMUX_EXPOSE_UNLOCK (demux);
2408       goto drop;
2409     }
2410     case GST_EVENT_FLUSH_STOP:
2411     {
2412       guint64 dur;
2413
2414       dur = demux->segment.duration;
2415       gst_qtdemux_reset (demux, FALSE);
2416       demux->segment.duration = dur;
2417
2418       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2419         gst_event_unref (event);
2420         goto drop;
2421       }
2422       break;
2423     }
2424     case GST_EVENT_EOS:
2425       /* If we are in push mode, and get an EOS before we've seen any streams,
2426        * then error out - we have nowhere to send the EOS */
2427       if (!demux->pullbased) {
2428         gint i;
2429         gboolean has_valid_stream = FALSE;
2430         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2431           if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2432             has_valid_stream = TRUE;
2433             break;
2434           }
2435         }
2436         if (!has_valid_stream)
2437           gst_qtdemux_post_no_playable_stream_error (demux);
2438         else {
2439           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2440               (guint) gst_adapter_available (demux->adapter));
2441           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2442             res = FALSE;
2443           }
2444         }
2445       }
2446       break;
2447     case GST_EVENT_CAPS:{
2448       GstCaps *caps = NULL;
2449
2450       gst_event_parse_caps (event, &caps);
2451       gst_qtdemux_setcaps (demux, caps);
2452       res = TRUE;
2453       gst_event_unref (event);
2454       goto drop;
2455     }
2456     case GST_EVENT_PROTECTION:
2457     {
2458       const gchar *system_id = NULL;
2459
2460       gst_event_parse_protection (event, &system_id, NULL, NULL);
2461       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2462           system_id);
2463       gst_qtdemux_append_protection_system_id (demux, system_id);
2464       /* save the event for later, for source pads that have not been created */
2465       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2466       /* send it to all pads that already exist */
2467       gst_qtdemux_push_event (demux, event);
2468       res = TRUE;
2469       goto drop;
2470     }
2471     case GST_EVENT_STREAM_START:
2472     {
2473       res = TRUE;
2474       gst_event_unref (event);
2475
2476       /* Drain all the buffers */
2477       gst_qtdemux_process_adapter (demux, TRUE);
2478       gst_qtdemux_reset (demux, FALSE);
2479       /* We expect new moov box after new stream-start event */
2480       if (demux->exposed) {
2481         gst_qtdemux_stream_concat (demux,
2482             demux->old_streams, demux->active_streams);
2483       }
2484
2485       goto drop;
2486     }
2487     default:
2488       break;
2489   }
2490
2491   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2492
2493 drop:
2494   return res;
2495 }
2496
2497 static gboolean
2498 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2499     GstQuery * query)
2500 {
2501   GstQTDemux *demux = GST_QTDEMUX (parent);
2502   gboolean res = FALSE;
2503
2504   switch (GST_QUERY_TYPE (query)) {
2505     case GST_QUERY_BITRATE:
2506     {
2507       GstClockTime duration;
2508
2509       /* populate demux->upstream_size if not done yet */
2510       gst_qtdemux_check_seekability (demux);
2511
2512       if (demux->upstream_size != -1
2513           && gst_qtdemux_get_duration (demux, &duration)) {
2514         guint bitrate =
2515             gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2516             duration);
2517
2518         GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2519             " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2520             demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2521
2522         /* TODO: better results based on ranges/index tables */
2523         gst_query_set_bitrate (query, bitrate);
2524         res = TRUE;
2525       }
2526       break;
2527     }
2528     default:
2529       res = gst_pad_query_default (pad, (GstObject *) demux, query);
2530       break;
2531   }
2532
2533   return res;
2534 }
2535
2536
2537 #if 0
2538 static void
2539 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2540 {
2541   GstQTDemux *demux = GST_QTDEMUX (element);
2542
2543   GST_OBJECT_LOCK (demux);
2544   if (demux->element_index)
2545     gst_object_unref (demux->element_index);
2546   if (index) {
2547     demux->element_index = gst_object_ref (index);
2548   } else {
2549     demux->element_index = NULL;
2550   }
2551   GST_OBJECT_UNLOCK (demux);
2552   /* object lock might be taken again */
2553   if (index)
2554     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2555   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2556       demux->element_index, demux->index_id);
2557 }
2558
2559 static GstIndex *
2560 gst_qtdemux_get_index (GstElement * element)
2561 {
2562   GstIndex *result = NULL;
2563   GstQTDemux *demux = GST_QTDEMUX (element);
2564
2565   GST_OBJECT_LOCK (demux);
2566   if (demux->element_index)
2567     result = gst_object_ref (demux->element_index);
2568   GST_OBJECT_UNLOCK (demux);
2569
2570   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2571
2572   return result;
2573 }
2574 #endif
2575
2576 static void
2577 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2578 {
2579   g_free ((gpointer) stream->stco.data);
2580   stream->stco.data = NULL;
2581   g_free ((gpointer) stream->stsz.data);
2582   stream->stsz.data = NULL;
2583   g_free ((gpointer) stream->stsc.data);
2584   stream->stsc.data = NULL;
2585   g_free ((gpointer) stream->stts.data);
2586   stream->stts.data = NULL;
2587   g_free ((gpointer) stream->stss.data);
2588   stream->stss.data = NULL;
2589   g_free ((gpointer) stream->stps.data);
2590   stream->stps.data = NULL;
2591   g_free ((gpointer) stream->ctts.data);
2592   stream->ctts.data = NULL;
2593 }
2594
2595 static void
2596 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2597 {
2598   g_free (stream->segments);
2599   stream->segments = NULL;
2600   stream->segment_index = -1;
2601   stream->accumulated_base = 0;
2602 }
2603
2604 static void
2605 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2606 {
2607   g_free (stream->samples);
2608   stream->samples = NULL;
2609   gst_qtdemux_stbl_free (stream);
2610
2611   /* fragments */
2612   g_free (stream->ra_entries);
2613   stream->ra_entries = NULL;
2614   stream->n_ra_entries = 0;
2615
2616   stream->sample_index = -1;
2617   stream->stbl_index = -1;
2618   stream->n_samples = 0;
2619   stream->time_position = 0;
2620
2621   stream->n_samples_moof = 0;
2622   stream->duration_moof = 0;
2623   stream->duration_last_moof = 0;
2624 }
2625
2626 static void
2627 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2628 {
2629   gint i;
2630   if (stream->allocator)
2631     gst_object_unref (stream->allocator);
2632   while (stream->buffers) {
2633     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2634     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2635   }
2636   for (i = 0; i < stream->stsd_entries_length; i++) {
2637     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2638     if (entry->rgb8_palette) {
2639       gst_memory_unref (entry->rgb8_palette);
2640       entry->rgb8_palette = NULL;
2641     }
2642     entry->sparse = FALSE;
2643   }
2644
2645   if (stream->stream_tags)
2646     gst_tag_list_unref (stream->stream_tags);
2647
2648   stream->stream_tags = gst_tag_list_new_empty ();
2649   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2650   g_free (stream->redirect_uri);
2651   stream->redirect_uri = NULL;
2652   stream->sent_eos = FALSE;
2653   stream->protected = FALSE;
2654   if (stream->protection_scheme_info) {
2655     if (stream->protection_scheme_type == FOURCC_cenc
2656         || stream->protection_scheme_type == FOURCC_cbcs) {
2657       QtDemuxCencSampleSetInfo *info =
2658           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2659       if (info->default_properties)
2660         gst_structure_free (info->default_properties);
2661       if (info->crypto_info)
2662         g_ptr_array_free (info->crypto_info, TRUE);
2663     }
2664     if (stream->protection_scheme_type == FOURCC_aavd) {
2665       QtDemuxAavdEncryptionInfo *info =
2666           (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
2667       if (info->default_properties)
2668         gst_structure_free (info->default_properties);
2669     }
2670     g_free (stream->protection_scheme_info);
2671     stream->protection_scheme_info = NULL;
2672   }
2673   stream->protection_scheme_type = 0;
2674   stream->protection_scheme_version = 0;
2675   g_queue_clear_full (&stream->protection_scheme_event_queue,
2676       (GDestroyNotify) gst_event_unref);
2677   gst_qtdemux_stream_flush_segments_data (stream);
2678   gst_qtdemux_stream_flush_samples_data (stream);
2679 }
2680
2681 static void
2682 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2683 {
2684   gint i;
2685   gst_qtdemux_stream_clear (stream);
2686   for (i = 0; i < stream->stsd_entries_length; i++) {
2687     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2688     if (entry->caps) {
2689       gst_caps_unref (entry->caps);
2690       entry->caps = NULL;
2691     }
2692   }
2693   g_free (stream->stsd_entries);
2694   stream->stsd_entries = NULL;
2695   stream->stsd_entries_length = 0;
2696 }
2697
2698 static QtDemuxStream *
2699 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2700 {
2701   g_atomic_int_add (&stream->ref_count, 1);
2702
2703   return stream;
2704 }
2705
2706 static void
2707 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2708 {
2709   if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2710     gst_qtdemux_stream_reset (stream);
2711     gst_tag_list_unref (stream->stream_tags);
2712     if (stream->pad) {
2713       GstQTDemux *demux = stream->demux;
2714       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2715       GST_OBJECT_LOCK (demux);
2716       gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2717       GST_OBJECT_UNLOCK (demux);
2718     }
2719     g_free (stream->stream_id);
2720     g_free (stream);
2721   }
2722 }
2723
2724 static GstStateChangeReturn
2725 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2726 {
2727   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2728   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2729
2730   switch (transition) {
2731     case GST_STATE_CHANGE_READY_TO_PAUSED:
2732       gst_qtdemux_reset (qtdemux, TRUE);
2733       break;
2734     default:
2735       break;
2736   }
2737
2738   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2739
2740   switch (transition) {
2741     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2742       gst_qtdemux_reset (qtdemux, TRUE);
2743       break;
2744     }
2745     default:
2746       break;
2747   }
2748
2749   return result;
2750 }
2751
2752 static void
2753 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2754 {
2755   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2756
2757   g_return_if_fail (GST_IS_CONTEXT (context));
2758
2759   if (gst_context_has_context_type (context,
2760           "drm-preferred-decryption-system-id")) {
2761     const GstStructure *s;
2762
2763     s = gst_context_get_structure (context);
2764     g_free (qtdemux->preferred_protection_system_id);
2765     qtdemux->preferred_protection_system_id =
2766         g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2767     GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2768         qtdemux->preferred_protection_system_id);
2769   }
2770
2771   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2772 }
2773
2774 static void
2775 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2776 {
2777   /* counts as header data */
2778   qtdemux->header_size += length;
2779
2780   /* only consider at least a sufficiently complete ftyp atom */
2781   if (length >= 20) {
2782     GstBuffer *buf;
2783     guint32 minor_version;
2784     const guint8 *p;
2785
2786     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2787     GST_DEBUG_OBJECT (qtdemux, "ftyp major brand: %" GST_FOURCC_FORMAT,
2788         GST_FOURCC_ARGS (qtdemux->major_brand));
2789     minor_version = QT_UINT32 (buffer + 12);
2790     GST_DEBUG_OBJECT (qtdemux, "ftyp minor version: %u", minor_version);
2791     if (qtdemux->comp_brands)
2792       gst_buffer_unref (qtdemux->comp_brands);
2793     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2794     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2795
2796     p = buffer + 16;
2797     length = length - 16;
2798     while (length > 0) {
2799       GST_DEBUG_OBJECT (qtdemux, "ftyp compatible brand: %" GST_FOURCC_FORMAT,
2800           GST_FOURCC_ARGS (QT_FOURCC (p)));
2801       length -= 4;
2802       p += 4;
2803     }
2804   }
2805 }
2806
2807 static void
2808 qtdemux_parse_styp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2809 {
2810   /* only consider at least a sufficiently complete styp atom */
2811   if (length >= 20) {
2812     GstBuffer *buf;
2813     guint32 major_brand;
2814     guint32 minor_version;
2815     const guint8 *p;
2816
2817     major_brand = QT_FOURCC (buffer + 8);
2818     GST_DEBUG_OBJECT (qtdemux, "styp major brand: %" GST_FOURCC_FORMAT,
2819         GST_FOURCC_ARGS (major_brand));
2820     minor_version = QT_UINT32 (buffer + 12);
2821     GST_DEBUG_OBJECT (qtdemux, "styp minor version: %u", minor_version);
2822     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2823     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2824
2825     p = buffer + 16;
2826     length = length - 16;
2827     while (length > 0) {
2828       GST_DEBUG_OBJECT (qtdemux, "styp compatible brand: %" GST_FOURCC_FORMAT,
2829           GST_FOURCC_ARGS (QT_FOURCC (p)));
2830       length -= 4;
2831       p += 4;
2832     }
2833   }
2834 }
2835
2836 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
2837 static void
2838 _get_int_value_from_xml_string (GstQTDemux * qtdemux,
2839     const char *xml_str, const char *param_name, int *value)
2840 {
2841   char *value_start, *value_end, *endptr;
2842   const short value_length_max = 12;
2843   char init_view_ret[12];
2844   int value_length = 0;
2845   int i = 0;
2846
2847   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2848
2849   if (!value_start) {
2850     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2851         param_name);
2852     return;
2853   }
2854
2855   value_start += strlen (param_name);
2856   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2857     value_start++;
2858
2859   value_end = strchr (value_start, '<');
2860   if (!value_end) {
2861     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2862     return;
2863   }
2864
2865   value_length = value_end - value_start;
2866   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2867           || (value_start[value_length - 1] == '\t')))
2868     value_length--;
2869
2870   if (value_start[i] == '+' || value_start[i] == '-')
2871     i++;
2872   while (i < value_length) {
2873     if (value_start[i] < '0' || value_start[i] > '9') {
2874       GST_ERROR_OBJECT (qtdemux,
2875           "error: incorrect value, integer was expected\n");
2876       return;
2877     }
2878     i++;
2879   }
2880
2881   if (value_length >= value_length_max || value_length < 1) {
2882     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2883     return;
2884   }
2885
2886   strncpy (init_view_ret, value_start, value_length_max);
2887   init_view_ret[value_length] = '\0';
2888
2889   *value = strtol (init_view_ret, &endptr, 10);
2890   if (endptr == init_view_ret) {
2891     GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n");
2892     return;
2893   }
2894
2895   return;
2896 }
2897
2898 static void
2899 _get_string_value_from_xml_string (GstQTDemux * qtdemux,
2900     const char *xml_str, const char *param_name, char **value)
2901 {
2902   char *value_start, *value_end;
2903   const short value_length_max = 256;
2904   int value_length = 0;
2905
2906   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2907
2908   if (!value_start) {
2909     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2910         param_name);
2911     return;
2912   }
2913
2914   value_start += strlen (param_name);
2915   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2916     value_start++;
2917
2918   value_end = strchr (value_start, '<');
2919   if (!value_end) {
2920     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2921     return;
2922   }
2923
2924   value_length = value_end - value_start;
2925   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2926           || (value_start[value_length - 1] == '\t')))
2927     value_length--;
2928
2929   if (value_length >= value_length_max || value_length < 1) {
2930     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2931     return;
2932   }
2933
2934   *value = strndup(value_start, value_length);
2935
2936   return;
2937 }
2938
2939 static void
2940 _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
2941     const char *xml_str, const char *param_name, gboolean * value)
2942 {
2943   char *value_start, *value_end;
2944   int value_length = 0;
2945
2946   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2947
2948   if (!value_start) {
2949     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2950         param_name);
2951     return;
2952   }
2953
2954   value_start += strlen (param_name);
2955   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2956     value_start++;
2957
2958   value_end = strchr (value_start, '<');
2959   if (!value_end) {
2960     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2961     return;
2962   }
2963
2964   value_length = value_end - value_start;
2965   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2966           || (value_start[value_length - 1] == '\t')))
2967     value_length--;
2968
2969   if (value_length < 1) {
2970     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2971     return;
2972   }
2973
2974   *value = g_strstr_len(value_start, value_length, "true") ? TRUE : FALSE;
2975
2976   return;
2977 }
2978
2979 static void
2980 _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux, const char *xmlStr)
2981 {
2982   const char is_spherical_str[] = "<GSpherical:Spherical>";
2983   const char is_stitched_str[] = "<GSpherical:Stitched>";
2984   const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
2985   const char projection_type_str[] = "<GSpherical:ProjectionType>";
2986   const char stereo_mode_str[] = "<GSpherical:StereoMode>";
2987   const char source_count_str[] = "<GSpherical:SourceCount>";
2988   const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
2989   const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
2990   const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
2991   const char timestamp_str[] = "<GSpherical:Timestamp>";
2992   const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
2993   const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
2994   const char cropped_area_image_width_str[] =
2995       "<GSpherical:CroppedAreaImageWidthPixels>";
2996   const char cropped_area_image_height_str[] =
2997       "<GSpherical:CroppedAreaImageHeightPixels>";
2998   const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
2999   const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
3000
3001   QtDemuxSphericalMetadata * spherical_metadata = qtdemux->spherical_metadata;
3002
3003   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
3004       (gboolean *) & spherical_metadata->is_spherical);
3005   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
3006       (gboolean *) & spherical_metadata->is_stitched);
3007
3008   if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
3009     _get_string_value_from_xml_string (qtdemux, xmlStr,
3010         stitching_software_str, &spherical_metadata->stitching_software);
3011     _get_string_value_from_xml_string (qtdemux, xmlStr,
3012         projection_type_str, &spherical_metadata->projection_type);
3013     _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
3014         &spherical_metadata->stereo_mode);
3015     _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
3016         &spherical_metadata->source_count);
3017     _get_int_value_from_xml_string (qtdemux, xmlStr,
3018         init_view_heading_str, &spherical_metadata->init_view_heading);
3019     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
3020         &spherical_metadata->init_view_pitch);
3021     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
3022         &spherical_metadata->init_view_roll);
3023     _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
3024         &spherical_metadata->timestamp);
3025     _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
3026         &spherical_metadata->full_pano_width_pixels);
3027     _get_int_value_from_xml_string (qtdemux, xmlStr,
3028         full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
3029     _get_int_value_from_xml_string (qtdemux, xmlStr,
3030         cropped_area_image_width_str,
3031         &spherical_metadata->cropped_area_image_width);
3032     _get_int_value_from_xml_string (qtdemux, xmlStr,
3033         cropped_area_image_height_str,
3034         &spherical_metadata->cropped_area_image_height);
3035     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
3036         &spherical_metadata->cropped_area_left);
3037     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
3038         &spherical_metadata->cropped_area_top);
3039   }
3040
3041   return;
3042 }
3043
3044 static void
3045 gst_tag_register_spherical_tags (void) {
3046   gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
3047       G_TYPE_INT,
3048       _("tag-spherical"),
3049       _("Flag indicating if the video is a spherical video"),
3050       NULL);
3051   gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
3052       G_TYPE_INT,
3053       _("tag-stitched"),
3054       _("Flag indicating if the video is stitched"),
3055       NULL);
3056   gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
3057       G_TYPE_STRING,
3058       _("tag-stitching-software"),
3059       _("Software used to stitch the spherical video"),
3060       NULL);
3061   gst_tag_register ("projection_type", GST_TAG_FLAG_META,
3062       G_TYPE_STRING,
3063       _("tag-projection-type"),
3064       _("Projection type used in the video frames"),
3065       NULL);
3066   gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
3067       G_TYPE_STRING,
3068       _("tag-stereo-mode"),
3069       _("Description of stereoscopic 3D layout"),
3070       NULL);
3071   gst_tag_register ("source_count", GST_TAG_FLAG_META,
3072       G_TYPE_INT,
3073       _("tag-source-count"),
3074       _("Number of cameras used to create the spherical video"),
3075       NULL);
3076   gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
3077       G_TYPE_INT,
3078       _("tag-init-view-heading"),
3079       _("The heading angle of the initial view in degrees"),
3080       NULL);
3081   gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
3082       G_TYPE_INT,
3083       _("tag-init-view-pitch"),
3084       _("The pitch angle of the initial view in degrees"),
3085       NULL);
3086   gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
3087       G_TYPE_INT,
3088       _("tag-init-view-roll"),
3089       _("The roll angle of the initial view in degrees"),
3090       NULL);
3091   gst_tag_register ("timestamp", GST_TAG_FLAG_META,
3092       G_TYPE_INT,
3093       _("tag-timestamp"),
3094       _("Epoch timestamp of when the first frame in the video was recorded"),
3095       NULL);
3096   gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
3097       G_TYPE_INT,
3098       _("tag-full-pano-width"),
3099       _("Width of the encoded video frame in pixels"),
3100       NULL);
3101   gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
3102       G_TYPE_INT,
3103       _("tag-full-pano-height"),
3104       _("Height of the encoded video frame in pixels"),
3105       NULL);
3106   gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
3107       G_TYPE_INT,
3108       _("tag-cropped-area-image-width"),
3109       _("Width of the video frame to display (e.g. cropping)"),
3110       NULL);
3111   gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
3112       G_TYPE_INT,
3113       _("tag-cropped-area-image-height"),
3114       _("Height of the video frame to display (e.g. cropping)"),
3115       NULL);
3116   gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
3117       G_TYPE_INT,
3118       _("tag-cropped-area-left"),
3119       _("Column where the left edge of the image was cropped from the"
3120           " full sized panorama"),
3121       NULL);
3122   gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
3123       G_TYPE_INT,
3124       _("tag-cropped-area-top"),
3125       _("Row where the top edge of the image was cropped from the"
3126           " full sized panorama"),
3127       NULL);
3128   gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
3129       G_TYPE_INT,
3130       _("tag-ambisonic-type"),
3131       _("Specifies the type of ambisonic audio represented"),
3132       NULL);
3133   gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
3134       G_TYPE_INT,
3135       _("tag-ambisonic-format"),
3136       _("Specifies the ambisonic audio format"),
3137       NULL);
3138   gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
3139       G_TYPE_INT,
3140       _("tag-ambisonic-order"),
3141       _("Specifies the ambisonic audio channel order"),
3142       NULL);
3143
3144   return;
3145 }
3146
3147 static void
3148 _send_spherical_metadata_msg_to_bus (GstQTDemux * qtdemux)
3149 {
3150   GstTagList *taglist;
3151   QtDemuxSphericalMetadata *spherical_metadata = qtdemux->spherical_metadata;
3152
3153   GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
3154       spherical_metadata->is_spherical);
3155   GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
3156       spherical_metadata->is_stitched);
3157   GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
3158       spherical_metadata->stitching_software);
3159   GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
3160       spherical_metadata->projection_type);
3161   GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
3162       spherical_metadata->stereo_mode);
3163   GST_DEBUG_OBJECT (qtdemux, "source_count %d",
3164       spherical_metadata->source_count);
3165   GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
3166       spherical_metadata->init_view_heading);
3167   GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
3168       spherical_metadata->init_view_pitch);
3169   GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
3170       spherical_metadata->init_view_roll);
3171   GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
3172   GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
3173       spherical_metadata->full_pano_width_pixels);
3174   GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
3175       spherical_metadata->full_pano_height_pixels);
3176   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
3177       spherical_metadata->cropped_area_image_width);
3178   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
3179       spherical_metadata->cropped_area_image_height);
3180   GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
3181       spherical_metadata->cropped_area_left);
3182   GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
3183       spherical_metadata->cropped_area_top);
3184   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
3185       spherical_metadata->ambisonic_type);
3186   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
3187       spherical_metadata->ambisonic_order);
3188   GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
3189       spherical_metadata->ambisonic_format);
3190
3191   taglist = gst_tag_list_new_empty ();
3192   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3193       "is_spherical", spherical_metadata->is_spherical,
3194       "is_stitched", spherical_metadata->is_stitched,
3195       "source_count", spherical_metadata->source_count,
3196       "init_view_heading", spherical_metadata->init_view_heading,
3197       "init_view_pitch", spherical_metadata->init_view_pitch,
3198       "init_view_roll", spherical_metadata->init_view_roll,
3199       "timestamp", spherical_metadata->timestamp,
3200       "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
3201       "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
3202       "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
3203       "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
3204       "cropped_area_left", spherical_metadata->cropped_area_left,
3205       "cropped_area_top", spherical_metadata->cropped_area_top,
3206       "ambisonic_type", spherical_metadata->ambisonic_type,
3207       "ambisonic_format", spherical_metadata->ambisonic_format,
3208       "ambisonic_order", spherical_metadata->ambisonic_order,
3209       NULL);
3210
3211   if (spherical_metadata->stitching_software)
3212     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3213         "stitching_software", spherical_metadata->stitching_software,
3214         NULL);
3215   if (spherical_metadata->projection_type)
3216     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3217         "projection_type", spherical_metadata->projection_type,
3218         NULL);
3219   if (spherical_metadata->stereo_mode)
3220     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3221         "stereo_mode", spherical_metadata->stereo_mode,
3222         NULL);
3223
3224   gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3225           gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
3226                   gst_tag_list_copy (taglist)));
3227
3228   gst_tag_list_unref(taglist);
3229
3230   return;
3231 }
3232
3233 static void
3234 qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3235 {
3236   guint offset = 0;
3237
3238   guint8 version = 0;
3239   guint8 ambisonic_type  = 0;
3240   guint32 ambisonic_order = 0;
3241   guint8 ambisonic_channel_ordering = 0;
3242   guint8 ambisonic_normalization = 0;
3243   guint32 num_channels = 0;
3244   guint32 channel_map[49] = { 0 };      /* Up to 6th order */
3245
3246   int i;
3247
3248   GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
3249
3250   qtdemux->header_size += length;
3251   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3252
3253   if (length <= offset + 16) {
3254     GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
3255     return;
3256   }
3257
3258   version = QT_UINT8 (buffer + offset);
3259   ambisonic_type = QT_UINT8 (buffer + offset + 1);
3260   ambisonic_order = QT_UINT32 (buffer + offset + 2);
3261   ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
3262   ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
3263   num_channels = QT_UINT32 (buffer + offset + 8);
3264   for (i = 0; i < num_channels; ++i)
3265     channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
3266
3267   GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
3268   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
3269   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
3270   GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
3271       ambisonic_channel_ordering);
3272   GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
3273       ambisonic_normalization);
3274   GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
3275   for (i = 0; i < num_channels; ++i)
3276     GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
3277
3278   if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
3279     if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
3280       qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
3281
3282     if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
3283       if (num_channels == 4) {
3284         qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
3285
3286         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
3287             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
3288             && (channel_map[0] == 0) && (channel_map[1] == 1)
3289             && (channel_map[2] == 2) && (channel_map[3] == 3))
3290           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
3291
3292         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
3293             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
3294             && (channel_map[0] == 0) && (channel_map[1] == 3)
3295             && (channel_map[2] == 1) && (channel_map[3] == 2))
3296           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
3297       }
3298     }
3299   }
3300
3301   return;
3302 }
3303 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3304
3305 static void
3306 qtdemux_update_default_sample_cenc_settings (GstQTDemux * qtdemux,
3307     QtDemuxCencSampleSetInfo * info, guint32 is_encrypted,
3308     guint32 protection_scheme_type, guint8 iv_size, const guint8 * kid,
3309     guint crypt_byte_block, guint skip_byte_block, guint8 constant_iv_size,
3310     const guint8 * constant_iv)
3311 {
3312   GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
3313   gst_buffer_fill (kid_buf, 0, kid, 16);
3314   if (info->default_properties)
3315     gst_structure_free (info->default_properties);
3316   info->default_properties =
3317       gst_structure_new ("application/x-cenc",
3318       "iv_size", G_TYPE_UINT, iv_size,
3319       "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
3320       "kid", GST_TYPE_BUFFER, kid_buf, NULL);
3321   GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
3322       "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
3323   gst_buffer_unref (kid_buf);
3324   if (protection_scheme_type == FOURCC_cbcs) {
3325     if (crypt_byte_block != 0 || skip_byte_block != 0) {
3326       gst_structure_set (info->default_properties, "crypt_byte_block",
3327           G_TYPE_UINT, crypt_byte_block, "skip_byte_block", G_TYPE_UINT,
3328           skip_byte_block, NULL);
3329     }
3330     if (constant_iv != NULL) {
3331       GstBuffer *constant_iv_buf =
3332           gst_buffer_new_allocate (NULL, constant_iv_size, NULL);
3333       gst_buffer_fill (constant_iv_buf, 0, constant_iv, constant_iv_size);
3334       gst_structure_set (info->default_properties, "constant_iv_size",
3335           G_TYPE_UINT, constant_iv_size, "iv", GST_TYPE_BUFFER, constant_iv_buf,
3336           NULL);
3337       gst_buffer_unref (constant_iv_buf);
3338     }
3339     gst_structure_set (info->default_properties, "cipher-mode",
3340         G_TYPE_STRING, "cbcs", NULL);
3341   } else {
3342     gst_structure_set (info->default_properties, "cipher-mode",
3343         G_TYPE_STRING, "cenc", NULL);
3344   }
3345 }
3346
3347 static gboolean
3348 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
3349     QtDemuxCencSampleSetInfo * info, GstByteReader * br)
3350 {
3351   guint32 algorithm_id = 0;
3352   const guint8 *kid;
3353   gboolean is_encrypted = TRUE;
3354   guint8 iv_size = 8;
3355
3356   if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
3357     GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
3358     return FALSE;
3359   }
3360
3361   algorithm_id >>= 8;
3362   if (algorithm_id == 0) {
3363     is_encrypted = FALSE;
3364   } else if (algorithm_id == 1) {
3365     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
3366   } else if (algorithm_id == 2) {
3367     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
3368   }
3369
3370   if (!gst_byte_reader_get_uint8 (br, &iv_size))
3371     return FALSE;
3372
3373   if (!gst_byte_reader_get_data (br, 16, &kid))
3374     return FALSE;
3375
3376   qtdemux_update_default_sample_cenc_settings (qtdemux, info,
3377       is_encrypted, FOURCC_cenc, iv_size, kid, 0, 0, 0, NULL);
3378   gst_structure_set (info->default_properties, "piff_algorithm_id",
3379       G_TYPE_UINT, algorithm_id, NULL);
3380   return TRUE;
3381 }
3382
3383
3384 static void
3385 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
3386     guint offset)
3387 {
3388   GstByteReader br;
3389   guint8 version;
3390   guint32 flags = 0;
3391   guint i;
3392   guint iv_size = 8;
3393   QtDemuxStream *stream;
3394   GstStructure *structure;
3395   QtDemuxCencSampleSetInfo *ss_info = NULL;
3396   const gchar *system_id;
3397   gboolean uses_sub_sample_encryption = FALSE;
3398   guint32 sample_count;
3399
3400   if (QTDEMUX_N_STREAMS (qtdemux) == 0)
3401     return;
3402
3403   stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
3404
3405   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
3406   if (!gst_structure_has_name (structure, "application/x-cenc")) {
3407     GST_WARNING_OBJECT (qtdemux,
3408         "Attempting PIFF box parsing on an unencrypted stream.");
3409     return;
3410   }
3411
3412   if (!gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
3413           G_TYPE_STRING, &system_id, NULL)) {
3414     GST_WARNING_OBJECT (qtdemux, "%s field not present in caps",
3415         GST_PROTECTION_SYSTEM_ID_CAPS_FIELD);
3416     return;
3417   }
3418
3419   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
3420
3421   stream->protected = TRUE;
3422   stream->protection_scheme_type = FOURCC_cenc;
3423
3424   if (!stream->protection_scheme_info)
3425     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
3426
3427   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3428   if (!ss_info->default_properties) {
3429     ss_info->default_properties =
3430         gst_structure_new ("application/x-cenc",
3431         "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
3432         NULL);
3433
3434   }
3435
3436   if (ss_info->crypto_info) {
3437     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3438     g_ptr_array_free (ss_info->crypto_info, TRUE);
3439     ss_info->crypto_info = NULL;
3440   }
3441
3442   /* skip UUID */
3443   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
3444
3445   if (!gst_byte_reader_get_uint8 (&br, &version)) {
3446     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
3447     return;
3448   }
3449
3450   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
3451     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
3452     return;
3453   }
3454
3455   if ((flags & 0x000001)) {
3456     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
3457             &br))
3458       return;
3459   } else if ((flags & 0x000002)) {
3460     uses_sub_sample_encryption = TRUE;
3461   }
3462
3463   if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
3464           &iv_size)) {
3465     GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
3466     return;
3467   }
3468
3469   if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
3470     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
3471     return;
3472   }
3473
3474   ss_info->crypto_info =
3475       g_ptr_array_new_full (sample_count,
3476       (GDestroyNotify) qtdemux_gst_structure_free);
3477
3478   for (i = 0; i < sample_count; ++i) {
3479     GstStructure *properties;
3480     guint8 *data;
3481     GstBuffer *buf;
3482
3483     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3484     if (properties == NULL) {
3485       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3486       qtdemux->cenc_aux_sample_count = i;
3487       return;
3488     }
3489
3490     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
3491       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
3492       gst_structure_free (properties);
3493       qtdemux->cenc_aux_sample_count = i;
3494       return;
3495     }
3496     buf = gst_buffer_new_wrapped (data, iv_size);
3497     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3498     gst_buffer_unref (buf);
3499
3500     if (uses_sub_sample_encryption) {
3501       guint16 n_subsamples;
3502       const GValue *kid_buf_value;
3503
3504       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
3505           || n_subsamples == 0) {
3506         GST_ERROR_OBJECT (qtdemux,
3507             "failed to get subsample count for sample %u", i);
3508         gst_structure_free (properties);
3509         qtdemux->cenc_aux_sample_count = i;
3510         return;
3511       }
3512       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3513       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
3514         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3515             i);
3516         gst_structure_free (properties);
3517         qtdemux->cenc_aux_sample_count = i;
3518         return;
3519       }
3520       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3521
3522       kid_buf_value =
3523           gst_structure_get_value (ss_info->default_properties, "kid");
3524
3525       gst_structure_set (properties,
3526           "subsample_count", G_TYPE_UINT, n_subsamples,
3527           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3528       gst_structure_set_value (properties, "kid", kid_buf_value);
3529       gst_buffer_unref (buf);
3530     } else {
3531       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3532     }
3533
3534     g_ptr_array_add (ss_info->crypto_info, properties);
3535   }
3536
3537   qtdemux->cenc_aux_sample_count = sample_count;
3538 }
3539
3540 static void
3541 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3542 {
3543   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
3544     0x97, 0xA9, 0x42, 0xE8,
3545     0x9C, 0x71, 0x99, 0x94,
3546     0x91, 0xE3, 0xAF, 0xAC
3547   };
3548   static const guint8 playready_uuid[] = {
3549     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
3550     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
3551   };
3552
3553   static const guint8 piff_sample_encryption_uuid[] = {
3554     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3555     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3556   };
3557
3558 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3559   static const guint8 spherical_uuid[] = {
3560     0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
3561     0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd
3562   };
3563 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3564
3565   guint offset;
3566
3567   /* counts as header data */
3568   qtdemux->header_size += length;
3569
3570   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3571
3572   if (length <= offset + 16) {
3573     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3574     return;
3575   }
3576
3577 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3578   if (memcmp (buffer + offset, spherical_uuid, 16) == 0) {
3579     const char *contents;
3580
3581     GST_DEBUG_OBJECT (qtdemux, "spherical uuid was found");
3582     contents = (char *) (buffer + offset + 16);
3583     GST_DEBUG_OBJECT (qtdemux, "contents: %s\n", contents);
3584
3585     if (qtdemux->spherical_metadata)
3586       _parse_spatial_video_metadata_from_xml_string (qtdemux, contents);
3587
3588     return;
3589   }
3590 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3591
3592   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3593     GstBuffer *buf;
3594     GstTagList *taglist;
3595
3596     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3597         length - offset - 16, NULL);
3598     taglist = gst_tag_list_from_xmp_buffer (buf);
3599     gst_buffer_unref (buf);
3600
3601     /* make sure we have a usable taglist */
3602     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3603
3604     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3605
3606   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3607     int len;
3608     const gunichar2 *s_utf16;
3609     char *contents;
3610
3611     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3612     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3613     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3614     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3615
3616     g_free (contents);
3617
3618     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3619         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3620         (NULL));
3621   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3622     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3623   } else {
3624     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3625         GST_READ_UINT32_LE (buffer + offset),
3626         GST_READ_UINT32_LE (buffer + offset + 4),
3627         GST_READ_UINT32_LE (buffer + offset + 8),
3628         GST_READ_UINT32_LE (buffer + offset + 12));
3629   }
3630 }
3631
3632 static void
3633 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3634 {
3635   GstSidxParser sidx_parser;
3636   GstIsoffParserResult res;
3637   guint consumed;
3638
3639   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3640
3641   res =
3642       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3643       &consumed);
3644   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3645   if (res == GST_ISOFF_QT_PARSER_DONE) {
3646     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3647   }
3648   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3649 }
3650
3651 static void
3652 qtdemux_parse_cstb (GstQTDemux * qtdemux, GstByteReader * data)
3653 {
3654   guint64 start_time;
3655   guint32 entry_count;
3656
3657   GST_DEBUG_OBJECT (qtdemux, "Parsing CorrectStartTime box");
3658
3659   qtdemux->start_utc_time = GST_CLOCK_TIME_NONE;
3660
3661   if (gst_byte_reader_get_remaining (data) < 4) {
3662     GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3663     return;
3664   }
3665
3666   entry_count = gst_byte_reader_get_uint32_be_unchecked (data);
3667   if (entry_count == 0)
3668     return;
3669
3670   /* XXX: We assume that all start times are the same as different start times
3671    * would violate the MP4 synchronization model, so we just take the first
3672    * one here and apply it to all tracks.
3673    */
3674
3675   if (gst_byte_reader_get_remaining (data) < entry_count * 12) {
3676     GST_WARNING_OBJECT (qtdemux, "Too small CorrectStartTime box");
3677     return;
3678   }
3679
3680   /* Skip track id */
3681   gst_byte_reader_skip_unchecked (data, 4);
3682
3683   /* In 100ns intervals */
3684   start_time = gst_byte_reader_get_uint64_be_unchecked (data);
3685
3686   /* Convert from Jan 1 1601 to Jan 1 1970 */
3687   if (start_time < 11644473600 * G_GUINT64_CONSTANT (10000000)) {
3688     GST_WARNING_OBJECT (qtdemux, "Start UTC time before UNIX epoch");
3689     return;
3690   }
3691   start_time -= 11644473600 * G_GUINT64_CONSTANT (10000000);
3692
3693   /* Convert to GstClockTime */
3694   start_time *= 100;
3695
3696   GST_DEBUG_OBJECT (qtdemux, "Start UTC time: %" GST_TIME_FORMAT,
3697       GST_TIME_ARGS (start_time));
3698
3699   qtdemux->start_utc_time = start_time;
3700 }
3701
3702 /* caller verifies at least 8 bytes in buf */
3703 static void
3704 extract_initial_length_and_fourcc (const guint8 * data, gsize size,
3705     guint64 * plength, guint32 * pfourcc)
3706 {
3707   guint64 length;
3708   guint32 fourcc;
3709
3710   length = QT_UINT32 (data);
3711   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3712   fourcc = QT_FOURCC (data + 4);
3713   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3714
3715   if (length == 0) {
3716     length = G_MAXUINT64;
3717   } else if (length == 1 && size >= 16) {
3718     /* this means we have an extended size, which is the 64 bit value of
3719      * the next 8 bytes */
3720     length = QT_UINT64 (data + 8);
3721     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3722   }
3723
3724   if (plength)
3725     *plength = length;
3726   if (pfourcc)
3727     *pfourcc = fourcc;
3728 }
3729
3730 static gboolean
3731 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3732 {
3733   guint32 version = 0;
3734   GstClockTime duration = 0;
3735
3736   if (!gst_byte_reader_get_uint32_be (br, &version))
3737     goto failed;
3738
3739   version >>= 24;
3740   if (version == 1) {
3741     if (!gst_byte_reader_get_uint64_be (br, &duration))
3742       goto failed;
3743   } else {
3744     guint32 dur = 0;
3745
3746     if (!gst_byte_reader_get_uint32_be (br, &dur))
3747       goto failed;
3748     duration = dur;
3749   }
3750
3751   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3752   qtdemux->duration = duration;
3753
3754   return TRUE;
3755
3756 failed:
3757   {
3758     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3759     return FALSE;
3760   }
3761 }
3762
3763 static gboolean
3764 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3765     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3766 {
3767   if (!stream->parsed_trex && qtdemux->moov_node) {
3768     GNode *mvex, *trex;
3769     GstByteReader trex_data;
3770
3771     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3772     if (mvex) {
3773       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3774           &trex_data);
3775       while (trex) {
3776         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3777
3778         /* skip version/flags */
3779         if (!gst_byte_reader_skip (&trex_data, 4))
3780           goto next;
3781         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3782           goto next;
3783         if (id != stream->track_id)
3784           goto next;
3785         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3786           goto next;
3787         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3788           goto next;
3789         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3790           goto next;
3791         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3792           goto next;
3793
3794         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3795             "duration %d,  size %d, flags 0x%x", stream->track_id,
3796             dur, size, flags);
3797
3798         stream->parsed_trex = TRUE;
3799         stream->def_sample_description_index = sdi;
3800         stream->def_sample_duration = dur;
3801         stream->def_sample_size = size;
3802         stream->def_sample_flags = flags;
3803
3804       next:
3805         /* iterate all siblings */
3806         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3807             &trex_data);
3808       }
3809     }
3810   }
3811
3812   *ds_duration = stream->def_sample_duration;
3813   *ds_size = stream->def_sample_size;
3814   *ds_flags = stream->def_sample_flags;
3815
3816   /* even then, above values are better than random ... */
3817   if (G_UNLIKELY (!stream->parsed_trex)) {
3818     GST_WARNING_OBJECT (qtdemux,
3819         "failed to find fragment defaults for stream %d", stream->track_id);
3820     return FALSE;
3821   }
3822
3823   return TRUE;
3824 }
3825
3826 /* This method should be called whenever a more accurate duration might
3827  * have been found. It will update all relevant variables if/where needed
3828  */
3829 static void
3830 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3831 {
3832   guint i;
3833   guint64 movdur;
3834   GstClockTime prevdur;
3835
3836   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3837
3838   if (movdur > qtdemux->duration) {
3839     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3840     GST_DEBUG_OBJECT (qtdemux,
3841         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3842         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3843     qtdemux->duration = movdur;
3844     GST_DEBUG_OBJECT (qtdemux,
3845         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3846         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3847         GST_TIME_ARGS (qtdemux->segment.stop));
3848     if (qtdemux->segment.duration == prevdur) {
3849       /* If the current segment has duration/stop identical to previous duration
3850        * update them also (because they were set at that point in time with
3851        * the wrong duration */
3852       /* We convert the value *from* the timescale version to avoid rounding errors */
3853       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3854       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3855       qtdemux->segment.duration = fixeddur;
3856       qtdemux->segment.stop = fixeddur;
3857     }
3858   }
3859
3860   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3861     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3862
3863     movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3864     if (movdur > stream->duration) {
3865       GST_DEBUG_OBJECT (qtdemux,
3866           "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3867           GST_TIME_ARGS (duration));
3868       stream->duration = movdur;
3869       /* internal duration tracking state has been updated above, so */
3870       /* preserve an open-ended dummy segment rather than repeatedly updating
3871        * it and spamming downstream accordingly with segment events */
3872       /* also mangle the edit list end time when fragmented with a single edit
3873        * list that may only cover any non-fragmented data */
3874       if ((stream->dummy_segment ||
3875               (qtdemux->fragmented && stream->n_segments == 1)) &&
3876           GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3877         /* Update all dummy values to new duration */
3878         stream->segments[0].stop_time = duration;
3879         stream->segments[0].duration = duration;
3880         stream->segments[0].media_stop = duration;
3881
3882         /* let downstream know we possibly have a new stop time */
3883         if (stream->segment_index != -1) {
3884           GstClockTime pos;
3885
3886           if (qtdemux->segment.rate >= 0) {
3887             pos = stream->segment.start;
3888           } else {
3889             pos = stream->segment.stop;
3890           }
3891
3892           gst_qtdemux_stream_update_segment (qtdemux, stream,
3893               stream->segment_index, pos, NULL, NULL);
3894         }
3895       }
3896     }
3897   }
3898 }
3899
3900 static gboolean
3901 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3902     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3903     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3904     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3905     gboolean has_tfdt)
3906 {
3907   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3908   guint64 timestamp;
3909   gint32 data_offset = 0;
3910   guint8 version;
3911   guint32 flags = 0, first_flags = 0, samples_count = 0;
3912   gint i;
3913   guint8 *data;
3914   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3915   QtDemuxSample *sample;
3916   gboolean ismv = FALSE;
3917   gint64 initial_offset;
3918   gint32 min_ct = 0;
3919
3920   GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3921       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3922       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3923       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3924
3925   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3926     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3927     return TRUE;
3928   }
3929
3930   /* presence of stss or not can't really tell us much,
3931    * and flags and so on tend to be marginally reliable in these files */
3932   if (stream->subtype == FOURCC_soun) {
3933     GST_DEBUG_OBJECT (qtdemux,
3934         "sound track in fragmented file; marking all keyframes");
3935     stream->all_keyframe = TRUE;
3936   }
3937
3938   if (!gst_byte_reader_get_uint8 (trun, &version) ||
3939       !gst_byte_reader_get_uint24_be (trun, &flags))
3940     goto fail;
3941
3942   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3943     goto fail;
3944
3945   if (flags & TR_DATA_OFFSET) {
3946     /* note this is really signed */
3947     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3948       goto fail;
3949     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3950     /* default base offset = first byte of moof */
3951     if (*base_offset == -1) {
3952       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3953       *base_offset = moof_offset;
3954     }
3955     *running_offset = *base_offset + data_offset;
3956   } else {
3957     /* if no offset at all, that would mean data starts at moof start,
3958      * which is a bit wrong and is ismv crappy way, so compensate
3959      * assuming data is in mdat following moof */
3960     if (*base_offset == -1) {
3961       *base_offset = moof_offset + moof_length + 8;
3962       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3963       ismv = TRUE;
3964     }
3965     if (*running_offset == -1)
3966       *running_offset = *base_offset;
3967   }
3968
3969   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3970       *running_offset);
3971   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3972       data_offset, flags, samples_count);
3973
3974   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3975     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3976       GST_DEBUG_OBJECT (qtdemux,
3977           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3978       flags ^= TR_FIRST_SAMPLE_FLAGS;
3979     } else {
3980       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3981         goto fail;
3982       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3983     }
3984   }
3985
3986   /* FIXME ? spec says other bits should also be checked to determine
3987    * entry size (and prefix size for that matter) */
3988   entry_size = 0;
3989   dur_offset = size_offset = 0;
3990   if (flags & TR_SAMPLE_DURATION) {
3991     GST_LOG_OBJECT (qtdemux, "entry duration present");
3992     dur_offset = entry_size;
3993     entry_size += 4;
3994   }
3995   if (flags & TR_SAMPLE_SIZE) {
3996     GST_LOG_OBJECT (qtdemux, "entry size present");
3997     size_offset = entry_size;
3998     entry_size += 4;
3999   }
4000   if (flags & TR_SAMPLE_FLAGS) {
4001     GST_LOG_OBJECT (qtdemux, "entry flags present");
4002     flags_offset = entry_size;
4003     entry_size += 4;
4004   }
4005   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
4006     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
4007     ct_offset = entry_size;
4008     entry_size += 4;
4009   }
4010
4011   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
4012     goto fail;
4013   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
4014
4015   if (stream->n_samples + samples_count >=
4016       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
4017     goto index_too_big;
4018
4019   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
4020       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
4021       (stream->n_samples + samples_count) *
4022       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
4023
4024   /* create a new array of samples if it's the first sample parsed */
4025   if (stream->n_samples == 0) {
4026     g_assert (stream->samples == NULL);
4027     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
4028     /* or try to reallocate it with space enough to insert the new samples */
4029   } else
4030     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
4031         stream->n_samples + samples_count);
4032   if (stream->samples == NULL)
4033     goto out_of_memory;
4034
4035   if (qtdemux->fragment_start != -1) {
4036     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
4037     qtdemux->fragment_start = -1;
4038   } else {
4039     if (stream->n_samples == 0) {
4040       if (decode_ts > 0) {
4041         timestamp = decode_ts;
4042       } else if (stream->pending_seek != NULL) {
4043         /* if we don't have a timestamp from a tfdt box, we'll use the one
4044          * from the mfra seek table */
4045         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
4046             GST_TIME_ARGS (stream->pending_seek->ts));
4047
4048         /* FIXME: this is not fully correct, the timestamp refers to the random
4049          * access sample refered to in the tfra entry, which may not necessarily
4050          * be the first sample in the tfrag/trun (but hopefully/usually is) */
4051         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
4052       } else {
4053         timestamp = 0;
4054       }
4055
4056       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
4057       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
4058           GST_TIME_ARGS (gst_ts));
4059     } else {
4060       /* If this is a GST_FORMAT_BYTES stream and we have a tfdt then use it
4061        * instead of the sum of sample durations */
4062       if (has_tfdt && !qtdemux->upstream_format_is_time) {
4063         timestamp = decode_ts;
4064         gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
4065         GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
4066             " (using tfdt)", GST_TIME_ARGS (gst_ts));
4067       } else {
4068         /* subsequent fragments extend stream */
4069         timestamp =
4070             stream->samples[stream->n_samples - 1].timestamp +
4071             stream->samples[stream->n_samples - 1].duration;
4072         gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
4073         GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
4074             " (extends previous samples)", GST_TIME_ARGS (gst_ts));
4075       }
4076     }
4077   }
4078
4079   initial_offset = *running_offset;
4080
4081   sample = stream->samples + stream->n_samples;
4082   for (i = 0; i < samples_count; i++) {
4083     guint32 dur, size, sflags;
4084     gint32 ct;
4085
4086     /* first read sample data */
4087     if (flags & TR_SAMPLE_DURATION) {
4088       dur = QT_UINT32 (data + dur_offset);
4089     } else {
4090       dur = d_sample_duration;
4091     }
4092     if (flags & TR_SAMPLE_SIZE) {
4093       size = QT_UINT32 (data + size_offset);
4094     } else {
4095       size = d_sample_size;
4096     }
4097     if (flags & TR_FIRST_SAMPLE_FLAGS) {
4098       if (i == 0) {
4099         sflags = first_flags;
4100       } else {
4101         sflags = d_sample_flags;
4102       }
4103     } else if (flags & TR_SAMPLE_FLAGS) {
4104       sflags = QT_UINT32 (data + flags_offset);
4105     } else {
4106       sflags = d_sample_flags;
4107     }
4108
4109     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
4110       /* Read offsets as signed numbers regardless of trun version as very
4111        * high offsets are unlikely and there are files out there that use
4112        * version=0 truns with negative offsets */
4113       ct = QT_UINT32 (data + ct_offset);
4114
4115       /* FIXME: Set offset to 0 for "no decode samples". This needs
4116        * to be handled in a codec specific manner ideally. */
4117       if (ct == G_MININT32)
4118         ct = 0;
4119     } else {
4120       ct = 0;
4121     }
4122     data += entry_size;
4123
4124     /* fill the sample information */
4125     sample->offset = *running_offset;
4126     sample->pts_offset = ct;
4127     sample->size = size;
4128     sample->timestamp = timestamp;
4129     sample->duration = dur;
4130     /* sample-is-difference-sample */
4131     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
4132      * now idea how it relates to bitfield other than massive LE/BE confusion */
4133     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
4134     *running_offset += size;
4135     timestamp += dur;
4136     stream->duration_moof += dur;
4137     sample++;
4138
4139     if (ct < min_ct)
4140       min_ct = ct;
4141   }
4142
4143   /* Shift PTS/DTS to allow for negative composition offsets while keeping
4144    * A/V sync in place. This is similar to the code handling ctts/cslg in the
4145    * non-fragmented case.
4146    */
4147   if (min_ct < 0)
4148     stream->cslg_shift = -min_ct;
4149   else
4150     stream->cslg_shift = 0;
4151
4152   GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
4153       stream->cslg_shift);
4154
4155   /* Update total duration if needed */
4156   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
4157
4158   /* Pre-emptively figure out size of mdat based on trun information.
4159    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
4160    * size, else we will still be able to use this when dealing with gap'ed
4161    * input */
4162   qtdemux->mdatleft = *running_offset - initial_offset;
4163   qtdemux->mdatoffset = initial_offset;
4164   qtdemux->mdatsize = qtdemux->mdatleft;
4165
4166   stream->n_samples += samples_count;
4167   stream->n_samples_moof += samples_count;
4168
4169   if (stream->pending_seek != NULL)
4170     stream->pending_seek = NULL;
4171
4172   return TRUE;
4173
4174 fail:
4175   {
4176     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
4177     return FALSE;
4178   }
4179 out_of_memory:
4180   {
4181     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
4182         stream->n_samples);
4183     return FALSE;
4184   }
4185 index_too_big:
4186   {
4187     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
4188         "be larger than %uMB (broken file?)", stream->n_samples,
4189         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
4190     return FALSE;
4191   }
4192 }
4193
4194 /* find stream with @id */
4195 static inline QtDemuxStream *
4196 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
4197 {
4198   QtDemuxStream *stream;
4199   gint i;
4200
4201   /* check */
4202   if (G_UNLIKELY (!id)) {
4203     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
4204     return NULL;
4205   }
4206
4207   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4208     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4209     if (stream->track_id == id)
4210       return stream;
4211   }
4212   if (qtdemux->variant == VARIANT_MSS_FRAGMENTED) {
4213     /* mss should have only 1 stream anyway */
4214     return QTDEMUX_NTH_STREAM (qtdemux, 0);
4215   }
4216
4217   return NULL;
4218 }
4219
4220 static gboolean
4221 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
4222     guint32 * fragment_number)
4223 {
4224   if (!gst_byte_reader_skip (mfhd, 4))
4225     goto fail;
4226   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
4227     goto fail;
4228   return TRUE;
4229 fail:
4230   {
4231     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
4232     return FALSE;
4233   }
4234 }
4235
4236 static gboolean
4237 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
4238     QtDemuxStream ** stream, guint32 * default_sample_duration,
4239     guint32 * default_sample_size, guint32 * default_sample_flags,
4240     gint64 * base_offset)
4241 {
4242   guint32 flags = 0;
4243   guint32 track_id = 0;
4244
4245   if (!gst_byte_reader_skip (tfhd, 1) ||
4246       !gst_byte_reader_get_uint24_be (tfhd, &flags))
4247     goto invalid_track;
4248
4249   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
4250     goto invalid_track;
4251
4252   *stream = qtdemux_find_stream (qtdemux, track_id);
4253   if (G_UNLIKELY (!*stream))
4254     goto unknown_stream;
4255
4256   if (flags & TF_DEFAULT_BASE_IS_MOOF)
4257     *base_offset = qtdemux->moof_offset;
4258
4259   if (flags & TF_BASE_DATA_OFFSET)
4260     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
4261       goto invalid_track;
4262
4263   /* obtain stream defaults */
4264   if (qtdemux_parse_trex (qtdemux, *stream,
4265           default_sample_duration, default_sample_size, default_sample_flags)) {
4266
4267     /* Default sample description index is only valid if trex parsing succeeded */
4268     (*stream)->stsd_sample_description_id =
4269         (*stream)->def_sample_description_index - 1;
4270   }
4271
4272   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
4273     guint32 sample_description_index;
4274     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
4275       goto invalid_track;
4276     (*stream)->stsd_sample_description_id = sample_description_index - 1;
4277   }
4278
4279   if (qtdemux->variant == VARIANT_MSS_FRAGMENTED) {
4280     /* mss has no stsd entry */
4281     (*stream)->stsd_sample_description_id = 0;
4282   }
4283
4284   if (flags & TF_DEFAULT_SAMPLE_DURATION)
4285     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
4286       goto invalid_track;
4287
4288   if (flags & TF_DEFAULT_SAMPLE_SIZE)
4289     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
4290       goto invalid_track;
4291
4292   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
4293     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
4294       goto invalid_track;
4295
4296   return TRUE;
4297
4298 invalid_track:
4299   {
4300     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
4301     return FALSE;
4302   }
4303 unknown_stream:
4304   {
4305     GST_DEBUG_OBJECT (qtdemux, "unknown stream (%u) in tfhd", track_id);
4306     return TRUE;
4307   }
4308 }
4309
4310 static gboolean
4311 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
4312     guint64 * decode_time)
4313 {
4314   guint32 version = 0;
4315
4316   if (!gst_byte_reader_get_uint32_be (br, &version))
4317     return FALSE;
4318
4319   version >>= 24;
4320   if (version == 1) {
4321     if (!gst_byte_reader_get_uint64_be (br, decode_time))
4322       goto failed;
4323   } else {
4324     guint32 dec_time = 0;
4325     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
4326       goto failed;
4327     *decode_time = dec_time;
4328   }
4329
4330   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
4331       *decode_time);
4332
4333   return TRUE;
4334
4335 failed:
4336   {
4337     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
4338     return FALSE;
4339   }
4340 }
4341
4342 /* Returns a pointer to a GstStructure containing the properties of
4343  * the stream sample identified by @sample_index. The caller must unref
4344  * the returned object after use. Returns NULL if unsuccessful. */
4345 static GstStructure *
4346 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
4347     QtDemuxStream * stream, guint sample_index)
4348 {
4349   QtDemuxCencSampleSetInfo *info = NULL;
4350
4351   g_return_val_if_fail (stream != NULL, NULL);
4352   g_return_val_if_fail (stream->protected, NULL);
4353   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
4354
4355   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4356
4357   /* Currently, cenc properties for groups of samples are not supported, so
4358    * simply return a copy of the default sample properties */
4359   return gst_structure_copy (info->default_properties);
4360 }
4361
4362 /* Parses the sizes of sample auxiliary information contained within a stream,
4363  * as given in a saiz box. Returns array of sample_count guint8 size values,
4364  * or NULL on failure */
4365 static guint8 *
4366 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
4367     GstByteReader * br, guint32 * sample_count)
4368 {
4369   guint32 flags = 0;
4370   guint8 *info_sizes;
4371   guint8 default_info_size;
4372
4373   g_return_val_if_fail (qtdemux != NULL, NULL);
4374   g_return_val_if_fail (stream != NULL, NULL);
4375   g_return_val_if_fail (br != NULL, NULL);
4376   g_return_val_if_fail (sample_count != NULL, NULL);
4377
4378   if (!gst_byte_reader_get_uint32_be (br, &flags))
4379     return NULL;
4380
4381   if (flags & 0x1) {
4382     /* aux_info_type and aux_info_type_parameter are ignored */
4383     if (!gst_byte_reader_skip (br, 8))
4384       return NULL;
4385   }
4386
4387   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
4388     return NULL;
4389   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
4390
4391   if (!gst_byte_reader_get_uint32_be (br, sample_count))
4392     return NULL;
4393   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
4394
4395
4396   if (default_info_size == 0) {
4397     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
4398       return NULL;
4399     }
4400   } else {
4401     info_sizes = g_new (guint8, *sample_count);
4402     memset (info_sizes, default_info_size, *sample_count);
4403   }
4404
4405   return info_sizes;
4406 }
4407
4408 /* Parses the offset of sample auxiliary information contained within a stream,
4409  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
4410 static gboolean
4411 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
4412     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
4413     guint64 * offset)
4414 {
4415   guint8 version = 0;
4416   guint32 flags = 0;
4417   guint32 aux_info_type = 0;
4418   guint32 aux_info_type_parameter = 0;
4419   guint32 entry_count;
4420   guint32 off_32;
4421   guint64 off_64;
4422   const guint8 *aux_info_type_data = NULL;
4423
4424   g_return_val_if_fail (qtdemux != NULL, FALSE);
4425   g_return_val_if_fail (stream != NULL, FALSE);
4426   g_return_val_if_fail (br != NULL, FALSE);
4427   g_return_val_if_fail (offset != NULL, FALSE);
4428
4429   if (!gst_byte_reader_get_uint8 (br, &version))
4430     return FALSE;
4431
4432   if (!gst_byte_reader_get_uint24_be (br, &flags))
4433     return FALSE;
4434
4435   if (flags & 0x1) {
4436
4437     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
4438       return FALSE;
4439     aux_info_type = QT_FOURCC (aux_info_type_data);
4440
4441     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
4442       return FALSE;
4443   } else if (stream->protected) {
4444     aux_info_type = stream->protection_scheme_type;
4445   } else {
4446     aux_info_type = CUR_STREAM (stream)->fourcc;
4447   }
4448
4449   if (info_type)
4450     *info_type = aux_info_type;
4451   if (info_type_parameter)
4452     *info_type_parameter = aux_info_type_parameter;
4453
4454   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
4455       "aux_info_type_parameter:  %#06x",
4456       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
4457
4458   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
4459     return FALSE;
4460
4461   if (entry_count != 1) {
4462     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
4463     return FALSE;
4464   }
4465
4466   if (version == 0) {
4467     if (!gst_byte_reader_get_uint32_be (br, &off_32))
4468       return FALSE;
4469     *offset = (guint64) off_32;
4470   } else {
4471     if (!gst_byte_reader_get_uint64_be (br, &off_64))
4472       return FALSE;
4473     *offset = off_64;
4474   }
4475
4476   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
4477   return TRUE;
4478 }
4479
4480 static void
4481 qtdemux_gst_structure_free (GstStructure * gststructure)
4482 {
4483   if (gststructure) {
4484     gst_structure_free (gststructure);
4485   }
4486 }
4487
4488 /* Parses auxiliary information relating to samples protected using
4489  * Common Encryption (cenc); the format of this information
4490  * is defined in ISO/IEC 23001-7. Returns TRUE if successful; FALSE
4491  * otherwise. */
4492 static gboolean
4493 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
4494     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
4495 {
4496   QtDemuxCencSampleSetInfo *ss_info = NULL;
4497   guint8 size;
4498   gint i;
4499   GPtrArray *old_crypto_info = NULL;
4500   guint old_entries = 0;
4501
4502   g_return_val_if_fail (qtdemux != NULL, FALSE);
4503   g_return_val_if_fail (stream != NULL, FALSE);
4504   g_return_val_if_fail (br != NULL, FALSE);
4505   g_return_val_if_fail (stream->protected, FALSE);
4506   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
4507
4508   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4509
4510   if (ss_info->crypto_info) {
4511     old_crypto_info = ss_info->crypto_info;
4512     /* Count number of non-null entries remaining at the tail end */
4513     for (i = old_crypto_info->len - 1; i >= 0; i--) {
4514       if (g_ptr_array_index (old_crypto_info, i) == NULL)
4515         break;
4516       old_entries++;
4517     }
4518   }
4519
4520   ss_info->crypto_info =
4521       g_ptr_array_new_full (sample_count + old_entries,
4522       (GDestroyNotify) qtdemux_gst_structure_free);
4523
4524   /* We preserve old entries because we parse the next moof in advance
4525    * of consuming all samples from the previous moof, and otherwise
4526    * we'd discard the corresponding crypto info for the samples
4527    * from the previous fragment. */
4528   if (old_entries) {
4529     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
4530         old_entries);
4531     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
4532       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
4533               i));
4534       g_ptr_array_index (old_crypto_info, i) = NULL;
4535     }
4536   }
4537
4538   if (old_crypto_info) {
4539     /* Everything now belongs to the new array */
4540     g_ptr_array_free (old_crypto_info, TRUE);
4541   }
4542
4543   for (i = 0; i < sample_count; ++i) {
4544     GstStructure *properties;
4545     guint16 n_subsamples = 0;
4546     guint8 *data;
4547     guint iv_size;
4548     GstBuffer *buf;
4549     gboolean could_read_iv;
4550
4551     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
4552     if (properties == NULL) {
4553       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
4554       return FALSE;
4555     }
4556     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
4557       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
4558       gst_structure_free (properties);
4559       return FALSE;
4560     }
4561     could_read_iv =
4562         iv_size > 0 ? gst_byte_reader_dup_data (br, iv_size, &data) : FALSE;
4563     if (could_read_iv) {
4564       buf = gst_buffer_new_wrapped (data, iv_size);
4565       gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
4566       gst_buffer_unref (buf);
4567     } else if (stream->protection_scheme_type == FOURCC_cbcs) {
4568       const GValue *constant_iv_size_value =
4569           gst_structure_get_value (properties, "constant_iv_size");
4570       const GValue *constant_iv_value =
4571           gst_structure_get_value (properties, "iv");
4572       if (constant_iv_size_value == NULL || constant_iv_value == NULL) {
4573         GST_ERROR_OBJECT (qtdemux, "failed to get constant_iv");
4574         gst_structure_free (properties);
4575         return FALSE;
4576       }
4577       gst_structure_set_value (properties, "iv_size", constant_iv_size_value);
4578       gst_structure_remove_field (properties, "constant_iv_size");
4579     } else if (stream->protection_scheme_type == FOURCC_cenc) {
4580       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4581       gst_structure_free (properties);
4582       return FALSE;
4583     }
4584     size = info_sizes[i];
4585     if (size > iv_size) {
4586       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4587           || !(n_subsamples > 0)) {
4588         gst_structure_free (properties);
4589         GST_ERROR_OBJECT (qtdemux,
4590             "failed to get subsample count for sample %u", i);
4591         return FALSE;
4592       }
4593       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4594       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4595         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4596             i);
4597         gst_structure_free (properties);
4598         return FALSE;
4599       }
4600       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4601       if (!buf) {
4602         gst_structure_free (properties);
4603         return FALSE;
4604       }
4605       gst_structure_set (properties,
4606           "subsample_count", G_TYPE_UINT, n_subsamples,
4607           "subsamples", GST_TYPE_BUFFER, buf, NULL);
4608       gst_buffer_unref (buf);
4609     } else {
4610       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4611     }
4612     g_ptr_array_add (ss_info->crypto_info, properties);
4613   }
4614   return TRUE;
4615 }
4616
4617 /* Converts a UUID in raw byte form to a string representation, as defined in
4618  * RFC 4122. The caller takes ownership of the returned string and is
4619  * responsible for freeing it after use. */
4620 static gchar *
4621 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4622 {
4623   const guint8 *uuid = (const guint8 *) uuid_bytes;
4624
4625   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4626       "%02x%02x-%02x%02x%02x%02x%02x%02x",
4627       uuid[0], uuid[1], uuid[2], uuid[3],
4628       uuid[4], uuid[5], uuid[6], uuid[7],
4629       uuid[8], uuid[9], uuid[10], uuid[11],
4630       uuid[12], uuid[13], uuid[14], uuid[15]);
4631 }
4632
4633 /* Parses a Protection System Specific Header box (pssh), as defined in the
4634  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4635  * information needed by a specific content protection system in order to
4636  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4637  * otherwise. */
4638 static gboolean
4639 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4640 {
4641   gchar *sysid_string;
4642   guint32 pssh_size = QT_UINT32 (node->data);
4643   GstBuffer *pssh = NULL;
4644   GstEvent *event = NULL;
4645   guint32 parent_box_type;
4646   gint i;
4647
4648   if (G_UNLIKELY (pssh_size < 32U)) {
4649     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4650     return FALSE;
4651   }
4652
4653   sysid_string =
4654       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4655
4656   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4657
4658   pssh = gst_buffer_new_memdup (node->data, pssh_size);
4659   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4660       gst_buffer_get_size (pssh));
4661
4662   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4663
4664   /* Push an event containing the pssh box onto the queues of all streams. */
4665   event = gst_event_new_protection (sysid_string, pssh,
4666       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4667   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4668     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4669     GST_TRACE_OBJECT (qtdemux,
4670         "adding protection event for stream %s and system %s",
4671         stream->stream_id, sysid_string);
4672     g_queue_push_tail (&stream->protection_scheme_event_queue,
4673         gst_event_ref (event));
4674   }
4675   g_free (sysid_string);
4676   gst_event_unref (event);
4677   gst_buffer_unref (pssh);
4678   return TRUE;
4679 }
4680
4681 static gboolean
4682 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4683     guint64 moof_offset, QtDemuxStream * stream)
4684 {
4685   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4686   GNode *uuid_node;
4687   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4688   GNode *saiz_node, *saio_node, *pssh_node;
4689   GstByteReader saiz_data, saio_data;
4690   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4691   gint64 base_offset, running_offset;
4692   guint32 frag_num;
4693   GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4694
4695   /* NOTE @stream ignored */
4696
4697   moof_node = g_node_new ((guint8 *) buffer);
4698   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4699   qtdemux_node_dump (qtdemux, moof_node);
4700
4701   /* Get fragment number from mfhd and check it's valid */
4702   mfhd_node =
4703       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4704   if (mfhd_node == NULL)
4705     goto missing_mfhd;
4706   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4707     goto fail;
4708   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4709
4710   /* unknown base_offset to start with */
4711   base_offset = running_offset = -1;
4712   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4713   while (traf_node) {
4714     guint64 decode_time = 0;
4715
4716     /* Fragment Header node */
4717     tfhd_node =
4718         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4719         &tfhd_data);
4720     if (!tfhd_node)
4721       goto missing_tfhd;
4722     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4723             &ds_size, &ds_flags, &base_offset))
4724       goto missing_tfhd;
4725
4726     /* The following code assumes at most a single set of sample auxiliary
4727      * data in the fragment (consisting of a saiz box and a corresponding saio
4728      * box); in theory, however, there could be multiple sets of sample
4729      * auxiliary data in a fragment. */
4730     saiz_node =
4731         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4732         &saiz_data);
4733     if (saiz_node) {
4734       guint32 info_type = 0;
4735       guint64 offset = 0;
4736       guint32 info_type_parameter = 0;
4737
4738       g_free (qtdemux->cenc_aux_info_sizes);
4739
4740       qtdemux->cenc_aux_info_sizes =
4741           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4742           &qtdemux->cenc_aux_sample_count);
4743       if (qtdemux->cenc_aux_info_sizes == NULL) {
4744         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4745         goto fail;
4746       }
4747       saio_node =
4748           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4749           &saio_data);
4750       if (!saio_node) {
4751         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4752         g_free (qtdemux->cenc_aux_info_sizes);
4753         qtdemux->cenc_aux_info_sizes = NULL;
4754         goto fail;
4755       }
4756
4757       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4758                   &info_type, &info_type_parameter, &offset))) {
4759         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4760         g_free (qtdemux->cenc_aux_info_sizes);
4761         qtdemux->cenc_aux_info_sizes = NULL;
4762         goto fail;
4763       }
4764       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4765         offset += (guint64) (base_offset - qtdemux->moof_offset);
4766       if ((info_type == FOURCC_cenc || info_type == FOURCC_cbcs)
4767           && info_type_parameter == 0U) {
4768         GstByteReader br;
4769         if (offset > length) {
4770           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4771           qtdemux->cenc_aux_info_offset = offset;
4772         } else {
4773           gst_byte_reader_init (&br, buffer + offset, length - offset);
4774           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4775                   qtdemux->cenc_aux_info_sizes,
4776                   qtdemux->cenc_aux_sample_count)) {
4777             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4778             g_free (qtdemux->cenc_aux_info_sizes);
4779             qtdemux->cenc_aux_info_sizes = NULL;
4780             goto fail;
4781           }
4782         }
4783       }
4784     }
4785
4786     tfdt_node =
4787         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4788         &tfdt_data);
4789     if (tfdt_node) {
4790       /* We'll use decode_time to interpolate timestamps
4791        * in case the input timestamps are missing */
4792       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4793
4794       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4795           " (%" GST_TIME_FORMAT ")", decode_time,
4796           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4797                   decode_time) : GST_CLOCK_TIME_NONE));
4798
4799       /* Discard the fragment buffer timestamp info to avoid using it.
4800        * Rely on tfdt instead as it is more accurate than the timestamp
4801        * that is fetched from a manifest/playlist and is usually
4802        * less accurate. */
4803       qtdemux->fragment_start = -1;
4804     }
4805
4806     if (G_UNLIKELY (!stream)) {
4807       /* we lost track of offset, we'll need to regain it,
4808        * but can delay complaining until later or avoid doing so altogether */
4809       base_offset = -2;
4810       goto next;
4811     }
4812     if (G_UNLIKELY (base_offset < -1))
4813       goto lost_offset;
4814
4815     min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4816
4817     if (!qtdemux->pullbased) {
4818       /* Sample tables can grow enough to be problematic if the system memory
4819        * is very low (e.g. embedded devices) and the videos very long
4820        * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4821        * Fortunately, we can easily discard them for each new fragment when
4822        * we know qtdemux will not receive seeks outside of the current fragment.
4823        * adaptivedemux honors this assumption.
4824        * This optimization is also useful for applications that use qtdemux as
4825        * a push-based simple demuxer, like Media Source Extensions. */
4826       gst_qtdemux_stream_flush_samples_data (stream);
4827     }
4828
4829     /* initialise moof sample data */
4830     stream->n_samples_moof = 0;
4831     stream->duration_last_moof = stream->duration_moof;
4832     stream->duration_moof = 0;
4833
4834     /* Track Run node */
4835     trun_node =
4836         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4837         &trun_data);
4838     while (trun_node) {
4839       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4840           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4841           &running_offset, decode_time, (tfdt_node != NULL));
4842       /* iterate all siblings */
4843       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4844           &trun_data);
4845       /* don't use tfdt for subsequent trun as it only refers to the first */
4846       tfdt_node = NULL;
4847     }
4848
4849     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4850     if (uuid_node) {
4851       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4852       guint32 box_length = QT_UINT32 (uuid_buffer);
4853
4854       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4855     }
4856
4857     /* if no new base_offset provided for next traf,
4858      * base is end of current traf */
4859     base_offset = running_offset;
4860     running_offset = -1;
4861
4862     if (stream->n_samples_moof && stream->duration_moof)
4863       stream->new_caps = TRUE;
4864
4865   next:
4866     /* iterate all siblings */
4867     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4868   }
4869
4870   /* parse any protection system info */
4871   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4872   if (pssh_node) {
4873     /* Unref old protection events if we are going to receive new ones. */
4874     qtdemux_clear_protection_events_on_all_streams (qtdemux);
4875   }
4876   while (pssh_node) {
4877     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4878     qtdemux_parse_pssh (qtdemux, pssh_node);
4879     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4880   }
4881
4882   if (!qtdemux->upstream_format_is_time
4883       && qtdemux->variant != VARIANT_MSE_BYTESTREAM
4884       && !qtdemux->first_moof_already_parsed
4885       && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4886       && min_dts != 0) {
4887     /* Unless the user has explicitly requested another seek, perform an
4888      * internal seek to the time specified in the tfdt.
4889      *
4890      * This way if the user opens a file where the first tfdt is 1 hour
4891      * into the presentation, they will not have to wait 1 hour for run
4892      * time to catch up and actual playback to start. */
4893     gint i;
4894
4895     GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4896         "performing an internal seek to %" GST_TIME_FORMAT,
4897         GST_TIME_ARGS (min_dts));
4898
4899     qtdemux->segment.start = min_dts;
4900     qtdemux->segment.time = qtdemux->segment.position = min_dts;
4901
4902     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4903       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4904       stream->time_position = min_dts;
4905     }
4906
4907     /* Before this code was run a segment was already sent when the moov was
4908      * parsed... which is OK -- some apps (mostly tests) expect a segment to
4909      * be emitted after a moov, and we can emit a second segment anyway for
4910      * special cases like this. */
4911     qtdemux->need_segment = TRUE;
4912   }
4913
4914   qtdemux->first_moof_already_parsed = TRUE;
4915
4916   g_node_destroy (moof_node);
4917   return TRUE;
4918
4919 missing_tfhd:
4920   {
4921     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4922     goto fail;
4923   }
4924 missing_mfhd:
4925   {
4926     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4927     goto fail;
4928   }
4929 lost_offset:
4930   {
4931     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4932     goto fail;
4933   }
4934 fail:
4935   {
4936     g_node_destroy (moof_node);
4937     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4938         (_("This file is corrupt and cannot be played.")), (NULL));
4939     return FALSE;
4940   }
4941 }
4942
4943 #if 0
4944 /* might be used if some day we actually use mfra & co
4945  * for random access to fragments,
4946  * but that will require quite some modifications and much less relying
4947  * on a sample array */
4948 #endif
4949
4950 static gboolean
4951 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4952 {
4953   QtDemuxStream *stream;
4954   guint32 ver_flags, track_id, len, num_entries, i;
4955   guint value_size, traf_size, trun_size, sample_size;
4956   guint64 time = 0, moof_offset = 0;
4957 #if 0
4958   GstBuffer *buf = NULL;
4959   GstFlowReturn ret;
4960 #endif
4961   GstByteReader tfra;
4962
4963   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4964
4965   if (!gst_byte_reader_skip (&tfra, 8))
4966     return FALSE;
4967
4968   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4969     return FALSE;
4970
4971   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4972       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4973       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4974     return FALSE;
4975
4976   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4977
4978   stream = qtdemux_find_stream (qtdemux, track_id);
4979   if (stream == NULL)
4980     goto unknown_trackid;
4981
4982   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4983   sample_size = (len & 3) + 1;
4984   trun_size = ((len & 12) >> 2) + 1;
4985   traf_size = ((len & 48) >> 4) + 1;
4986
4987   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4988       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4989
4990   if (num_entries == 0)
4991     goto no_samples;
4992
4993   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4994           value_size + value_size + traf_size + trun_size + sample_size))
4995     goto corrupt_file;
4996
4997   g_free (stream->ra_entries);
4998   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4999   stream->n_ra_entries = num_entries;
5000
5001   for (i = 0; i < num_entries; i++) {
5002     qt_atom_parser_get_offset (&tfra, value_size, &time);
5003     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
5004     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
5005     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
5006     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
5007
5008     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
5009
5010     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
5011         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
5012
5013     stream->ra_entries[i].ts = time;
5014     stream->ra_entries[i].moof_offset = moof_offset;
5015
5016     /* don't want to go through the entire file and read all moofs at startup */
5017 #if 0
5018     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
5019     if (ret != GST_FLOW_OK)
5020       goto corrupt_file;
5021     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
5022         moof_offset, stream);
5023     gst_buffer_unref (buf);
5024 #endif
5025   }
5026
5027   check_update_duration (qtdemux, time);
5028
5029   return TRUE;
5030
5031 /* ERRORS */
5032 unknown_trackid:
5033   {
5034     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
5035     return FALSE;
5036   }
5037 corrupt_file:
5038   {
5039     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
5040     return FALSE;
5041   }
5042 no_samples:
5043   {
5044     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
5045     return FALSE;
5046   }
5047 }
5048
5049 static gboolean
5050 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
5051 {
5052   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
5053   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
5054   GstBuffer *mfro = NULL, *mfra = NULL;
5055   GstFlowReturn flow;
5056   gboolean ret = FALSE;
5057   GNode *mfra_node, *tfra_node;
5058   guint64 mfra_offset = 0;
5059   guint32 fourcc, mfra_size;
5060   gint64 len;
5061
5062   /* query upstream size in bytes */
5063   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
5064     goto size_query_failed;
5065
5066   /* mfro box should be at the very end of the file */
5067   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
5068   if (flow != GST_FLOW_OK)
5069     goto exit;
5070
5071   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
5072
5073   fourcc = QT_FOURCC (mfro_map.data + 4);
5074   if (fourcc != FOURCC_mfro)
5075     goto exit;
5076
5077   GST_INFO_OBJECT (qtdemux, "Found mfro box");
5078   if (mfro_map.size < 16)
5079     goto invalid_mfro_size;
5080
5081   mfra_size = QT_UINT32 (mfro_map.data + 12);
5082   if (mfra_size >= len)
5083     goto invalid_mfra_size;
5084
5085   mfra_offset = len - mfra_size;
5086
5087   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
5088       mfra_offset, mfra_size);
5089
5090   /* now get and parse mfra box */
5091   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
5092   if (flow != GST_FLOW_OK)
5093     goto broken_file;
5094
5095   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
5096
5097   mfra_node = g_node_new ((guint8 *) mfra_map.data);
5098   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
5099
5100   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
5101
5102   while (tfra_node) {
5103     qtdemux_parse_tfra (qtdemux, tfra_node);
5104     /* iterate all siblings */
5105     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
5106   }
5107   g_node_destroy (mfra_node);
5108
5109   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
5110   ret = TRUE;
5111
5112 exit:
5113
5114   if (mfro) {
5115     if (mfro_map.memory != NULL)
5116       gst_buffer_unmap (mfro, &mfro_map);
5117     gst_buffer_unref (mfro);
5118   }
5119   if (mfra) {
5120     if (mfra_map.memory != NULL)
5121       gst_buffer_unmap (mfra, &mfra_map);
5122     gst_buffer_unref (mfra);
5123   }
5124   return ret;
5125
5126 /* ERRORS */
5127 size_query_failed:
5128   {
5129     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
5130     goto exit;
5131   }
5132 invalid_mfro_size:
5133   {
5134     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
5135     goto exit;
5136   }
5137 invalid_mfra_size:
5138   {
5139     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
5140     goto exit;
5141   }
5142 broken_file:
5143   {
5144     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
5145     goto exit;
5146   }
5147 }
5148
5149 static guint64
5150 add_offset (guint64 offset, guint64 advance)
5151 {
5152   /* Avoid 64-bit overflow by clamping */
5153   if (offset > G_MAXUINT64 - advance)
5154     return G_MAXUINT64;
5155   return offset + advance;
5156 }
5157
5158 static GstFlowReturn
5159 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
5160 {
5161   guint64 length = 0;
5162   guint32 fourcc = 0;
5163   GstBuffer *buf = NULL;
5164   GstFlowReturn ret = GST_FLOW_OK;
5165   guint64 cur_offset = qtdemux->offset;
5166   GstMapInfo map;
5167
5168   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
5169   if (G_UNLIKELY (ret != GST_FLOW_OK))
5170     goto beach;
5171   gst_buffer_map (buf, &map, GST_MAP_READ);
5172   if (G_LIKELY (map.size >= 8))
5173     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
5174   gst_buffer_unmap (buf, &map);
5175   gst_buffer_unref (buf);
5176
5177   /* maybe we already got most we needed, so only consider this eof */
5178   if (G_UNLIKELY (length == 0)) {
5179     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5180         (_("Invalid atom size.")),
5181         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
5182             GST_FOURCC_ARGS (fourcc)));
5183     ret = GST_FLOW_EOS;
5184     goto beach;
5185   }
5186
5187   switch (fourcc) {
5188     case FOURCC_moof:
5189       /* record for later parsing when needed */
5190       if (!qtdemux->moof_offset) {
5191         qtdemux->moof_offset = qtdemux->offset;
5192       }
5193       if (qtdemux_pull_mfro_mfra (qtdemux)) {
5194         /* FIXME */
5195       } else {
5196         qtdemux->offset += length;      /* skip moof and keep going */
5197       }
5198       if (qtdemux->got_moov) {
5199         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
5200         ret = GST_FLOW_EOS;
5201         goto beach;
5202       }
5203       break;
5204     case FOURCC_mdat:
5205     case FOURCC_free:
5206     case FOURCC_skip:
5207     case FOURCC_wide:
5208     case FOURCC_PICT:
5209     case FOURCC_pnot:
5210     {
5211       GST_LOG_OBJECT (qtdemux,
5212           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5213           GST_FOURCC_ARGS (fourcc), cur_offset);
5214       qtdemux->offset = add_offset (qtdemux->offset, length);
5215       break;
5216     }
5217     case FOURCC_moov:
5218     {
5219       GstBuffer *moov = NULL;
5220
5221       if (qtdemux->got_moov) {
5222         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
5223         qtdemux->offset = add_offset (qtdemux->offset, length);
5224         goto beach;
5225       }
5226
5227       if (length == G_MAXUINT64) {
5228         /* Read until the end */
5229         gint64 duration;
5230         if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES,
5231                 &duration)) {
5232           GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5233               (_("Cannot query file size")),
5234               ("Duration query on sink pad failed"));
5235           ret = GST_FLOW_ERROR;
5236           goto beach;
5237         }
5238         if (G_UNLIKELY (cur_offset > duration)) {
5239           GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5240               (_("Cannot query file size")),
5241               ("Duration %" G_GINT64_FORMAT " < current offset %"
5242                   G_GUINT64_FORMAT, duration, cur_offset));
5243           ret = GST_FLOW_ERROR;
5244           goto beach;
5245         }
5246         length = duration - cur_offset;
5247         if (length > QTDEMUX_MAX_ATOM_SIZE) {
5248           GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5249               (_("Cannot demux file")),
5250               ("Moov atom size %" G_GINT64_FORMAT " > maximum %d", length,
5251                   QTDEMUX_MAX_ATOM_SIZE));
5252           ret = GST_FLOW_ERROR;
5253           goto beach;
5254         }
5255       }
5256
5257       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
5258       if (ret != GST_FLOW_OK)
5259         goto beach;
5260       gst_buffer_map (moov, &map, GST_MAP_READ);
5261
5262       if (length != map.size) {
5263         /* Some files have a 'moov' atom at the end of the file which contains
5264          * a terminal 'free' atom where the body of the atom is missing.
5265          * Check for, and permit, this special case.
5266          */
5267         if (map.size >= 8) {
5268           guint8 *final_data = map.data + (map.size - 8);
5269           guint32 final_length = QT_UINT32 (final_data);
5270           guint32 final_fourcc = QT_FOURCC (final_data + 4);
5271
5272           if (final_fourcc == FOURCC_free
5273               && map.size + final_length - 8 == length) {
5274             /* Ok, we've found that special case. Allocate a new buffer with
5275              * that free atom actually present. */
5276             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
5277             gst_buffer_fill (newmoov, 0, map.data, map.size);
5278             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
5279             gst_buffer_unmap (moov, &map);
5280             gst_buffer_unref (moov);
5281             moov = newmoov;
5282             gst_buffer_map (moov, &map, GST_MAP_READ);
5283           }
5284         }
5285       }
5286
5287       if (length != map.size) {
5288         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5289             (_("This file is incomplete and cannot be played.")),
5290             ("We got less than expected (received %" G_GSIZE_FORMAT
5291                 ", wanted %" G_GUINT64_FORMAT ", offset %" G_GUINT64_FORMAT ")",
5292                 map.size, length, cur_offset));
5293         gst_buffer_unmap (moov, &map);
5294         gst_buffer_unref (moov);
5295         ret = GST_FLOW_ERROR;
5296         goto beach;
5297       }
5298       qtdemux->offset += length;
5299
5300       qtdemux_parse_moov (qtdemux, map.data, length);
5301       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
5302
5303       qtdemux_parse_tree (qtdemux);
5304       if (qtdemux->moov_node_compressed) {
5305         g_node_destroy (qtdemux->moov_node_compressed);
5306         g_free (qtdemux->moov_node->data);
5307       }
5308       qtdemux->moov_node_compressed = NULL;
5309       g_node_destroy (qtdemux->moov_node);
5310       qtdemux->moov_node = NULL;
5311       gst_buffer_unmap (moov, &map);
5312       gst_buffer_unref (moov);
5313       qtdemux->got_moov = TRUE;
5314
5315       break;
5316     }
5317     case FOURCC_ftyp:
5318     {
5319       GstBuffer *ftyp = NULL;
5320
5321       /* extract major brand; might come in handy for ISO vs QT issues */
5322       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
5323       if (ret != GST_FLOW_OK)
5324         goto beach;
5325       qtdemux->offset += length;
5326       gst_buffer_map (ftyp, &map, GST_MAP_READ);
5327       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
5328       gst_buffer_unmap (ftyp, &map);
5329       gst_buffer_unref (ftyp);
5330       break;
5331     }
5332     case FOURCC_styp:
5333     {
5334       GstBuffer *styp = NULL;
5335
5336       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &styp);
5337       if (ret != GST_FLOW_OK)
5338         goto beach;
5339       qtdemux->offset += length;
5340       gst_buffer_map (styp, &map, GST_MAP_READ);
5341       qtdemux_parse_styp (qtdemux, map.data, map.size);
5342       gst_buffer_unmap (styp, &map);
5343       gst_buffer_unref (styp);
5344       break;
5345     }
5346     case FOURCC_uuid:
5347     {
5348       GstBuffer *uuid = NULL;
5349
5350       /* uuid are extension atoms */
5351       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
5352       if (ret != GST_FLOW_OK)
5353         goto beach;
5354       qtdemux->offset += length;
5355       gst_buffer_map (uuid, &map, GST_MAP_READ);
5356       qtdemux_parse_uuid (qtdemux, map.data, map.size);
5357       gst_buffer_unmap (uuid, &map);
5358       gst_buffer_unref (uuid);
5359       break;
5360     }
5361     case FOURCC_sidx:
5362     {
5363       GstBuffer *sidx = NULL;
5364       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
5365       if (ret != GST_FLOW_OK)
5366         goto beach;
5367       qtdemux->offset += length;
5368       gst_buffer_map (sidx, &map, GST_MAP_READ);
5369       qtdemux_parse_sidx (qtdemux, map.data, map.size);
5370       gst_buffer_unmap (sidx, &map);
5371       gst_buffer_unref (sidx);
5372       break;
5373     }
5374     case FOURCC_meta:
5375     {
5376       GstBuffer *meta = NULL;
5377       GNode *node, *child;
5378       GstByteReader child_data;
5379       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &meta);
5380       if (ret != GST_FLOW_OK)
5381         goto beach;
5382       qtdemux->offset += length;
5383       gst_buffer_map (meta, &map, GST_MAP_READ);
5384
5385       node = g_node_new (map.data);
5386
5387       qtdemux_parse_node (qtdemux, node, map.data, map.size);
5388
5389       /* Parse ONVIF Export File Format CorrectStartTime box if available */
5390       if ((child =
5391               qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
5392                   &child_data))) {
5393         qtdemux_parse_cstb (qtdemux, &child_data);
5394       }
5395
5396       g_node_destroy (node);
5397
5398       gst_buffer_unmap (meta, &map);
5399       gst_buffer_unref (meta);
5400       break;
5401     }
5402     default:
5403     {
5404       GstBuffer *unknown = NULL;
5405
5406       GST_LOG_OBJECT (qtdemux,
5407           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
5408           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
5409           cur_offset);
5410       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
5411       if (ret != GST_FLOW_OK)
5412         goto beach;
5413       gst_buffer_map (unknown, &map, GST_MAP_READ);
5414       GST_MEMDUMP ("Unknown tag", map.data, map.size);
5415       gst_buffer_unmap (unknown, &map);
5416       gst_buffer_unref (unknown);
5417       qtdemux->offset += length;
5418       break;
5419     }
5420   }
5421
5422 beach:
5423   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
5424     /* digested all data, show what we have */
5425 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
5426     if (qtdemux->spherical_metadata)
5427       _send_spherical_metadata_msg_to_bus (qtdemux);
5428 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
5429     qtdemux_prepare_streams (qtdemux);
5430     QTDEMUX_EXPOSE_LOCK (qtdemux);
5431     ret = qtdemux_expose_streams (qtdemux);
5432     QTDEMUX_EXPOSE_UNLOCK (qtdemux);
5433
5434     qtdemux->state = QTDEMUX_STATE_MOVIE;
5435     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
5436         qtdemux->state);
5437     return ret;
5438   }
5439   return ret;
5440 }
5441
5442 /* Seeks to the previous keyframe of the indexed stream and
5443  * aligns other streams with respect to the keyframe timestamp
5444  * of indexed stream. Only called in case of Reverse Playback
5445  */
5446 static GstFlowReturn
5447 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
5448 {
5449   guint32 seg_idx = 0, k_index = 0;
5450   guint32 ref_seg_idx, ref_k_index;
5451   GstClockTime k_pos = 0, last_stop = 0;
5452   QtDemuxSegment *seg = NULL;
5453   QtDemuxStream *ref_str = NULL;
5454   guint64 seg_media_start_mov;  /* segment media start time in mov format */
5455   guint64 target_ts;
5456   gint i;
5457
5458   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
5459    * and finally align all the other streams on that timestamp with their
5460    * respective keyframes */
5461   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
5462     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
5463
5464     /* No candidate yet, take the first stream */
5465     if (!ref_str) {
5466       ref_str = str;
5467       continue;
5468     }
5469
5470     /* So that stream has a segment, we prefer video streams */
5471     if (str->subtype == FOURCC_vide) {
5472       ref_str = str;
5473       break;
5474     }
5475   }
5476
5477   if (G_UNLIKELY (!ref_str)) {
5478     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
5479     goto eos;
5480   }
5481
5482   if (G_UNLIKELY (!ref_str->from_sample)) {
5483     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
5484     goto eos;
5485   }
5486
5487   /* So that stream has been playing from from_sample to to_sample. We will
5488    * get the timestamp of the previous sample and search for a keyframe before
5489    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
5490   if (ref_str->subtype == FOURCC_vide) {
5491     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
5492         ref_str->from_sample - 1, FALSE);
5493   } else {
5494     if (ref_str->from_sample >= 10)
5495       k_index = ref_str->from_sample - 10;
5496     else
5497       k_index = 0;
5498   }
5499
5500   target_ts =
5501       ref_str->samples[k_index].timestamp +
5502       ref_str->samples[k_index].pts_offset;
5503
5504   /* get current segment for that stream */
5505   seg = &ref_str->segments[ref_str->segment_index];
5506   /* Use segment start in original timescale for comparisons */
5507   seg_media_start_mov = seg->trak_media_start;
5508
5509   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
5510       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
5511       k_index, target_ts, seg_media_start_mov,
5512       GST_TIME_ARGS (seg->media_start));
5513
5514   /* Crawl back through segments to find the one containing this I frame */
5515   while (target_ts < seg_media_start_mov) {
5516     GST_DEBUG_OBJECT (qtdemux,
5517         "keyframe position (sample %u) is out of segment %u " " target %"
5518         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
5519         ref_str->segment_index, target_ts, seg_media_start_mov);
5520
5521     if (G_UNLIKELY (!ref_str->segment_index)) {
5522       /* Reached first segment, let's consider it's EOS */
5523       goto eos;
5524     }
5525     ref_str->segment_index--;
5526     seg = &ref_str->segments[ref_str->segment_index];
5527     /* Use segment start in original timescale for comparisons */
5528     seg_media_start_mov = seg->trak_media_start;
5529   }
5530   /* Calculate time position of the keyframe and where we should stop */
5531   k_pos =
5532       QTSTREAMTIME_TO_GSTTIME (ref_str,
5533       target_ts - seg->trak_media_start) + seg->time;
5534   last_stop =
5535       QTSTREAMTIME_TO_GSTTIME (ref_str,
5536       ref_str->samples[ref_str->from_sample].timestamp -
5537       seg->trak_media_start) + seg->time;
5538
5539   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
5540       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
5541       k_index, GST_TIME_ARGS (k_pos));
5542
5543   /* Set last_stop with the keyframe timestamp we pushed of that stream */
5544   qtdemux->segment.position = last_stop;
5545   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
5546       GST_TIME_ARGS (last_stop));
5547
5548   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
5549     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
5550     goto eos;
5551   }
5552
5553   ref_seg_idx = ref_str->segment_index;
5554   ref_k_index = k_index;
5555
5556   /* Align them all on this */
5557   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
5558     guint32 index = 0;
5559     GstClockTime seg_time = 0;
5560     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
5561
5562     /* aligning reference stream again might lead to backing up to yet another
5563      * keyframe (due to timestamp rounding issues),
5564      * potentially putting more load on downstream; so let's try to avoid */
5565     if (str == ref_str) {
5566       seg_idx = ref_seg_idx;
5567       seg = &str->segments[seg_idx];
5568       k_index = ref_k_index;
5569       GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
5570           "sample at index %d", str->track_id, ref_str->segment_index, k_index);
5571     } else {
5572       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
5573       GST_DEBUG_OBJECT (qtdemux,
5574           "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
5575           str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
5576
5577       /* get segment and time in the segment */
5578       seg = &str->segments[seg_idx];
5579       seg_time = k_pos - seg->time;
5580
5581       /* get the media time in the segment.
5582        * No adjustment for empty "filler" segments */
5583       if (seg->media_start != GST_CLOCK_TIME_NONE)
5584         seg_time += seg->media_start;
5585
5586       /* get the index of the sample with media time */
5587       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
5588       GST_DEBUG_OBJECT (qtdemux,
5589           "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
5590           GST_TIME_ARGS (seg_time), index);
5591
5592       /* find previous keyframe */
5593       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
5594     }
5595
5596     /* Remember until where we want to go */
5597     str->to_sample = str->from_sample - 1;
5598     /* Define our time position */
5599     target_ts =
5600         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
5601     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
5602     if (seg->media_start != GST_CLOCK_TIME_NONE)
5603       str->time_position -= seg->media_start;
5604
5605     /* Now seek back in time */
5606     gst_qtdemux_move_stream (qtdemux, str, k_index);
5607     GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
5608         GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
5609         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
5610   }
5611
5612   return GST_FLOW_OK;
5613
5614 eos:
5615   return GST_FLOW_EOS;
5616 }
5617
5618 /*
5619  * Gets the current qt segment start, stop and position for the
5620  * given time offset. This is used in update_segment()
5621  */
5622 static void
5623 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5624     QtDemuxStream * stream, GstClockTime offset,
5625     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5626 {
5627   GstClockTime seg_time;
5628   GstClockTime start, stop, time;
5629   QtDemuxSegment *segment;
5630
5631   segment = &stream->segments[stream->segment_index];
5632
5633   /* get time in this segment */
5634   seg_time = (offset - segment->time) * segment->rate;
5635
5636   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5637       GST_TIME_ARGS (seg_time));
5638
5639   if (G_UNLIKELY (seg_time > segment->duration)) {
5640     GST_LOG_OBJECT (stream->pad,
5641         "seg_time > segment->duration %" GST_TIME_FORMAT,
5642         GST_TIME_ARGS (segment->duration));
5643     seg_time = segment->duration;
5644   }
5645
5646   /* qtdemux->segment.stop is in outside-time-realm, whereas
5647    * segment->media_stop is in track-time-realm.
5648    *
5649    * In order to compare the two, we need to bring segment.stop
5650    * into the track-time-realm
5651    *
5652    * FIXME - does this comment still hold? Don't see any conversion here */
5653
5654   stop = qtdemux->segment.stop;
5655   if (stop == GST_CLOCK_TIME_NONE)
5656     stop = qtdemux->segment.duration;
5657   if (stop == GST_CLOCK_TIME_NONE)
5658     stop = segment->media_stop;
5659   else
5660     stop =
5661         MIN (segment->media_stop, stop - segment->time + segment->media_start);
5662
5663   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5664     start = segment->time + seg_time;
5665     time = offset;
5666     stop = start - seg_time + segment->duration;
5667   } else if (qtdemux->segment.rate >= 0) {
5668     start = MIN (segment->media_start + seg_time, stop);
5669     time = offset;
5670   } else {
5671     if (segment->media_start >= qtdemux->segment.start) {
5672       time = segment->time;
5673     } else {
5674       time = segment->time + (qtdemux->segment.start - segment->media_start);
5675     }
5676
5677     start = MAX (segment->media_start, qtdemux->segment.start);
5678     stop = MIN (segment->media_start + seg_time, stop);
5679   }
5680
5681   *_start = start;
5682   *_stop = stop;
5683   *_time = time;
5684 }
5685
5686 /*
5687  * Updates the qt segment used for the stream and pushes a new segment event
5688  * downstream on this stream's pad.
5689  */
5690 static gboolean
5691 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5692     gint seg_idx, GstClockTime offset, GstClockTime * _start,
5693     GstClockTime * _stop)
5694 {
5695   QtDemuxSegment *segment;
5696   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5697   gdouble rate;
5698   GstEvent *event;
5699
5700   /* update the current segment */
5701   stream->segment_index = seg_idx;
5702
5703   /* get the segment */
5704   segment = &stream->segments[seg_idx];
5705
5706   if (G_UNLIKELY (offset < segment->time)) {
5707     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5708         GST_TIME_ARGS (segment->time));
5709     return FALSE;
5710   }
5711
5712   /* segment lies beyond total indicated duration */
5713   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5714           segment->time > qtdemux->segment.duration)) {
5715     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5716         " < segment->time %" GST_TIME_FORMAT,
5717         GST_TIME_ARGS (qtdemux->segment.duration),
5718         GST_TIME_ARGS (segment->time));
5719     return FALSE;
5720   }
5721
5722   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5723       &start, &stop, &time);
5724
5725   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5726       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5727       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5728
5729   /* combine global rate with that of the segment */
5730   rate = segment->rate * qtdemux->segment.rate;
5731
5732   /* Copy flags from main segment */
5733   stream->segment.flags = qtdemux->segment.flags;
5734
5735   /* update the segment values used for clipping */
5736   stream->segment.offset = qtdemux->segment.offset;
5737   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5738   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5739   stream->segment.rate = rate;
5740   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5741       stream->cslg_shift);
5742   if (stop != -1)
5743     stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5744         stream->cslg_shift);
5745   else
5746     stream->segment.stop = stop;
5747   stream->segment.time = time;
5748   stream->segment.position = stream->segment.start;
5749
5750   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5751       &stream->segment);
5752
5753   /* now prepare and send the segment */
5754   if (stream->pad) {
5755     event = gst_event_new_segment (&stream->segment);
5756     if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5757       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5758     }
5759     gst_pad_push_event (stream->pad, event);
5760     /* assume we can send more data now */
5761     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5762     /* clear to send tags on this pad now */
5763     gst_qtdemux_push_tags (qtdemux, stream);
5764   }
5765
5766   if (_start)
5767     *_start = start;
5768   if (_stop)
5769     *_stop = stop;
5770
5771   return TRUE;
5772 }
5773
5774 /* activate the given segment number @seg_idx of @stream at time @offset.
5775  * @offset is an absolute global position over all the segments.
5776  *
5777  * This will push out a NEWSEGMENT event with the right values and
5778  * position the stream index to the first decodable sample before
5779  * @offset.
5780  */
5781 static gboolean
5782 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5783     guint32 seg_idx, GstClockTime offset)
5784 {
5785   QtDemuxSegment *segment;
5786   guint32 index, kf_index;
5787   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5788
5789   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5790       seg_idx, GST_TIME_ARGS (offset));
5791
5792   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5793           &start, &stop))
5794     return FALSE;
5795
5796   segment = &stream->segments[stream->segment_index];
5797
5798   /* in the fragmented case, we pick a fragment that starts before our
5799    * desired position and rely on downstream to wait for a keyframe
5800    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5801    * tfra entries tells us which trun/sample the key unit is in, but we don't
5802    * make use of this additional information at the moment) */
5803   if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5804     stream->to_sample = G_MAXUINT32;
5805     return TRUE;
5806   } else {
5807     /* well, it will be taken care of below */
5808     qtdemux->fragmented_seek_pending = FALSE;
5809     /* FIXME ideally the do_fragmented_seek can be done right here,
5810      * rather than at loop level
5811      * (which might even allow handling edit lists in a fragmented file) */
5812   }
5813
5814   /* We don't need to look for a sample in push-based */
5815   if (!qtdemux->pullbased)
5816     return TRUE;
5817
5818   /* and move to the keyframe before the indicated media time of the
5819    * segment */
5820   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5821     if (qtdemux->segment.rate >= 0) {
5822       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5823       stream->to_sample = G_MAXUINT32;
5824       GST_DEBUG_OBJECT (stream->pad,
5825           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5826           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5827           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5828     } else {
5829       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5830       stream->to_sample = index;
5831       GST_DEBUG_OBJECT (stream->pad,
5832           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5833           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5834           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5835     }
5836   } else {
5837     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5838         "this is an empty segment");
5839     return TRUE;
5840   }
5841
5842   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5843    * encountered an error and printed a message so we return appropriately */
5844   if (index == -1)
5845     return FALSE;
5846
5847   /* we're at the right spot */
5848   if (index == stream->sample_index) {
5849     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5850     return TRUE;
5851   }
5852
5853   /* find keyframe of the target index */
5854   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5855
5856   /* go back two frames to provide lead-in for non-raw audio decoders */
5857   if (stream->subtype == FOURCC_soun && !stream->need_clip) {
5858     guint32 lead_in = 2;
5859     guint32 old_index = kf_index;
5860     GstStructure *s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
5861
5862     if (gst_structure_has_name (s, "audio/mpeg")) {
5863       gint mpegversion;
5864       if (gst_structure_get_int (s, "mpegversion", &mpegversion)
5865           && mpegversion == 1) {
5866         /* mp3 could need up to 30 frames of lead-in per mpegaudioparse */
5867         lead_in = 30;
5868       }
5869     }
5870
5871     kf_index = MAX (kf_index, lead_in) - lead_in;
5872     if (qtdemux_parse_samples (qtdemux, stream, kf_index)) {
5873       GST_DEBUG_OBJECT (stream->pad,
5874           "Moving backwards %u frames to ensure sufficient sound lead-in",
5875           old_index - kf_index);
5876     } else {
5877       kf_index = old_index;
5878     }
5879   }
5880
5881   /* if we move forwards, we don't have to go back to the previous
5882    * keyframe since we already sent that. We can also just jump to
5883    * the keyframe right before the target index if there is one. */
5884   if (index > stream->sample_index) {
5885     /* moving forwards check if we move past a keyframe */
5886     if (kf_index > stream->sample_index) {
5887       GST_DEBUG_OBJECT (stream->pad,
5888           "moving forwards to keyframe at %u "
5889           "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5890           kf_index,
5891           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5892           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5893       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5894     } else {
5895       GST_DEBUG_OBJECT (stream->pad,
5896           "moving forwards, keyframe at %u "
5897           "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " ) already sent",
5898           kf_index,
5899           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5900           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5901     }
5902   } else {
5903     GST_DEBUG_OBJECT (stream->pad,
5904         "moving backwards to %sframe at %u "
5905         "(pts %" GST_TIME_FORMAT " dts %" GST_TIME_FORMAT " )",
5906         (stream->subtype == FOURCC_soun) ? "audio " : "key", kf_index,
5907         GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5908         GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5909     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5910   }
5911
5912   return TRUE;
5913 }
5914
5915 /* prepare to get the current sample of @stream, getting essential values.
5916  *
5917  * This function will also prepare and send the segment when needed.
5918  *
5919  * Return FALSE if the stream is EOS.
5920  *
5921  * PULL-BASED
5922  */
5923 static gboolean
5924 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5925     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5926     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5927     gboolean * keyframe)
5928 {
5929   QtDemuxSample *sample;
5930   GstClockTime time_position;
5931   guint32 seg_idx;
5932
5933   g_return_val_if_fail (stream != NULL, FALSE);
5934
5935   time_position = stream->time_position;
5936   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5937     goto eos;
5938
5939   seg_idx = stream->segment_index;
5940   if (G_UNLIKELY (seg_idx == -1)) {
5941     /* find segment corresponding to time_position if we are looking
5942      * for a segment. */
5943     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5944   }
5945
5946   /* different segment, activate it, sample_index will be set. */
5947   if (G_UNLIKELY (stream->segment_index != seg_idx))
5948     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5949
5950   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5951               segments[stream->segment_index]))) {
5952     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5953
5954     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5955         " prepare empty sample");
5956
5957     *empty = TRUE;
5958     *pts = *dts = time_position;
5959     *duration = seg->duration - (time_position - seg->time);
5960
5961     return TRUE;
5962   }
5963
5964   *empty = FALSE;
5965
5966   if (stream->sample_index == -1)
5967     stream->sample_index = 0;
5968
5969   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5970       stream->sample_index, stream->n_samples);
5971
5972   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5973     if (!qtdemux->fragmented)
5974       goto eos;
5975
5976     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5977     do {
5978       GstFlowReturn flow;
5979
5980       GST_OBJECT_LOCK (qtdemux);
5981       flow = qtdemux_add_fragmented_samples (qtdemux);
5982       GST_OBJECT_UNLOCK (qtdemux);
5983
5984       if (flow != GST_FLOW_OK)
5985         goto eos;
5986     }
5987     while (stream->sample_index >= stream->n_samples);
5988   }
5989
5990   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5991     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5992         stream->sample_index);
5993     return FALSE;
5994   }
5995
5996   /* now get the info for the sample we're at */
5997   sample = &stream->samples[stream->sample_index];
5998
5999   *dts = QTSAMPLE_DTS (stream, sample);
6000   *pts = QTSAMPLE_PTS (stream, sample);
6001   *offset = sample->offset;
6002   *size = sample->size;
6003   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
6004   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6005
6006   return TRUE;
6007
6008   /* special cases */
6009 eos:
6010   {
6011     stream->time_position = GST_CLOCK_TIME_NONE;
6012     return FALSE;
6013   }
6014 }
6015
6016 /* move to the next sample in @stream.
6017  *
6018  * Moves to the next segment when needed.
6019  */
6020 static void
6021 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
6022 {
6023   QtDemuxSample *sample;
6024   QtDemuxSegment *segment;
6025
6026   /* get current segment */
6027   segment = &stream->segments[stream->segment_index];
6028
6029   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
6030     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
6031     goto next_segment;
6032   }
6033
6034   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
6035     /* Mark the stream as EOS */
6036     GST_DEBUG_OBJECT (qtdemux,
6037         "reached max allowed sample %u, mark EOS", stream->to_sample);
6038     stream->time_position = GST_CLOCK_TIME_NONE;
6039     return;
6040   }
6041
6042   /* move to next sample */
6043   stream->sample_index++;
6044   stream->offset_in_sample = 0;
6045
6046   GST_TRACE_OBJECT (qtdemux, "advance to sample %u/%u", stream->sample_index,
6047       stream->n_samples);
6048
6049   /* reached the last sample, we need the next segment */
6050   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
6051     goto next_segment;
6052
6053   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
6054     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
6055         stream->sample_index);
6056     return;
6057   }
6058
6059   /* get next sample */
6060   sample = &stream->samples[stream->sample_index];
6061
6062   GST_TRACE_OBJECT (qtdemux, "sample dts %" GST_TIME_FORMAT " media_stop: %"
6063       GST_TIME_FORMAT, GST_TIME_ARGS (QTSAMPLE_DTS (stream, sample)),
6064       GST_TIME_ARGS (segment->media_stop));
6065
6066   /* see if we are past the segment */
6067   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
6068     goto next_segment;
6069
6070   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
6071     /* inside the segment, update time_position, looks very familiar to
6072      * GStreamer segments, doesn't it? */
6073     stream->time_position =
6074         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
6075   } else {
6076     /* not yet in segment, time does not yet increment. This means
6077      * that we are still prerolling keyframes to the decoder so it can
6078      * decode the first sample of the segment. */
6079     stream->time_position = segment->time;
6080   }
6081   return;
6082
6083   /* move to the next segment */
6084 next_segment:
6085   {
6086     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
6087
6088     if (stream->segment_index == stream->n_segments - 1) {
6089       /* are we at the end of the last segment, we're EOS */
6090       stream->time_position = GST_CLOCK_TIME_NONE;
6091     } else {
6092       /* else we're only at the end of the current segment */
6093       stream->time_position = segment->stop_time;
6094     }
6095     /* make sure we select a new segment */
6096
6097     /* accumulate previous segments */
6098     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
6099       stream->accumulated_base +=
6100           (stream->segment.stop -
6101           stream->segment.start) / ABS (stream->segment.rate);
6102
6103     stream->segment_index = -1;
6104   }
6105 }
6106
6107 static void
6108 gst_qtdemux_sync_streams (GstQTDemux * demux)
6109 {
6110   gint i;
6111
6112   if (QTDEMUX_N_STREAMS (demux) <= 1)
6113     return;
6114
6115   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
6116     QtDemuxStream *stream;
6117     GstClockTime end_time;
6118
6119     stream = QTDEMUX_NTH_STREAM (demux, i);
6120
6121     if (!stream->pad)
6122       continue;
6123
6124     /* TODO advance time on subtitle streams here, if any some day */
6125
6126     /* some clips/trailers may have unbalanced streams at the end,
6127      * so send EOS on shorter stream to prevent stalling others */
6128
6129     /* do not mess with EOS if SEGMENT seeking */
6130     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
6131       continue;
6132
6133     if (demux->pullbased) {
6134       /* loop mode is sample time based */
6135       if (!STREAM_IS_EOS (stream))
6136         continue;
6137     } else {
6138       /* push mode is byte position based */
6139       if (stream->n_samples &&
6140           stream->samples[stream->n_samples - 1].offset >= demux->offset)
6141         continue;
6142     }
6143
6144     if (stream->sent_eos)
6145       continue;
6146
6147     /* only act if some gap */
6148     end_time = stream->segments[stream->n_segments - 1].stop_time;
6149     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
6150         ", stream end: %" GST_TIME_FORMAT,
6151         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
6152     if (GST_CLOCK_TIME_IS_VALID (end_time)
6153         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
6154       GstEvent *event;
6155
6156       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
6157           GST_PAD_NAME (stream->pad));
6158       stream->sent_eos = TRUE;
6159       event = gst_event_new_eos ();
6160       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6161         gst_event_set_seqnum (event, demux->segment_seqnum);
6162       gst_pad_push_event (stream->pad, event);
6163     }
6164   }
6165 }
6166
6167 /* EOS and NOT_LINKED need to be combined. This means that we return:
6168  *
6169  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
6170  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
6171  */
6172 static GstFlowReturn
6173 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
6174     GstFlowReturn ret)
6175 {
6176   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
6177
6178   if (stream->pad)
6179     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
6180         ret);
6181   else
6182     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
6183
6184   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
6185   return ret;
6186 }
6187
6188 /* the input buffer metadata must be writable. Returns NULL when the buffer is
6189  * completely clipped
6190  *
6191  * Should be used only with raw buffers */
6192 static GstBuffer *
6193 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6194     GstBuffer * buf)
6195 {
6196   guint64 start, stop, cstart, cstop, diff;
6197   GstClockTime pts, duration;
6198   gsize size, osize;
6199   gint num_rate, denom_rate;
6200   gint frame_size;
6201   gboolean clip_data;
6202   guint offset;
6203
6204   osize = size = gst_buffer_get_size (buf);
6205   offset = 0;
6206
6207   /* depending on the type, setup the clip parameters */
6208   if (stream->subtype == FOURCC_soun) {
6209     frame_size = CUR_STREAM (stream)->bytes_per_frame;
6210     num_rate = GST_SECOND;
6211     denom_rate = (gint) CUR_STREAM (stream)->rate;
6212     clip_data = TRUE;
6213   } else if (stream->subtype == FOURCC_vide) {
6214     frame_size = size;
6215     num_rate = CUR_STREAM (stream)->fps_n;
6216     denom_rate = CUR_STREAM (stream)->fps_d;
6217     clip_data = FALSE;
6218   } else
6219     goto wrong_type;
6220
6221   if (frame_size <= 0)
6222     goto bad_frame_size;
6223
6224   /* we can only clip if we have a valid pts */
6225   pts = GST_BUFFER_PTS (buf);
6226   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
6227     goto no_pts;
6228
6229   duration = GST_BUFFER_DURATION (buf);
6230
6231   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
6232     duration =
6233         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
6234   }
6235
6236   start = pts;
6237   stop = start + duration;
6238
6239   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
6240               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
6241     goto clipped;
6242
6243   /* see if some clipping happened */
6244   diff = cstart - start;
6245   if (diff > 0) {
6246     pts += diff;
6247     duration -= diff;
6248
6249     if (clip_data) {
6250       /* bring clipped time to samples and to bytes */
6251       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
6252       diff *= frame_size;
6253
6254       GST_DEBUG_OBJECT (qtdemux,
6255           "clipping start to %" GST_TIME_FORMAT " %"
6256           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
6257
6258       offset = diff;
6259       size -= diff;
6260     }
6261   }
6262   diff = stop - cstop;
6263   if (diff > 0) {
6264     duration -= diff;
6265
6266     if (clip_data) {
6267       /* bring clipped time to samples and then to bytes */
6268       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
6269       diff *= frame_size;
6270       GST_DEBUG_OBJECT (qtdemux,
6271           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
6272           " bytes", GST_TIME_ARGS (cstop), diff);
6273       size -= diff;
6274     }
6275   }
6276
6277   if (offset != 0 || size != osize)
6278     gst_buffer_resize (buf, offset, size);
6279
6280   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
6281   GST_BUFFER_PTS (buf) = pts;
6282   GST_BUFFER_DURATION (buf) = duration;
6283
6284   return buf;
6285
6286   /* dropped buffer */
6287 wrong_type:
6288   {
6289     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6290     return buf;
6291   }
6292 bad_frame_size:
6293   {
6294     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
6295     return buf;
6296   }
6297 no_pts:
6298   {
6299     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
6300     return buf;
6301   }
6302 clipped:
6303   {
6304     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
6305     gst_buffer_unref (buf);
6306     return NULL;
6307   }
6308 }
6309
6310 static GstBuffer *
6311 gst_qtdemux_align_buffer (GstQTDemux * demux,
6312     GstBuffer * buffer, gsize alignment)
6313 {
6314   GstMapInfo map;
6315
6316   gst_buffer_map (buffer, &map, GST_MAP_READ);
6317
6318   if (map.size < sizeof (guintptr)) {
6319     gst_buffer_unmap (buffer, &map);
6320     return buffer;
6321   }
6322
6323   if (((guintptr) map.data) & (alignment - 1)) {
6324     GstBuffer *new_buffer;
6325     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
6326
6327     new_buffer = gst_buffer_new_allocate (NULL,
6328         gst_buffer_get_size (buffer), &params);
6329
6330     /* Copy data "by hand", so ensure alignment is kept: */
6331     gst_buffer_fill (new_buffer, 0, map.data, map.size);
6332
6333     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
6334     GST_DEBUG_OBJECT (demux,
6335         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
6336         alignment);
6337
6338     gst_buffer_unmap (buffer, &map);
6339     gst_buffer_unref (buffer);
6340
6341     return new_buffer;
6342   }
6343
6344   gst_buffer_unmap (buffer, &map);
6345   return buffer;
6346 }
6347
6348 static guint8 *
6349 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
6350     gsize * res)
6351 {
6352   guint8 *storage;
6353   gsize i;
6354
6355   /* We are converting from pairs to triplets */
6356   *res = ccpair_size / 2 * 3;
6357   storage = g_malloc (*res);
6358   for (i = 0; i * 2 < ccpair_size; i += 1) {
6359     /* FIXME: Use line offset 0 as we simply can't know here */
6360     if (field == 1)
6361       storage[i * 3] = 0x80 | 0x00;
6362     else
6363       storage[i * 3] = 0x00 | 0x00;
6364     storage[i * 3 + 1] = ccpair[i * 2];
6365     storage[i * 3 + 2] = ccpair[i * 2 + 1];
6366   }
6367
6368   return storage;
6369 }
6370
6371 static guint8 *
6372 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
6373     gsize * cclen)
6374 {
6375   guint8 *res = NULL;
6376   guint32 atom_length, fourcc;
6377   QtDemuxStreamStsdEntry *stsd_entry;
6378
6379   GST_MEMDUMP ("caption atom", data, size);
6380
6381   /* There might be multiple atoms */
6382
6383   *cclen = 0;
6384   if (size < 8)
6385     goto invalid_cdat;
6386   atom_length = QT_UINT32 (data);
6387   fourcc = QT_FOURCC (data + 4);
6388   if (G_UNLIKELY (atom_length > size || atom_length == 8))
6389     goto invalid_cdat;
6390
6391   GST_DEBUG_OBJECT (stream->pad, "here");
6392
6393   /* Check if we have something compatible */
6394   stsd_entry = CUR_STREAM (stream);
6395   switch (stsd_entry->fourcc) {
6396     case FOURCC_c608:{
6397       guint8 *cdat = NULL, *cdt2 = NULL;
6398       gsize cdat_size = 0, cdt2_size = 0;
6399       /* Should be cdat or cdt2 */
6400       if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
6401         GST_WARNING_OBJECT (stream->pad,
6402             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
6403             GST_FOURCC_ARGS (fourcc));
6404         goto invalid_cdat;
6405       }
6406
6407       /* Convert to S334-1 Annex A byte triplet */
6408       if (fourcc == FOURCC_cdat)
6409         cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
6410       else
6411         cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
6412       GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
6413           size, atom_length);
6414
6415       /* Check for another atom ? */
6416       if (size > atom_length + 8) {
6417         guint32 new_atom_length = QT_UINT32 (data + atom_length);
6418         if (size >= atom_length + new_atom_length) {
6419           fourcc = QT_FOURCC (data + atom_length + 4);
6420           if (fourcc == FOURCC_cdat) {
6421             if (cdat == NULL)
6422               cdat =
6423                   convert_to_s334_1a (data + atom_length + 8,
6424                   new_atom_length - 8, 1, &cdat_size);
6425             else
6426               GST_WARNING_OBJECT (stream->pad,
6427                   "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
6428           } else {
6429             if (cdt2 == NULL)
6430               cdt2 =
6431                   convert_to_s334_1a (data + atom_length + 8,
6432                   new_atom_length - 8, 2, &cdt2_size);
6433             else
6434               GST_WARNING_OBJECT (stream->pad,
6435                   "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
6436           }
6437         }
6438       }
6439
6440       *cclen = cdat_size + cdt2_size;
6441       res = g_malloc (*cclen);
6442       if (cdat_size)
6443         memcpy (res, cdat, cdat_size);
6444       if (cdt2_size)
6445         memcpy (res + cdat_size, cdt2, cdt2_size);
6446       g_free (cdat);
6447       g_free (cdt2);
6448     }
6449       break;
6450     case FOURCC_c708:
6451       if (fourcc != FOURCC_ccdp) {
6452         GST_WARNING_OBJECT (stream->pad,
6453             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
6454             GST_FOURCC_ARGS (fourcc));
6455         goto invalid_cdat;
6456       }
6457       *cclen = atom_length - 8;
6458       res = g_memdup2 (data + 8, *cclen);
6459       break;
6460     default:
6461       /* Keep this here in case other closed caption formats are added */
6462       g_assert_not_reached ();
6463       break;
6464   }
6465
6466   GST_MEMDUMP ("Output", res, *cclen);
6467   return res;
6468
6469   /* Errors */
6470 invalid_cdat:
6471   GST_WARNING ("[cdat] atom is too small or invalid");
6472   return NULL;
6473 }
6474
6475 /* Handle Closed Caption sample buffers.
6476  * The input buffer metadata must be writable,
6477  * but time/duration etc not yet set and need not be preserved */
6478 static GstBuffer *
6479 gst_qtdemux_process_buffer_clcp (GstQTDemux * qtdemux, QtDemuxStream * stream,
6480     GstBuffer * buf)
6481 {
6482   GstBuffer *outbuf = NULL;
6483   GstMapInfo map;
6484   guint8 *cc;
6485   gsize cclen = 0;
6486
6487   gst_buffer_map (buf, &map, GST_MAP_READ);
6488
6489   /* empty buffer is sent to terminate previous subtitle */
6490   if (map.size <= 2) {
6491     gst_buffer_unmap (buf, &map);
6492     gst_buffer_unref (buf);
6493     return NULL;
6494   }
6495
6496   /* For closed caption, we need to extract the information from the
6497    * [cdat],[cdt2] or [ccdp] atom */
6498   cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
6499   gst_buffer_unmap (buf, &map);
6500   if (cc) {
6501     outbuf = _gst_buffer_new_wrapped (cc, cclen, g_free);
6502     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
6503   } else {
6504     /* Conversion failed or there's nothing */
6505   }
6506   gst_buffer_unref (buf);
6507
6508   return outbuf;
6509 }
6510
6511 /* DVD subpicture specific sample handling.
6512  * the input buffer metadata must be writable,
6513  * but time/duration etc not yet set and need not be preserved */
6514 static GstBuffer *
6515 gst_qtdemux_process_buffer_dvd (GstQTDemux * qtdemux, QtDemuxStream * stream,
6516     GstBuffer * buf)
6517 {
6518   /* send a one time dvd clut event */
6519   if (stream->pending_event && stream->pad)
6520     gst_pad_push_event (stream->pad, stream->pending_event);
6521   stream->pending_event = NULL;
6522
6523   /* empty buffer is sent to terminate previous subtitle */
6524   if (gst_buffer_get_size (buf) <= 2) {
6525     gst_buffer_unref (buf);
6526     return NULL;
6527   }
6528
6529   /* That's all the processing needed for subpictures */
6530   return buf;
6531 }
6532
6533 /* Timed text formats
6534  * the input buffer metadata must be writable,
6535  * but time/duration etc not yet set and need not be preserved */
6536 static GstBuffer *
6537 gst_qtdemux_process_buffer_text (GstQTDemux * qtdemux, QtDemuxStream * stream,
6538     GstBuffer * buf)
6539 {
6540   GstBuffer *outbuf = NULL;
6541   GstMapInfo map;
6542   guint nsize = 0;
6543   gchar *str;
6544
6545   /* not many cases for now */
6546   if (G_UNLIKELY (stream->subtype != FOURCC_text &&
6547           stream->subtype != FOURCC_sbtl)) {
6548     return buf;
6549   }
6550
6551   gst_buffer_map (buf, &map, GST_MAP_READ);
6552
6553   /* empty buffer is sent to terminate previous subtitle */
6554   if (map.size <= 2) {
6555     gst_buffer_unmap (buf, &map);
6556     gst_buffer_unref (buf);
6557     return NULL;
6558   }
6559
6560   nsize = GST_READ_UINT16_BE (map.data);
6561   nsize = MIN (nsize, map.size - 2);
6562
6563   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
6564       nsize, map.size);
6565
6566   /* takes care of UTF-8 validation or UTF-16 recognition,
6567    * no other encoding expected */
6568   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
6569   gst_buffer_unmap (buf, &map);
6570
6571   if (str) {
6572     outbuf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
6573     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
6574   } else {
6575     /* this should not really happen unless the subtitle is corrupted */
6576   }
6577   gst_buffer_unref (buf);
6578
6579   /* FIXME ? convert optional subsequent style info to markup */
6580
6581   return outbuf;
6582 }
6583
6584 /* WebVTT sample handling according to 14496-30 */
6585 static GstBuffer *
6586 gst_qtdemux_process_buffer_wvtt (GstQTDemux * qtdemux, QtDemuxStream * stream,
6587     GstBuffer * buf)
6588 {
6589   GstBuffer *outbuf = NULL;
6590   GstMapInfo map;
6591
6592   if (!gst_buffer_map (buf, &map, GST_MAP_READ)) {
6593     g_assert_not_reached ();    /* The buffer must be mappable */
6594   }
6595
6596   if (qtdemux_webvtt_is_empty (qtdemux, map.data, map.size)) {
6597     GstEvent *gap = NULL;
6598     /* Push a gap event */
6599     stream->segment.position = GST_BUFFER_PTS (buf);
6600     gap =
6601         gst_event_new_gap (stream->segment.position, GST_BUFFER_DURATION (buf));
6602     gst_pad_push_event (stream->pad, gap);
6603
6604     if (GST_BUFFER_DURATION_IS_VALID (buf))
6605       stream->segment.position += GST_BUFFER_DURATION (buf);
6606   } else {
6607     outbuf =
6608         qtdemux_webvtt_decode (qtdemux, GST_BUFFER_PTS (buf),
6609         GST_BUFFER_DURATION (buf), map.data, map.size);
6610     gst_buffer_copy_into (outbuf, buf, GST_BUFFER_COPY_METADATA, 0, -1);
6611   }
6612
6613   gst_buffer_unmap (buf, &map);
6614   gst_buffer_unref (buf);
6615
6616   return outbuf;
6617 }
6618
6619 static GstFlowReturn
6620 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6621     GstBuffer * buf)
6622 {
6623   GstFlowReturn ret = GST_FLOW_OK;
6624   GstClockTime pts, duration;
6625
6626   if (stream->need_clip)
6627     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6628
6629   if (G_UNLIKELY (buf == NULL))
6630     goto exit;
6631
6632   if (G_UNLIKELY (stream->discont)) {
6633     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6634     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6635     stream->discont = FALSE;
6636   } else {
6637     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6638   }
6639
6640   GST_LOG_OBJECT (qtdemux,
6641       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6642       ", duration %" GST_TIME_FORMAT " on pad %s",
6643       GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6644       GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6645       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6646
6647   if (stream->protected && stream->protection_scheme_type == FOURCC_aavd) {
6648     GstStructure *crypto_info;
6649     QtDemuxAavdEncryptionInfo *info =
6650         (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
6651
6652     crypto_info = gst_structure_copy (info->default_properties);
6653     if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6654       GST_ERROR_OBJECT (qtdemux, "failed to attach aavd metadata to buffer");
6655   }
6656
6657   if (stream->protected && (stream->protection_scheme_type == FOURCC_cenc
6658           || stream->protection_scheme_type == FOURCC_cbcs)) {
6659     GstStructure *crypto_info;
6660     QtDemuxCencSampleSetInfo *info =
6661         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6662     gint index;
6663     GstEvent *event;
6664
6665     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6666       GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6667           GST_PTR_FORMAT, event);
6668       gst_pad_push_event (stream->pad, event);
6669     }
6670
6671     if (info->crypto_info == NULL) {
6672       if (stream->protection_scheme_type == FOURCC_cbcs) {
6673         if (CUR_STREAM (stream)->fourcc == FOURCC_enca ||
6674             CUR_STREAM (stream)->fourcc == FOURCC_encs ||
6675             CUR_STREAM (stream)->fourcc == FOURCC_enct ||
6676             CUR_STREAM (stream)->fourcc == FOURCC_encv) {
6677           crypto_info = qtdemux_get_cenc_sample_properties (qtdemux, stream, 0);
6678           if (!crypto_info
6679               || !gst_buffer_add_protection_meta (buf, crypto_info)) {
6680             GST_ERROR_OBJECT (qtdemux,
6681                 "failed to attach cbcs metadata to buffer");
6682             qtdemux_gst_structure_free (crypto_info);
6683           } else {
6684             GST_TRACE_OBJECT (qtdemux, "added cbcs protection metadata");
6685           }
6686         } else {
6687           GST_TRACE_OBJECT (qtdemux,
6688               "cbcs stream is not encrypted yet, not adding protection metadata");
6689         }
6690       } else {
6691         GST_DEBUG_OBJECT (qtdemux,
6692             "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6693       }
6694     } else {
6695       /* The end of the crypto_info array matches our n_samples position,
6696        * so count backward from there */
6697       index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6698       if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6699         /* steal structure from array */
6700         crypto_info = g_ptr_array_index (info->crypto_info, index);
6701         g_ptr_array_index (info->crypto_info, index) = NULL;
6702         GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6703             info->crypto_info->len);
6704         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6705           GST_ERROR_OBJECT (qtdemux,
6706               "failed to attach cenc metadata to buffer");
6707       } else {
6708         GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6709             index, stream->sample_index);
6710       }
6711     }
6712   }
6713
6714   if (stream->alignment > 1)
6715     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6716
6717   pts = GST_BUFFER_PTS (buf);
6718   duration = GST_BUFFER_DURATION (buf);
6719
6720   ret = gst_pad_push (stream->pad, buf);
6721
6722   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6723     /* mark position in stream, we'll need this to know when to send GAP event */
6724     stream->segment.position = pts + duration;
6725   }
6726
6727 exit:
6728
6729   return ret;
6730 }
6731
6732 static GstFlowReturn
6733 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6734     GstBuffer * buf)
6735 {
6736   GstFlowReturn ret = GST_FLOW_OK;
6737
6738   if (stream->subtype == FOURCC_clcp
6739       && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6740     GstMapInfo map;
6741     guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6742     guint n_triplets, i;
6743     guint field1_off = 0, field2_off = 0;
6744
6745     /* We have to split CEA608 buffers so that each outgoing buffer contains
6746      * one byte pair per field according to the framerate of the video track.
6747      *
6748      * If there is only a single byte pair per field we don't have to do
6749      * anything
6750      */
6751
6752     gst_buffer_map (buf, &map, GST_MAP_READ);
6753
6754     n_triplets = map.size / 3;
6755     for (i = 0; i < n_triplets; i++) {
6756       if (map.data[3 * i] & 0x80)
6757         n_field1++;
6758       else
6759         n_field2++;
6760     }
6761
6762     g_assert (n_field1 || n_field2);
6763
6764     /* If there's more than 1 frame we have to split, otherwise we can just
6765      * pass through */
6766     if (n_field1 > 1 || n_field2 > 1) {
6767       n_output_buffers =
6768           gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6769           CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6770
6771       for (i = 0; i < n_output_buffers; i++) {
6772         GstBuffer *outbuf =
6773             gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6774         GstMapInfo outmap;
6775         guint8 *outptr;
6776
6777         gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6778         outptr = outmap.data;
6779
6780         if (n_field1) {
6781           gboolean found = FALSE;
6782
6783           while (map.data + field1_off < map.data + map.size) {
6784             if (map.data[field1_off] & 0x80) {
6785               memcpy (outptr, &map.data[field1_off], 3);
6786               field1_off += 3;
6787               found = TRUE;
6788               break;
6789             }
6790             field1_off += 3;
6791           }
6792
6793           if (!found) {
6794             const guint8 empty[] = { 0x80, 0x80, 0x80 };
6795
6796             memcpy (outptr, empty, 3);
6797           }
6798
6799           outptr += 3;
6800         }
6801
6802         if (n_field2) {
6803           gboolean found = FALSE;
6804
6805           while (map.data + field2_off < map.data + map.size) {
6806             if ((map.data[field2_off] & 0x80) == 0) {
6807               memcpy (outptr, &map.data[field2_off], 3);
6808               field2_off += 3;
6809               found = TRUE;
6810               break;
6811             }
6812             field2_off += 3;
6813           }
6814
6815           if (!found) {
6816             const guint8 empty[] = { 0x00, 0x80, 0x80 };
6817
6818             memcpy (outptr, empty, 3);
6819           }
6820
6821           outptr += 3;
6822         }
6823
6824         gst_buffer_unmap (outbuf, &outmap);
6825
6826         GST_BUFFER_PTS (outbuf) =
6827             GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6828             GST_SECOND * CUR_STREAM (stream)->fps_d,
6829             CUR_STREAM (stream)->fps_n);
6830         GST_BUFFER_DURATION (outbuf) =
6831             gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6832             CUR_STREAM (stream)->fps_n);
6833         GST_BUFFER_OFFSET (outbuf) = -1;
6834         GST_BUFFER_OFFSET_END (outbuf) = -1;
6835
6836         ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6837
6838         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6839           break;
6840       }
6841       gst_buffer_unmap (buf, &map);
6842       gst_buffer_unref (buf);
6843     } else {
6844       gst_buffer_unmap (buf, &map);
6845       ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6846     }
6847   } else {
6848     ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6849   }
6850
6851   return ret;
6852 }
6853
6854 /* Sets a buffer's attributes properly and pushes it downstream.
6855  * Also checks for additional actions and custom processing that may
6856  * need to be done first.
6857  */
6858 static GstFlowReturn
6859 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6860     QtDemuxStream * stream, GstBuffer * buf,
6861     GstClockTime dts, GstClockTime pts, GstClockTime duration,
6862     gboolean keyframe, GstClockTime position, guint64 byte_position)
6863 {
6864   GstFlowReturn ret = GST_FLOW_OK;
6865
6866   /* offset the timestamps according to the edit list */
6867
6868   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6869     gchar *url;
6870     GstMapInfo map;
6871
6872     gst_buffer_map (buf, &map, GST_MAP_READ);
6873     url = g_strndup ((gchar *) map.data, map.size);
6874     gst_buffer_unmap (buf, &map);
6875     if (url != NULL && strlen (url) != 0) {
6876       /* we have RTSP redirect now */
6877       g_free (qtdemux->redirect_location);
6878       qtdemux->redirect_location = g_strdup (url);
6879       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6880           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6881               gst_structure_new ("redirect",
6882                   "new-location", G_TYPE_STRING, url, NULL)));
6883     } else {
6884       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6885           "posting");
6886     }
6887     g_free (url);
6888   }
6889
6890   /* position reporting */
6891   if (qtdemux->segment.rate >= 0) {
6892     qtdemux->segment.position = position;
6893     gst_qtdemux_sync_streams (qtdemux);
6894   }
6895
6896   if (G_UNLIKELY (!stream->pad)) {
6897     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6898     gst_buffer_unref (buf);
6899     goto exit;
6900   }
6901
6902   /* send out pending buffers */
6903   while (stream->buffers) {
6904     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6905
6906     if (G_UNLIKELY (stream->discont)) {
6907       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6908       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6909       stream->discont = FALSE;
6910     } else {
6911       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6912     }
6913
6914     if (stream->alignment > 1)
6915       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6916     gst_pad_push (stream->pad, buffer);
6917
6918     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6919   }
6920
6921   /* we're going to modify the metadata */
6922   buf = gst_buffer_make_writable (buf);
6923
6924   if (qtdemux->start_utc_time != GST_CLOCK_TIME_NONE) {
6925     static GstStaticCaps unix_caps = GST_STATIC_CAPS ("timestamp/x-unix");
6926     GstCaps *caps = gst_static_caps_get (&unix_caps);
6927     gst_buffer_add_reference_timestamp_meta (buf, caps,
6928         pts + qtdemux->start_utc_time - stream->cslg_shift,
6929         GST_CLOCK_TIME_NONE);
6930     gst_caps_unref (caps);
6931   }
6932
6933   GST_BUFFER_DTS (buf) = dts;
6934   GST_BUFFER_PTS (buf) = pts;
6935   GST_BUFFER_DURATION (buf) = duration;
6936   GST_BUFFER_OFFSET (buf) = -1;
6937   GST_BUFFER_OFFSET_END (buf) = -1;
6938
6939   if (G_UNLIKELY (stream->process_func))
6940     buf = stream->process_func (qtdemux, stream, buf);
6941
6942   if (!buf) {
6943     goto exit;
6944   }
6945
6946   if (!keyframe) {
6947     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6948     stream->on_keyframe = FALSE;
6949   } else {
6950     stream->on_keyframe = TRUE;
6951   }
6952
6953   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6954     gst_buffer_append_memory (buf,
6955         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6956
6957   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6958     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6959   }
6960 #if 0
6961   if (G_UNLIKELY (qtdemux->element_index)) {
6962     GstClockTime stream_time;
6963
6964     stream_time =
6965         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6966         timestamp);
6967     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6968       GST_LOG_OBJECT (qtdemux,
6969           "adding association %" GST_TIME_FORMAT "-> %"
6970           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6971       gst_index_add_association (qtdemux->element_index,
6972           qtdemux->index_id,
6973           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6974           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6975           GST_FORMAT_BYTES, byte_position, NULL);
6976     }
6977   }
6978 #endif
6979
6980   ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6981
6982 exit:
6983   return ret;
6984 }
6985
6986 static const QtDemuxRandomAccessEntry *
6987 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6988     GstClockTime pos, gboolean after)
6989 {
6990   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6991   guint n_entries = stream->n_ra_entries;
6992   guint i;
6993
6994   /* we assume the table is sorted */
6995   for (i = 0; i < n_entries; ++i) {
6996     if (entries[i].ts > pos)
6997       break;
6998   }
6999
7000   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
7001    * probably okay to assume that the index lists the very first fragment */
7002   if (i == 0)
7003     return &entries[0];
7004
7005   if (after)
7006     return &entries[i];
7007   else
7008     return &entries[i - 1];
7009 }
7010
7011 static gboolean
7012 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
7013 {
7014   const QtDemuxRandomAccessEntry *best_entry = NULL;
7015   gint i;
7016
7017   GST_OBJECT_LOCK (qtdemux);
7018
7019   g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
7020
7021   /* first see if we can determine where to go to using mfra,
7022    * before we start clearing things */
7023   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
7024     const QtDemuxRandomAccessEntry *entry;
7025     QtDemuxStream *stream;
7026     gboolean is_audio_or_video;
7027
7028     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
7029
7030     if (stream->ra_entries == NULL)
7031       continue;
7032
7033     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
7034       is_audio_or_video = TRUE;
7035     else
7036       is_audio_or_video = FALSE;
7037
7038     entry =
7039         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
7040         stream->time_position, !is_audio_or_video);
7041
7042     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
7043         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
7044
7045     stream->pending_seek = entry;
7046
7047     /* decide position to jump to just based on audio/video tracks, not subs */
7048     if (!is_audio_or_video)
7049       continue;
7050
7051     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
7052       best_entry = entry;
7053   }
7054
7055   /* no luck, will handle seek otherwise */
7056   if (best_entry == NULL) {
7057     GST_OBJECT_UNLOCK (qtdemux);
7058     return FALSE;
7059   }
7060
7061   /* ok, now we can prepare for processing as of located moof */
7062   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
7063     QtDemuxStream *stream;
7064
7065     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
7066
7067     g_free (stream->samples);
7068     stream->samples = NULL;
7069     stream->n_samples = 0;
7070     stream->stbl_index = -1;    /* no samples have yet been parsed */
7071     stream->sample_index = -1;
7072
7073     if (stream->protection_scheme_info) {
7074       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
7075       if (stream->protection_scheme_type == FOURCC_cenc
7076           || stream->protection_scheme_type == FOURCC_cbcs) {
7077         QtDemuxCencSampleSetInfo *info =
7078             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
7079         if (info->crypto_info) {
7080           g_ptr_array_free (info->crypto_info, TRUE);
7081           info->crypto_info = NULL;
7082         }
7083       }
7084     }
7085   }
7086
7087   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
7088       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
7089       GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
7090       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
7091
7092   qtdemux->moof_offset = best_entry->moof_offset;
7093
7094   qtdemux_add_fragmented_samples (qtdemux);
7095
7096   GST_OBJECT_UNLOCK (qtdemux);
7097   return TRUE;
7098 }
7099
7100 static GstFlowReturn
7101 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
7102 {
7103   GstFlowReturn ret = GST_FLOW_OK;
7104   GstBuffer *buf = NULL;
7105   QtDemuxStream *stream, *target_stream = NULL;
7106   GstClockTime min_time;
7107   guint64 offset = 0;
7108   GstClockTime dts = GST_CLOCK_TIME_NONE;
7109   GstClockTime pts = GST_CLOCK_TIME_NONE;
7110   GstClockTime duration = 0;
7111   gboolean keyframe = FALSE;
7112   guint sample_size = 0;
7113   guint num_samples = 1;
7114   gboolean empty = 0;
7115   guint size;
7116   gint i;
7117
7118   if (qtdemux->fragmented_seek_pending) {
7119     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
7120     if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
7121       GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
7122       qtdemux->fragmented_seek_pending = FALSE;
7123     } else {
7124       GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
7125     }
7126   }
7127
7128   /* Figure out the next stream sample to output, min_time is expressed in
7129    * global time and runs over the edit list segments. */
7130   min_time = G_MAXUINT64;
7131   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
7132     GstClockTime position;
7133
7134     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
7135     position = stream->time_position;
7136
7137     /* position of -1 is EOS */
7138     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
7139       min_time = position;
7140       target_stream = stream;
7141     }
7142   }
7143   /* all are EOS */
7144   if (G_UNLIKELY (target_stream == NULL)) {
7145     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
7146     goto eos;
7147   }
7148
7149   /* check for segment end */
7150   if (G_UNLIKELY (qtdemux->segment.stop != -1
7151           && qtdemux->segment.rate >= 0
7152           && qtdemux->segment.stop <= min_time && target_stream->on_keyframe)) {
7153     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
7154     target_stream->time_position = GST_CLOCK_TIME_NONE;
7155     goto eos_stream;
7156   }
7157
7158   /* fetch info for the current sample of this stream */
7159   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, target_stream,
7160               &empty, &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
7161     goto eos_stream;
7162
7163   /* Send catche-up GAP event for each other stream if required.
7164    * This logic will be applied only for positive rate */
7165   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux) &&
7166       qtdemux->segment.rate >= 0; i++) {
7167     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
7168
7169     if (stream == target_stream ||
7170         !GST_CLOCK_TIME_IS_VALID (stream->segment.stop) ||
7171         !GST_CLOCK_TIME_IS_VALID (stream->segment.position))
7172       continue;
7173
7174     if (stream->pad) {
7175       GstClockTime gap_threshold;
7176       /* kind of running time with offset segment.base and segment.start */
7177       GstClockTime pseudo_target_time = target_stream->segment.base;
7178       GstClockTime pseudo_cur_time = stream->segment.base;
7179
7180       /* make sure positive offset, segment.position can be smallr than
7181        * segment.start for some reasons */
7182       if (target_stream->segment.position >= target_stream->segment.start) {
7183         pseudo_target_time +=
7184             (target_stream->segment.position - target_stream->segment.start);
7185       }
7186
7187       if (stream->segment.position >= stream->segment.start)
7188         pseudo_cur_time += (stream->segment.position - stream->segment.start);
7189
7190       /* Only send gap events on non-subtitle streams if lagging way behind. */
7191       if (stream->subtype == FOURCC_subp
7192           || stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl ||
7193           stream->subtype == FOURCC_wvtt)
7194         gap_threshold = 1 * GST_SECOND;
7195       else
7196         gap_threshold = 3 * GST_SECOND;
7197
7198       /* send gap events until the stream catches up */
7199       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
7200       while (GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
7201           pseudo_cur_time < (G_MAXUINT64 - gap_threshold) &&
7202           pseudo_cur_time + gap_threshold < pseudo_target_time) {
7203         GstEvent *gap =
7204             gst_event_new_gap (stream->segment.position, gap_threshold);
7205         GST_LOG_OBJECT (stream->pad, "Sending %" GST_PTR_FORMAT, gap);
7206
7207         gst_pad_push_event (stream->pad, gap);
7208         stream->segment.position += gap_threshold;
7209         pseudo_cur_time += gap_threshold;
7210       }
7211     }
7212   }
7213
7214   stream = target_stream;
7215
7216   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
7217   if (stream->new_caps) {
7218     gst_qtdemux_configure_stream (qtdemux, stream);
7219     qtdemux_do_allocation (stream, qtdemux);
7220   }
7221
7222   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
7223   if (G_UNLIKELY (qtdemux->segment.
7224           flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
7225     if (stream->subtype == FOURCC_vide) {
7226       if (!keyframe) {
7227         GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
7228             stream->track_id);
7229         goto next;
7230       } else if (qtdemux->trickmode_interval > 0) {
7231         GstClockTimeDiff interval;
7232
7233         if (qtdemux->segment.rate > 0)
7234           interval = stream->time_position - stream->last_keyframe_dts;
7235         else
7236           interval = stream->last_keyframe_dts - stream->time_position;
7237
7238         if (GST_CLOCK_TIME_IS_VALID (stream->last_keyframe_dts)
7239             && interval < qtdemux->trickmode_interval) {
7240           GST_LOG_OBJECT (qtdemux,
7241               "Skipping keyframe within interval on track-id %u",
7242               stream->track_id);
7243           goto next;
7244         } else {
7245           stream->last_keyframe_dts = stream->time_position;
7246         }
7247       }
7248     }
7249   }
7250
7251   GST_DEBUG_OBJECT (qtdemux,
7252       "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
7253       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
7254       ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
7255       sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
7256       GST_TIME_ARGS (duration));
7257
7258   if (G_UNLIKELY (empty)) {
7259     /* empty segment, push a gap if there's a second or more
7260      * difference and move to the next one */
7261     if ((pts + duration - stream->segment.position) >= GST_SECOND)
7262       gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
7263     stream->segment.position = pts + duration;
7264     goto next;
7265   }
7266
7267   /* hmm, empty sample, skip and move to next sample */
7268   if (G_UNLIKELY (sample_size <= 0))
7269     goto next;
7270
7271   /* last pushed sample was out of boundary, goto next sample */
7272   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
7273     goto next;
7274
7275   if (stream->max_buffer_size != 0 && sample_size > stream->max_buffer_size) {
7276     GST_DEBUG_OBJECT (qtdemux,
7277         "size %d larger than stream max_buffer_size %d, trimming",
7278         sample_size, stream->max_buffer_size);
7279     size =
7280         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
7281   } else if (stream->min_buffer_size != 0 && stream->offset_in_sample == 0
7282       && sample_size < stream->min_buffer_size) {
7283     guint start_sample_index = stream->sample_index;
7284     guint accumulated_size = sample_size;
7285     guint64 expected_next_offset = offset + sample_size;
7286
7287     GST_DEBUG_OBJECT (qtdemux,
7288         "size %d smaller than stream min_buffer_size %d, combining with the next",
7289         sample_size, stream->min_buffer_size);
7290
7291     while (stream->sample_index < stream->to_sample
7292         && stream->sample_index + 1 < stream->n_samples) {
7293       const QtDemuxSample *next_sample;
7294
7295       /* Increment temporarily */
7296       stream->sample_index++;
7297
7298       /* Failed to parse sample so let's go back to the previous one that was
7299        * still successful */
7300       if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
7301         stream->sample_index--;
7302         break;
7303       }
7304
7305       next_sample = &stream->samples[stream->sample_index];
7306
7307       /* Not contiguous with the previous sample so let's go back to the
7308        * previous one that was still successful */
7309       if (next_sample->offset != expected_next_offset) {
7310         stream->sample_index--;
7311         break;
7312       }
7313
7314       accumulated_size += next_sample->size;
7315       expected_next_offset += next_sample->size;
7316       if (accumulated_size >= stream->min_buffer_size)
7317         break;
7318     }
7319
7320     num_samples = stream->sample_index + 1 - start_sample_index;
7321     stream->sample_index = start_sample_index;
7322     GST_DEBUG_OBJECT (qtdemux, "Pulling %u samples of size %u at once",
7323         num_samples, accumulated_size);
7324     size = accumulated_size;
7325   } else {
7326     size = sample_size;
7327   }
7328
7329   if (qtdemux->cenc_aux_info_offset > 0) {
7330     GstMapInfo map;
7331     GstByteReader br;
7332     GstBuffer *aux_info = NULL;
7333
7334     /* pull the data stored before the sample */
7335     ret =
7336         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
7337         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
7338     if (G_UNLIKELY (ret != GST_FLOW_OK))
7339       goto beach;
7340     gst_buffer_map (aux_info, &map, GST_MAP_READ);
7341     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
7342     gst_byte_reader_init (&br, map.data + 8, map.size);
7343     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
7344             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
7345       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
7346       gst_buffer_unmap (aux_info, &map);
7347       gst_buffer_unref (aux_info);
7348       ret = GST_FLOW_ERROR;
7349       goto beach;
7350     }
7351     gst_buffer_unmap (aux_info, &map);
7352     gst_buffer_unref (aux_info);
7353   }
7354
7355   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
7356       offset);
7357
7358   if (stream->use_allocator) {
7359     /* if we have a per-stream allocator, use it */
7360     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
7361   }
7362
7363   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
7364       size, &buf);
7365   if (G_UNLIKELY (ret != GST_FLOW_OK))
7366     goto beach;
7367
7368   /* Update for both splitting and combining of samples */
7369   if (size != sample_size) {
7370     pts += gst_util_uint64_scale_int (GST_SECOND,
7371         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
7372         stream->timescale);
7373     dts +=
7374         gst_util_uint64_scale_int (GST_SECOND,
7375         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
7376         stream->timescale);
7377     duration =
7378         gst_util_uint64_scale_int (GST_SECOND,
7379         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
7380   }
7381
7382   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
7383       dts, pts, duration, keyframe, min_time, offset);
7384
7385   if (size < sample_size) {
7386     QtDemuxSample *sample = &stream->samples[stream->sample_index];
7387     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
7388
7389     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
7390         sample->timestamp +
7391         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
7392     if (time_position >= segment->media_start) {
7393       /* inside the segment, update time_position, looks very familiar to
7394        * GStreamer segments, doesn't it? */
7395       stream->time_position = (time_position - segment->media_start) +
7396           segment->time;
7397     } else {
7398       /* not yet in segment, time does not yet increment. This means
7399        * that we are still prerolling keyframes to the decoder so it can
7400        * decode the first sample of the segment. */
7401       stream->time_position = segment->time;
7402     }
7403   } else if (size > sample_size) {
7404     /* Increase to the last sample we already pulled so that advancing
7405      * below brings us to the next sample we need to pull */
7406     stream->sample_index += num_samples - 1;
7407   }
7408
7409   /* combine flows */
7410   GST_OBJECT_LOCK (qtdemux);
7411   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
7412   GST_OBJECT_UNLOCK (qtdemux);
7413   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
7414    * we have no more data for the pad to push */
7415   if (ret == GST_FLOW_EOS)
7416     ret = GST_FLOW_OK;
7417
7418   stream->offset_in_sample += size;
7419   if (stream->offset_in_sample >= sample_size) {
7420     gst_qtdemux_advance_sample (qtdemux, stream);
7421   }
7422   goto beach;
7423
7424 next:
7425   gst_qtdemux_advance_sample (qtdemux, stream);
7426
7427 beach:
7428   return ret;
7429
7430   /* special cases */
7431 eos:
7432   {
7433     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
7434     ret = GST_FLOW_EOS;
7435     goto beach;
7436   }
7437 eos_stream:
7438   {
7439     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
7440     /* EOS will be raised if all are EOS */
7441     ret = GST_FLOW_OK;
7442     goto beach;
7443   }
7444 }
7445
7446 static void
7447 gst_qtdemux_loop (GstPad * pad)
7448 {
7449   GstQTDemux *qtdemux;
7450   guint64 cur_offset;
7451   GstFlowReturn ret;
7452
7453   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
7454
7455   cur_offset = qtdemux->offset;
7456   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
7457       cur_offset, qt_demux_state_string (qtdemux->state));
7458
7459   switch (qtdemux->state) {
7460     case QTDEMUX_STATE_INITIAL:
7461     case QTDEMUX_STATE_HEADER:
7462       ret = gst_qtdemux_loop_state_header (qtdemux);
7463       break;
7464     case QTDEMUX_STATE_MOVIE:
7465       ret = gst_qtdemux_loop_state_movie (qtdemux);
7466       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
7467         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
7468       }
7469       break;
7470     default:
7471       /* ouch */
7472       goto invalid_state;
7473   }
7474
7475   /* if something went wrong, pause */
7476   if (ret != GST_FLOW_OK)
7477     goto pause;
7478
7479 done:
7480   gst_object_unref (qtdemux);
7481   return;
7482
7483   /* ERRORS */
7484 invalid_state:
7485   {
7486     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
7487         (NULL), ("streaming stopped, invalid state"));
7488     gst_pad_pause_task (pad);
7489     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
7490     goto done;
7491   }
7492 pause:
7493   {
7494     const gchar *reason = gst_flow_get_name (ret);
7495
7496     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
7497
7498     gst_pad_pause_task (pad);
7499
7500     /* fatal errors need special actions */
7501     /* check EOS */
7502     if (ret == GST_FLOW_EOS) {
7503       if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
7504         /* we have no streams, post an error */
7505         gst_qtdemux_post_no_playable_stream_error (qtdemux);
7506       }
7507       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
7508         gint64 stop;
7509
7510         if ((stop = qtdemux->segment.stop) == -1)
7511           stop = qtdemux->segment.duration;
7512
7513         if (qtdemux->segment.rate >= 0) {
7514           GstMessage *message;
7515           GstEvent *event;
7516
7517           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
7518           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
7519               GST_FORMAT_TIME, stop);
7520           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
7521           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
7522             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
7523             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7524           }
7525           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
7526           gst_qtdemux_push_event (qtdemux, event);
7527         } else {
7528           GstMessage *message;
7529           GstEvent *event;
7530
7531           /*  For Reverse Playback */
7532           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
7533           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
7534               GST_FORMAT_TIME, qtdemux->segment.start);
7535           event = gst_event_new_segment_done (GST_FORMAT_TIME,
7536               qtdemux->segment.start);
7537           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
7538             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
7539             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7540           }
7541           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
7542           gst_qtdemux_push_event (qtdemux, event);
7543         }
7544       } else {
7545         GstEvent *event;
7546
7547         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
7548         event = gst_event_new_eos ();
7549         if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
7550           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7551         gst_qtdemux_push_event (qtdemux, event);
7552       }
7553     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
7554       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
7555       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
7556     }
7557     goto done;
7558   }
7559 }
7560
7561 /*
7562  * has_next_entry
7563  *
7564  * Returns if there are samples to be played.
7565  */
7566 static gboolean
7567 has_next_entry (GstQTDemux * demux)
7568 {
7569   QtDemuxStream *stream;
7570   gint i;
7571
7572   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
7573
7574   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7575     stream = QTDEMUX_NTH_STREAM (demux, i);
7576
7577     if (stream->sample_index == -1) {
7578       stream->sample_index = 0;
7579       stream->offset_in_sample = 0;
7580     }
7581
7582     if (stream->sample_index >= stream->n_samples) {
7583       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7584       continue;
7585     }
7586     GST_DEBUG_OBJECT (demux, "Found a sample");
7587     return TRUE;
7588   }
7589
7590   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
7591   return FALSE;
7592 }
7593
7594 /*
7595  * next_entry_size
7596  *
7597  * Returns the size of the first entry at the current offset.
7598  * If -1, there are none (which means EOS or empty file).
7599  */
7600 static guint64
7601 next_entry_size (GstQTDemux * demux)
7602 {
7603   QtDemuxStream *stream, *target_stream = NULL;
7604   guint64 smalloffs = (guint64) - 1;
7605   QtDemuxSample *sample;
7606   gint i;
7607
7608   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
7609       demux->offset);
7610
7611   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7612     stream = QTDEMUX_NTH_STREAM (demux, i);
7613
7614     if (stream->sample_index == -1) {
7615       stream->sample_index = 0;
7616       stream->offset_in_sample = 0;
7617     }
7618
7619     if (stream->sample_index >= stream->n_samples) {
7620       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7621       continue;
7622     }
7623
7624     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7625       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7626           stream->sample_index);
7627       return -1;
7628     }
7629
7630     sample = &stream->samples[stream->sample_index];
7631
7632     GST_LOG_OBJECT (demux,
7633         "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7634         " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7635         stream->sample_index, sample->offset, sample->size);
7636
7637     if (((smalloffs == -1)
7638             || (sample->offset < smalloffs)) && (sample->size)) {
7639       smalloffs = sample->offset;
7640       target_stream = stream;
7641     }
7642   }
7643
7644   if (!target_stream)
7645     return -1;
7646
7647   GST_LOG_OBJECT (demux,
7648       "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7649       G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7650
7651   stream = target_stream;
7652   sample = &stream->samples[stream->sample_index];
7653
7654   if (sample->offset >= demux->offset) {
7655     demux->todrop = sample->offset - demux->offset;
7656     return sample->size + demux->todrop;
7657   }
7658
7659   GST_DEBUG_OBJECT (demux,
7660       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7661   return -1;
7662 }
7663
7664 static void
7665 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7666 {
7667   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7668
7669   gst_element_post_message (GST_ELEMENT_CAST (demux),
7670       gst_message_new_element (GST_OBJECT_CAST (demux),
7671           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7672 }
7673
7674 static gboolean
7675 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7676 {
7677   GstEvent *event;
7678   gboolean res = 0;
7679
7680   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7681
7682   event =
7683       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7684       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7685       GST_SEEK_TYPE_NONE, -1);
7686
7687   /* store seqnum to drop flush events, they don't need to reach downstream */
7688   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7689   res = gst_pad_push_event (demux->sinkpad, event);
7690   demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7691
7692   return res;
7693 }
7694
7695 /* check for seekable upstream, above and beyond a mere query */
7696 static void
7697 gst_qtdemux_check_seekability (GstQTDemux * demux)
7698 {
7699   GstQuery *query;
7700   gboolean seekable = FALSE;
7701   gint64 start = -1, stop = -1;
7702
7703   if (demux->upstream_size)
7704     return;
7705
7706   if (demux->upstream_format_is_time)
7707     return;
7708
7709   query = gst_query_new_seeking (GST_FORMAT_BYTES);
7710   if (!gst_pad_peer_query (demux->sinkpad, query)) {
7711     GST_DEBUG_OBJECT (demux, "seeking query failed");
7712     goto done;
7713   }
7714
7715   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7716
7717   /* try harder to query upstream size if we didn't get it the first time */
7718   if (seekable && stop == -1) {
7719     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7720     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7721   }
7722
7723   /* if upstream doesn't know the size, it's likely that it's not seekable in
7724    * practice even if it technically may be seekable */
7725   if (seekable && (start != 0 || stop <= start)) {
7726     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7727     seekable = FALSE;
7728   }
7729
7730 done:
7731   gst_query_unref (query);
7732
7733   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7734       G_GUINT64_FORMAT ")", seekable, start, stop);
7735   demux->upstream_seekable = seekable;
7736   demux->upstream_size = seekable ? stop : -1;
7737 }
7738
7739 static void
7740 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7741 {
7742   g_return_if_fail (bytes <= demux->todrop);
7743
7744   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7745   gst_adapter_flush (demux->adapter, bytes);
7746   demux->neededbytes -= bytes;
7747   demux->offset += bytes;
7748   demux->todrop -= bytes;
7749 }
7750
7751 /* PUSH-MODE only: Send a segment, if not done already. */
7752 static void
7753 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7754 {
7755   if (G_UNLIKELY (demux->need_segment)) {
7756     gint i;
7757
7758     if (!demux->upstream_format_is_time) {
7759       gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7760     } else {
7761       GstEvent *segment_event;
7762       segment_event = gst_event_new_segment (&demux->segment);
7763       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7764         gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7765       gst_qtdemux_push_event (demux, segment_event);
7766     }
7767
7768     demux->need_segment = FALSE;
7769
7770     /* clear to send tags on all streams */
7771     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7772       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7773       gst_qtdemux_push_tags (demux, stream);
7774       if (CUR_STREAM (stream)->sparse) {
7775         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7776         gst_pad_push_event (stream->pad,
7777             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7778       }
7779     }
7780   }
7781 }
7782
7783 /* Used for push mode only. */
7784 static void
7785 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7786     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7787 {
7788   GstClockTime ts, dur;
7789
7790   ts = pos;
7791   dur =
7792       stream->segments[segment_index].duration - (pos -
7793       stream->segments[segment_index].time);
7794   stream->time_position += dur;
7795
7796   /* Only gaps with a duration of at least one second are propagated.
7797    * Same workaround as in pull mode.
7798    * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7799   if (dur >= GST_SECOND) {
7800     GstEvent *gap;
7801     gap = gst_event_new_gap (ts, dur);
7802
7803     GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7804         "segment: %" GST_PTR_FORMAT, gap);
7805     gst_pad_push_event (stream->pad, gap);
7806   }
7807 }
7808
7809 static GstFlowReturn
7810 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7811 {
7812   GstQTDemux *demux;
7813
7814   demux = GST_QTDEMUX (parent);
7815
7816   GST_DEBUG_OBJECT (demux,
7817       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7818       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7819       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7820       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7821       gst_buffer_get_size (inbuf), demux->offset);
7822
7823   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7824     gboolean is_gap_input = FALSE;
7825     gint i;
7826
7827     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7828
7829     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7830       QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7831     }
7832
7833     /* Check if we can land back on our feet in the case where upstream is
7834      * handling the seeking/pushing of samples with gaps in between (like
7835      * in the case of trick-mode DASH for example) */
7836     if (demux->upstream_format_is_time
7837         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7838       for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7839         guint32 res;
7840         QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7841         GST_LOG_OBJECT (demux,
7842             "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7843             " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7844         res =
7845             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7846             stream, GST_BUFFER_OFFSET (inbuf));
7847         if (res != -1) {
7848           QtDemuxSample *sample = &stream->samples[res];
7849           GST_LOG_OBJECT (demux,
7850               "Checking if sample %d from track-id %u is valid (offset:%"
7851               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7852               stream->track_id, sample->offset, sample->size);
7853           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7854             GST_LOG_OBJECT (demux,
7855                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7856                 res);
7857             is_gap_input = TRUE;
7858             /* We can go back to standard playback mode */
7859             demux->state = QTDEMUX_STATE_MOVIE;
7860             /* Remember which sample this stream is at */
7861             stream->sample_index = res;
7862             /* Finally update all push-based values to the expected values */
7863             demux->neededbytes = stream->samples[res].size;
7864             demux->offset = GST_BUFFER_OFFSET (inbuf);
7865             demux->mdatleft =
7866                 demux->mdatsize - demux->offset + demux->mdatoffset;
7867             demux->todrop = 0;
7868           }
7869         }
7870       }
7871       if (!is_gap_input) {
7872         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7873         /* Reset state if it's a real discont */
7874         demux->neededbytes = 16;
7875         demux->state = QTDEMUX_STATE_INITIAL;
7876         demux->offset = GST_BUFFER_OFFSET (inbuf);
7877         gst_adapter_clear (demux->adapter);
7878       }
7879     }
7880     /* Reverse fragmented playback, need to flush all we have before
7881      * consuming a new fragment.
7882      * The samples array have the timestamps calculated by accumulating the
7883      * durations but this won't work for reverse playback of fragments as
7884      * the timestamps of a subsequent fragment should be smaller than the
7885      * previously received one. */
7886     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7887       gst_qtdemux_process_adapter (demux, TRUE);
7888       g_ptr_array_foreach (demux->active_streams,
7889           (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7890     }
7891   }
7892
7893   gst_adapter_push (demux->adapter, inbuf);
7894
7895   GST_DEBUG_OBJECT (demux,
7896       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7897       demux->neededbytes, gst_adapter_available (demux->adapter));
7898
7899   return gst_qtdemux_process_adapter (demux, FALSE);
7900 }
7901
7902 static guint64
7903 gst_segment_to_stream_time_clamped (const GstSegment * segment,
7904     guint64 position)
7905 {
7906   guint64 segment_stream_time_start;
7907   guint64 segment_stream_time_stop = GST_CLOCK_TIME_NONE;
7908   guint64 stream_pts_unsigned;
7909   int ret;
7910
7911   g_return_val_if_fail (segment != NULL, GST_CLOCK_TIME_NONE);
7912   g_return_val_if_fail (segment->format == GST_FORMAT_TIME,
7913       GST_CLOCK_TIME_NONE);
7914
7915   segment_stream_time_start = segment->time;
7916   if (segment->stop != GST_CLOCK_TIME_NONE)
7917     segment_stream_time_stop =
7918         gst_segment_to_stream_time (segment, GST_FORMAT_TIME, segment->stop);
7919
7920   ret =
7921       gst_segment_to_stream_time_full (segment, GST_FORMAT_TIME, position,
7922       &stream_pts_unsigned);
7923   /* ret == 0 if the segment is invalid (either position, segment->time or the segment start are -1). */
7924   g_return_val_if_fail (ret != 0, GST_CLOCK_TIME_NONE);
7925
7926   if (ret == -1 || stream_pts_unsigned < segment_stream_time_start) {
7927     /* Negative or prior to segment start stream time, clamp to segment start. */
7928     return segment_stream_time_start;
7929   } else if (segment_stream_time_stop != GST_CLOCK_TIME_NONE
7930       && stream_pts_unsigned > segment_stream_time_stop) {
7931     /* Clamp to segment end. */
7932     return segment_stream_time_stop;
7933   } else {
7934     return stream_pts_unsigned;
7935   }
7936 }
7937
7938 static GstFlowReturn
7939 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7940 {
7941   GstFlowReturn ret = GST_FLOW_OK;
7942
7943   /* we never really mean to buffer that much */
7944   if (demux->neededbytes == -1) {
7945     goto eos;
7946   }
7947
7948   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7949       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7950
7951 #ifndef GST_DISABLE_GST_DEBUG
7952     {
7953       guint64 discont_offset, distance_from_discont;
7954
7955       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7956       distance_from_discont =
7957           gst_adapter_distance_from_discont (demux->adapter);
7958
7959       GST_DEBUG_OBJECT (demux,
7960           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7961           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7962           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7963           demux->offset, discont_offset, distance_from_discont);
7964     }
7965 #endif
7966
7967     switch (demux->state) {
7968       case QTDEMUX_STATE_INITIAL:{
7969         const guint8 *data;
7970         guint32 fourcc;
7971         guint64 size;
7972
7973         gst_qtdemux_check_seekability (demux);
7974
7975         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7976
7977         /* get fourcc/length, set neededbytes */
7978         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7979             &size, &fourcc);
7980         gst_adapter_unmap (demux->adapter);
7981         data = NULL;
7982         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7983             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7984         if (size == 0) {
7985           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7986               (_("This file is invalid and cannot be played.")),
7987               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7988                   GST_FOURCC_ARGS (fourcc)));
7989           ret = GST_FLOW_ERROR;
7990           break;
7991         }
7992         if (fourcc == FOURCC_mdat) {
7993           gint next_entry = next_entry_size (demux);
7994           if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7995                   || !demux->fragmented)) {
7996             /* we have the headers, start playback */
7997             demux->state = QTDEMUX_STATE_MOVIE;
7998             demux->neededbytes = next_entry;
7999             demux->mdatleft = size;
8000             demux->mdatsize = demux->mdatleft;
8001           } else {
8002             /* no headers yet, try to get them */
8003             guint bs;
8004             gboolean res;
8005             guint64 old, target;
8006
8007           buffer_data:
8008             old = demux->offset;
8009             target = old + size;
8010
8011             /* try to jump over the atom with a seek */
8012             /* only bother if it seems worth doing so,
8013              * and avoids possible upstream/server problems */
8014             if (demux->upstream_seekable &&
8015                 demux->upstream_size > 4 * (1 << 20)) {
8016               res = qtdemux_seek_offset (demux, target);
8017             } else {
8018               GST_DEBUG_OBJECT (demux, "skipping seek");
8019               res = FALSE;
8020             }
8021
8022             if (res) {
8023               GST_DEBUG_OBJECT (demux, "seek success");
8024               /* remember the offset fo the first mdat so we can seek back to it
8025                * after we have the headers */
8026               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
8027                 demux->first_mdat = old;
8028                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
8029                     demux->first_mdat);
8030               }
8031               /* seek worked, continue reading */
8032               demux->offset = target;
8033               demux->neededbytes = 16;
8034               demux->state = QTDEMUX_STATE_INITIAL;
8035             } else {
8036               /* seek failed, need to buffer */
8037               demux->offset = old;
8038               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
8039               /* there may be multiple mdat (or alike) buffers */
8040               /* sanity check */
8041               if (demux->mdatbuffer)
8042                 bs = gst_buffer_get_size (demux->mdatbuffer);
8043               else
8044                 bs = 0;
8045               if (size + bs > 10 * (1 << 20))
8046                 goto no_moov;
8047               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
8048               demux->neededbytes = size;
8049               if (!demux->mdatbuffer)
8050                 demux->mdatoffset = demux->offset;
8051             }
8052           }
8053         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
8054           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8055               (_("This file is invalid and cannot be played.")),
8056               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
8057                   GST_FOURCC_ARGS (fourcc), size));
8058           ret = GST_FLOW_ERROR;
8059           break;
8060         } else {
8061           /* this means we already started buffering and still no moov header,
8062            * let's continue buffering everything till we get moov */
8063           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
8064                   || fourcc == FOURCC_moof))
8065             goto buffer_data;
8066           demux->neededbytes = size;
8067           demux->state = QTDEMUX_STATE_HEADER;
8068         }
8069         break;
8070       }
8071       case QTDEMUX_STATE_HEADER:{
8072         const guint8 *data;
8073         guint32 fourcc;
8074
8075         GST_DEBUG_OBJECT (demux, "In header");
8076
8077         data = gst_adapter_map (demux->adapter, demux->neededbytes);
8078
8079         /* parse the header */
8080         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
8081             &fourcc);
8082         if (fourcc == FOURCC_moov) {
8083           /* in usual fragmented setup we could try to scan for more
8084            * and end up at the the moov (after mdat) again */
8085           if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
8086               (!demux->fragmented
8087                   || demux->last_moov_offset == demux->offset)) {
8088             GST_DEBUG_OBJECT (demux,
8089                 "Skipping moov atom as we have (this) one already");
8090           } else {
8091             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
8092
8093             if (demux->got_moov && demux->fragmented) {
8094               GST_DEBUG_OBJECT (demux,
8095                   "Got a second moov, clean up data from old one");
8096               if (demux->moov_node_compressed) {
8097                 g_node_destroy (demux->moov_node_compressed);
8098                 if (demux->moov_node)
8099                   g_free (demux->moov_node->data);
8100               }
8101               demux->moov_node_compressed = NULL;
8102               if (demux->moov_node)
8103                 g_node_destroy (demux->moov_node);
8104               demux->moov_node = NULL;
8105               demux->start_utc_time = GST_CLOCK_TIME_NONE;
8106             }
8107
8108             demux->last_moov_offset = demux->offset;
8109
8110             /* Update streams with new moov */
8111             gst_qtdemux_stream_concat (demux,
8112                 demux->old_streams, demux->active_streams);
8113
8114             qtdemux_parse_moov (demux, data, demux->neededbytes);
8115             qtdemux_node_dump (demux, demux->moov_node);
8116             qtdemux_parse_tree (demux);
8117             qtdemux_prepare_streams (demux);
8118             QTDEMUX_EXPOSE_LOCK (demux);
8119             qtdemux_expose_streams (demux);
8120             QTDEMUX_EXPOSE_UNLOCK (demux);
8121
8122             demux->got_moov = TRUE;
8123
8124             gst_qtdemux_check_send_pending_segment (demux);
8125
8126             if (demux->moov_node_compressed) {
8127               g_node_destroy (demux->moov_node_compressed);
8128               g_free (demux->moov_node->data);
8129             }
8130             demux->moov_node_compressed = NULL;
8131             g_node_destroy (demux->moov_node);
8132             demux->moov_node = NULL;
8133             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
8134           }
8135         } else if (fourcc == FOURCC_moof) {
8136           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
8137             guint64 dist = 0;
8138             GstClockTime prev_pts;
8139             guint64 prev_offset;
8140             guint64 adapter_discont_offset, adapter_discont_dist;
8141
8142             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
8143
8144             /*
8145              * The timestamp of the moof buffer is relevant as some scenarios
8146              * won't have the initial timestamp in the atoms. Whenever a new
8147              * buffer has started, we get that buffer's PTS and use it as a base
8148              * timestamp for the trun entries.
8149              *
8150              * To keep track of the current buffer timestamp and starting point
8151              * we use gst_adapter_prev_pts that gives us the PTS and the distance
8152              * from the beginning of the buffer, with the distance and demux->offset
8153              * we know if it is still the same buffer or not.
8154              */
8155             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
8156             prev_offset = demux->offset - dist;
8157             if (demux->fragment_start_offset == -1
8158                 || prev_offset > demux->fragment_start_offset) {
8159               demux->fragment_start_offset = prev_offset;
8160               demux->fragment_start = prev_pts;
8161               GST_DEBUG_OBJECT (demux,
8162                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
8163                   GST_TIME_FORMAT, demux->fragment_start_offset,
8164                   GST_TIME_ARGS (demux->fragment_start));
8165             }
8166
8167             /* We can't use prev_offset() here because this would require
8168              * upstream to set consistent and correct offsets on all buffers
8169              * since the discont. Nothing ever did that in the past and we
8170              * would break backwards compatibility here then.
8171              * Instead take the offset we had at the last discont and count
8172              * the bytes from there. This works with old code as there would
8173              * be no discont between moov and moof, and also works with
8174              * adaptivedemux which correctly sets offset and will set the
8175              * DISCONT flag accordingly when needed.
8176              *
8177              * We also only do this for upstream TIME segments as otherwise
8178              * there are potential backwards compatibility problems with
8179              * seeking in PUSH mode and upstream providing inconsistent
8180              * timestamps. */
8181             adapter_discont_offset =
8182                 gst_adapter_offset_at_discont (demux->adapter);
8183             adapter_discont_dist =
8184                 gst_adapter_distance_from_discont (demux->adapter);
8185
8186             GST_DEBUG_OBJECT (demux,
8187                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
8188                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
8189                 demux->offset, adapter_discont_offset, adapter_discont_dist);
8190
8191             if (demux->upstream_format_is_time) {
8192               demux->moof_offset = adapter_discont_offset;
8193               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
8194                 demux->moof_offset += adapter_discont_dist;
8195               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
8196                 demux->moof_offset = demux->offset;
8197             } else {
8198               demux->moof_offset = demux->offset;
8199             }
8200
8201             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
8202                     demux->moof_offset, NULL)) {
8203               gst_adapter_unmap (demux->adapter);
8204               ret = GST_FLOW_ERROR;
8205               goto done;
8206             }
8207
8208             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
8209             if (demux->variant == VARIANT_MSS_FRAGMENTED && !demux->exposed) {
8210               QTDEMUX_EXPOSE_LOCK (demux);
8211               qtdemux_expose_streams (demux);
8212               QTDEMUX_EXPOSE_UNLOCK (demux);
8213             }
8214
8215             gst_qtdemux_check_send_pending_segment (demux);
8216           } else {
8217             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
8218           }
8219         } else if (fourcc == FOURCC_ftyp) {
8220           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
8221           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
8222         } else if (fourcc == FOURCC_uuid) {
8223           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
8224           qtdemux_parse_uuid (demux, data, demux->neededbytes);
8225         } else if (fourcc == FOURCC_sidx) {
8226           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
8227           qtdemux_parse_sidx (demux, data, demux->neededbytes);
8228         } else if (fourcc == FOURCC_meta) {
8229           GNode *node, *child;
8230           GstByteReader child_data;
8231
8232           node = g_node_new ((gpointer) data);
8233           qtdemux_parse_node (demux, node, data, demux->neededbytes);
8234
8235           /* Parse ONVIF Export File Format CorrectStartTime box if available */
8236           if ((child =
8237                   qtdemux_tree_get_child_by_type_full (node, FOURCC_cstb,
8238                       &child_data))) {
8239             qtdemux_parse_cstb (demux, &child_data);
8240           }
8241
8242           g_node_destroy (node);
8243         } else {
8244           switch (fourcc) {
8245             case FOURCC_styp:
8246               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
8247                * FALLTHROUGH */
8248             case FOURCC_skip:
8249             case FOURCC_free:
8250               /* [free] and [skip] are padding atoms */
8251               GST_DEBUG_OBJECT (demux,
8252                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
8253                   GST_FOURCC_ARGS (fourcc));
8254               break;
8255             default:
8256               GST_WARNING_OBJECT (demux,
8257                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
8258                   GST_FOURCC_ARGS (fourcc));
8259               /* Let's jump that one and go back to initial state */
8260               break;
8261           }
8262         }
8263         gst_adapter_unmap (demux->adapter);
8264         data = NULL;
8265
8266         if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
8267           gsize remaining_data_size = 0;
8268
8269           /* the mdat was before the header */
8270           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
8271               QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
8272           /* restore our adapter/offset view of things with upstream;
8273            * put preceding buffered data ahead of current moov data.
8274            * This should also handle evil mdat, moov, mdat cases and alike */
8275           gst_adapter_flush (demux->adapter, demux->neededbytes);
8276
8277           /* Store any remaining data after the mdat for later usage */
8278           remaining_data_size = gst_adapter_available (demux->adapter);
8279           if (remaining_data_size > 0) {
8280             g_assert (demux->restoredata_buffer == NULL);
8281             demux->restoredata_buffer =
8282                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
8283             demux->restoredata_offset = demux->offset + demux->neededbytes;
8284             GST_DEBUG_OBJECT (demux,
8285                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
8286                 G_GUINT64_FORMAT, remaining_data_size,
8287                 demux->restoredata_offset);
8288           }
8289
8290           gst_adapter_push (demux->adapter, demux->mdatbuffer);
8291           demux->mdatbuffer = NULL;
8292           demux->offset = demux->mdatoffset;
8293           demux->neededbytes = next_entry_size (demux);
8294           demux->state = QTDEMUX_STATE_MOVIE;
8295           demux->mdatleft = gst_adapter_available (demux->adapter);
8296           demux->mdatsize = demux->mdatleft;
8297         } else {
8298           GST_DEBUG_OBJECT (demux, "Carrying on normally");
8299           gst_adapter_flush (demux->adapter, demux->neededbytes);
8300
8301           /* only go back to the mdat if there are samples to play */
8302           if (demux->got_moov && demux->first_mdat != -1
8303               && has_next_entry (demux)) {
8304             gboolean res;
8305
8306             /* we need to seek back */
8307             res = qtdemux_seek_offset (demux, demux->first_mdat);
8308             if (res) {
8309               demux->offset = demux->first_mdat;
8310             } else {
8311               GST_DEBUG_OBJECT (demux, "Seek back failed");
8312             }
8313           } else {
8314             demux->offset += demux->neededbytes;
8315           }
8316           demux->neededbytes = 16;
8317           demux->state = QTDEMUX_STATE_INITIAL;
8318         }
8319
8320         break;
8321       }
8322       case QTDEMUX_STATE_BUFFER_MDAT:{
8323         GstBuffer *buf;
8324         guint8 fourcc[4];
8325
8326         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
8327             demux->offset);
8328         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
8329         gst_buffer_extract (buf, 0, fourcc, 4);
8330         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
8331             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
8332         if (demux->mdatbuffer)
8333           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
8334         else
8335           demux->mdatbuffer = buf;
8336         demux->offset += demux->neededbytes;
8337         demux->neededbytes = 16;
8338         demux->state = QTDEMUX_STATE_INITIAL;
8339         gst_qtdemux_post_progress (demux, 1, 1);
8340
8341         break;
8342       }
8343       case QTDEMUX_STATE_MOVIE:{
8344         QtDemuxStream *stream = NULL;
8345         QtDemuxSample *sample;
8346         GstClockTime dts, pts, stream_pts, duration;
8347         gboolean keyframe;
8348         gint i;
8349
8350         GST_DEBUG_OBJECT (demux,
8351             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
8352
8353         if (demux->fragmented) {
8354           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
8355               demux->mdatleft);
8356           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
8357             /* if needed data starts within this atom,
8358              * then it should not exceed this atom */
8359             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
8360               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8361                   (_("This file is invalid and cannot be played.")),
8362                   ("sample data crosses atom boundary"));
8363               ret = GST_FLOW_ERROR;
8364               break;
8365             }
8366             demux->mdatleft -= demux->neededbytes;
8367           } else {
8368             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
8369             /* so we are dropping more than left in this atom */
8370             gst_qtdemux_drop_data (demux, demux->mdatleft);
8371             demux->mdatleft = 0;
8372
8373             /* need to resume atom parsing so we do not miss any other pieces */
8374             demux->state = QTDEMUX_STATE_INITIAL;
8375             demux->neededbytes = 16;
8376
8377             /* check if there was any stored post mdat data from previous buffers */
8378             if (demux->restoredata_buffer) {
8379               g_assert (gst_adapter_available (demux->adapter) == 0);
8380
8381               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
8382               demux->restoredata_buffer = NULL;
8383               demux->offset = demux->restoredata_offset;
8384             }
8385
8386             break;
8387           }
8388         }
8389
8390         if (demux->todrop) {
8391           if (demux->cenc_aux_info_offset > 0) {
8392             GstByteReader br;
8393             const guint8 *data;
8394
8395             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
8396             data = gst_adapter_map (demux->adapter, demux->todrop);
8397             gst_byte_reader_init (&br, data + 8, demux->todrop);
8398             if (!qtdemux_parse_cenc_aux_info (demux,
8399                     QTDEMUX_NTH_STREAM (demux, 0), &br,
8400                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
8401               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
8402               ret = GST_FLOW_ERROR;
8403               gst_adapter_unmap (demux->adapter);
8404               g_free (demux->cenc_aux_info_sizes);
8405               demux->cenc_aux_info_sizes = NULL;
8406               goto done;
8407             }
8408             demux->cenc_aux_info_offset = 0;
8409             g_free (demux->cenc_aux_info_sizes);
8410             demux->cenc_aux_info_sizes = NULL;
8411             gst_adapter_unmap (demux->adapter);
8412           }
8413           gst_qtdemux_drop_data (demux, demux->todrop);
8414         }
8415
8416         /* first buffer? */
8417         /* initial newsegment sent here after having added pads,
8418          * possible others in sink_event */
8419         gst_qtdemux_check_send_pending_segment (demux);
8420
8421         /* Figure out which stream this packet belongs to */
8422         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
8423           stream = QTDEMUX_NTH_STREAM (demux, i);
8424           if (stream->sample_index >= stream->n_samples) {
8425             /* reset to be checked below G_UNLIKELY (stream == NULL) */
8426             stream = NULL;
8427             continue;
8428           }
8429           GST_LOG_OBJECT (demux,
8430               "Checking track-id %u (sample_index:%d / offset:%"
8431               G_GUINT64_FORMAT " / size:%d)", stream->track_id,
8432               stream->sample_index,
8433               stream->samples[stream->sample_index].offset,
8434               stream->samples[stream->sample_index].size);
8435
8436           if (stream->samples[stream->sample_index].offset == demux->offset)
8437             break;
8438         }
8439
8440         if (G_UNLIKELY (stream == NULL))
8441           goto unknown_stream;
8442
8443         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
8444
8445         if (stream->new_caps) {
8446           gst_qtdemux_configure_stream (demux, stream);
8447         }
8448
8449         /* Put data in a buffer, set timestamps, caps, ... */
8450         sample = &stream->samples[stream->sample_index];
8451
8452         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
8453           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
8454               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
8455
8456           dts = QTSAMPLE_DTS (stream, sample);
8457           pts = QTSAMPLE_PTS (stream, sample);
8458           stream_pts =
8459               gst_segment_to_stream_time_clamped (&stream->segment, pts);
8460           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
8461           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
8462
8463           /* check for segment end */
8464           if (G_UNLIKELY (demux->segment.stop != -1
8465                   && demux->segment.stop <= stream_pts && keyframe)
8466               && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
8467             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
8468             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
8469
8470             /* skip this data, stream is EOS */
8471             gst_adapter_flush (demux->adapter, demux->neededbytes);
8472             demux->offset += demux->neededbytes;
8473
8474             /* check if all streams are eos */
8475             ret = GST_FLOW_EOS;
8476             for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
8477               if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
8478                 ret = GST_FLOW_OK;
8479                 break;
8480               }
8481             }
8482           } else {
8483             GstBuffer *outbuf;
8484
8485             outbuf =
8486                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
8487
8488             /* FIXME: should either be an assert or a plain check */
8489             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
8490
8491             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
8492                 dts, pts, duration, keyframe, dts, demux->offset);
8493           }
8494
8495           /* combine flows */
8496           GST_OBJECT_LOCK (demux);
8497           ret = gst_qtdemux_combine_flows (demux, stream, ret);
8498           GST_OBJECT_UNLOCK (demux);
8499         } else {
8500           /* skip this data, stream is EOS */
8501           gst_adapter_flush (demux->adapter, demux->neededbytes);
8502         }
8503
8504         stream->sample_index++;
8505         stream->offset_in_sample = 0;
8506
8507         /* update current offset and figure out size of next buffer */
8508         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
8509             demux->offset, demux->neededbytes);
8510         demux->offset += demux->neededbytes;
8511         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
8512             demux->offset);
8513
8514
8515         if (ret == GST_FLOW_EOS) {
8516           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
8517           demux->neededbytes = -1;
8518           goto eos;
8519         }
8520
8521         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
8522           if (demux->fragmented) {
8523             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
8524             /* there may be more to follow, only finish this atom */
8525             demux->todrop = demux->mdatleft;
8526             demux->neededbytes = demux->todrop;
8527             break;
8528           }
8529           goto eos;
8530         }
8531         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
8532           goto non_ok_unlinked_flow;
8533         }
8534         break;
8535       }
8536       default:
8537         goto invalid_state;
8538     }
8539   }
8540
8541   /* when buffering movie data, at least show user something is happening */
8542   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
8543       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
8544     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
8545         demux->neededbytes);
8546   }
8547 done:
8548
8549   return ret;
8550
8551   /* ERRORS */
8552 non_ok_unlinked_flow:
8553   {
8554     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
8555         gst_flow_get_name (ret));
8556     return ret;
8557   }
8558 unknown_stream:
8559   {
8560     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
8561     ret = GST_FLOW_ERROR;
8562     goto done;
8563   }
8564 eos:
8565   {
8566     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
8567     ret = GST_FLOW_EOS;
8568     goto done;
8569   }
8570 invalid_state:
8571   {
8572     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
8573         (NULL), ("qtdemuxer invalid state %d", demux->state));
8574     ret = GST_FLOW_ERROR;
8575     goto done;
8576   }
8577 no_moov:
8578   {
8579     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
8580         (NULL), ("no 'moov' atom within the first 10 MB"));
8581     ret = GST_FLOW_ERROR;
8582     goto done;
8583   }
8584 }
8585
8586 static gboolean
8587 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
8588 {
8589   GstQuery *query;
8590   gboolean pull_mode;
8591
8592   query = gst_query_new_scheduling ();
8593
8594   if (!gst_pad_peer_query (sinkpad, query)) {
8595     gst_query_unref (query);
8596     goto activate_push;
8597   }
8598
8599   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
8600       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
8601   gst_query_unref (query);
8602
8603   if (!pull_mode)
8604     goto activate_push;
8605
8606   GST_DEBUG_OBJECT (sinkpad, "activating pull");
8607   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
8608
8609 activate_push:
8610   {
8611     GST_DEBUG_OBJECT (sinkpad, "activating push");
8612     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
8613   }
8614 }
8615
8616 static gboolean
8617 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
8618     GstPadMode mode, gboolean active)
8619 {
8620   gboolean res;
8621   GstQTDemux *demux = GST_QTDEMUX (parent);
8622
8623   switch (mode) {
8624     case GST_PAD_MODE_PUSH:
8625       demux->pullbased = FALSE;
8626       res = TRUE;
8627       break;
8628     case GST_PAD_MODE_PULL:
8629       if (active) {
8630         demux->pullbased = TRUE;
8631         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
8632             sinkpad, NULL);
8633       } else {
8634         res = gst_pad_stop_task (sinkpad);
8635       }
8636       break;
8637     default:
8638       res = FALSE;
8639       break;
8640   }
8641   return res;
8642 }
8643
8644 #ifdef HAVE_ZLIB
8645 static void *
8646 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
8647 {
8648   guint8 *buffer;
8649   z_stream z;
8650   int ret;
8651
8652   memset (&z, 0, sizeof (z));
8653   z.zalloc = NULL;
8654   z.zfree = NULL;
8655   z.opaque = NULL;
8656
8657   if ((ret = inflateInit (&z)) != Z_OK) {
8658     GST_ERROR ("inflateInit() returned %d", ret);
8659     return NULL;
8660   }
8661
8662   z.next_in = z_buffer;
8663   z.avail_in = z_length;
8664
8665   buffer = (guint8 *) g_malloc (*length);
8666   z.avail_out = *length;
8667   z.next_out = (Bytef *) buffer;
8668   do {
8669     ret = inflate (&z, Z_NO_FLUSH);
8670     if (ret == Z_STREAM_END) {
8671       break;
8672     } else if (ret != Z_OK) {
8673       GST_WARNING ("inflate() returned %d", ret);
8674       break;
8675     }
8676
8677     if (*length > G_MAXUINT - 4096 || *length > QTDEMUX_MAX_SAMPLE_INDEX_SIZE) {
8678       GST_WARNING ("too big decompressed data");
8679       ret = Z_MEM_ERROR;
8680       break;
8681     }
8682
8683     *length += 4096;
8684     buffer = (guint8 *) g_realloc (buffer, *length);
8685     z.next_out = (Bytef *) (buffer + z.total_out);
8686     z.avail_out += *length - z.total_out;
8687   } while (z.avail_in > 0);
8688
8689   if (ret != Z_STREAM_END) {
8690     g_free (buffer);
8691     buffer = NULL;
8692     *length = 0;
8693   } else {
8694     *length = z.total_out;
8695   }
8696
8697   inflateEnd (&z);
8698
8699   return buffer;
8700 }
8701 #endif /* HAVE_ZLIB */
8702
8703 static gboolean
8704 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8705 {
8706   GNode *cmov;
8707
8708   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8709
8710   /* counts as header data */
8711   qtdemux->header_size += length;
8712
8713   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8714   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8715
8716   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8717   if (cmov) {
8718     guint32 method;
8719     GNode *dcom;
8720     GNode *cmvd;
8721     guint32 dcom_len;
8722
8723     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8724     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8725     if (dcom == NULL || cmvd == NULL)
8726       goto invalid_compression;
8727
8728     dcom_len = QT_UINT32 (dcom->data);
8729     if (dcom_len < 12)
8730       goto invalid_compression;
8731
8732     method = QT_FOURCC ((guint8 *) dcom->data + 8);
8733     switch (method) {
8734 #ifdef HAVE_ZLIB
8735       case FOURCC_zlib:{
8736         guint uncompressed_length;
8737         guint compressed_length;
8738         guint8 *buf;
8739         guint32 cmvd_len;
8740
8741         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8742         if (cmvd_len < 12)
8743           goto invalid_compression;
8744
8745         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8746         compressed_length = cmvd_len - 12;
8747         GST_LOG ("length = %u", uncompressed_length);
8748
8749         buf =
8750             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8751             compressed_length, &uncompressed_length);
8752
8753         if (buf) {
8754           qtdemux->moov_node_compressed = qtdemux->moov_node;
8755           qtdemux->moov_node = g_node_new (buf);
8756
8757           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8758               uncompressed_length);
8759         }
8760         break;
8761       }
8762 #endif /* HAVE_ZLIB */
8763       default:
8764         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8765             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8766         break;
8767     }
8768   }
8769   return TRUE;
8770
8771   /* ERRORS */
8772 invalid_compression:
8773   {
8774     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8775     return FALSE;
8776   }
8777 }
8778
8779 static gboolean
8780 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8781     const guint8 * end)
8782 {
8783   while (G_UNLIKELY (buf < end)) {
8784     GNode *child;
8785     guint32 len;
8786
8787     if (G_UNLIKELY (buf + 4 > end)) {
8788       GST_LOG_OBJECT (qtdemux, "buffer overrun");
8789       break;
8790     }
8791     len = QT_UINT32 (buf);
8792     if (G_UNLIKELY (len == 0)) {
8793       GST_LOG_OBJECT (qtdemux, "empty container");
8794       break;
8795     }
8796     if (G_UNLIKELY (len < 8)) {
8797       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8798       break;
8799     }
8800     if (G_UNLIKELY (len > (end - buf))) {
8801       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8802           (gint) (end - buf));
8803       break;
8804     }
8805
8806     child = g_node_new ((guint8 *) buf);
8807     g_node_append (node, child);
8808     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8809     qtdemux_parse_node (qtdemux, child, buf, len);
8810
8811     buf += len;
8812   }
8813   return TRUE;
8814 }
8815
8816 static gboolean
8817 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8818     GNode * xdxt)
8819 {
8820   int len = QT_UINT32 (xdxt->data);
8821   guint8 *buf = xdxt->data;
8822   guint8 *end = buf + len;
8823   GstBuffer *buffer;
8824
8825   /* skip size and type */
8826   buf += 8;
8827   end -= 8;
8828
8829   while (buf < end) {
8830     gint size;
8831     guint32 type;
8832
8833     size = QT_UINT32 (buf);
8834     type = QT_FOURCC (buf + 4);
8835
8836     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8837
8838     if (buf + size > end || size <= 0)
8839       break;
8840
8841     buf += 8;
8842     size -= 8;
8843
8844     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8845         GST_FOURCC_ARGS (type));
8846
8847     switch (type) {
8848       case FOURCC_tCtH:
8849         buffer = gst_buffer_new_and_alloc (size);
8850         gst_buffer_fill (buffer, 0, buf, size);
8851         stream->buffers = g_slist_append (stream->buffers, buffer);
8852         GST_LOG_OBJECT (qtdemux, "parsing theora header");
8853         break;
8854       case FOURCC_tCt_:
8855         buffer = gst_buffer_new_and_alloc (size);
8856         gst_buffer_fill (buffer, 0, buf, size);
8857         stream->buffers = g_slist_append (stream->buffers, buffer);
8858         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8859         break;
8860       case FOURCC_tCtC:
8861         buffer = gst_buffer_new_and_alloc (size);
8862         gst_buffer_fill (buffer, 0, buf, size);
8863         stream->buffers = g_slist_append (stream->buffers, buffer);
8864         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8865         break;
8866       default:
8867         GST_WARNING_OBJECT (qtdemux,
8868             "unknown theora cookie %" GST_FOURCC_FORMAT,
8869             GST_FOURCC_ARGS (type));
8870         break;
8871     }
8872     buf += size;
8873   }
8874   return TRUE;
8875 }
8876
8877 static gboolean
8878 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8879     guint length)
8880 {
8881   guint32 fourcc = 0;
8882   guint32 node_length = 0;
8883   const QtNodeType *type;
8884   const guint8 *end;
8885
8886   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8887
8888   if (G_UNLIKELY (length < 8))
8889     goto not_enough_data;
8890
8891   node_length = QT_UINT32 (buffer);
8892   fourcc = QT_FOURCC (buffer + 4);
8893
8894   /* ignore empty nodes */
8895   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8896     return TRUE;
8897
8898   type = qtdemux_type_get (fourcc);
8899
8900   end = buffer + length;
8901
8902   GST_LOG_OBJECT (qtdemux,
8903       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8904       GST_FOURCC_ARGS (fourcc), node_length, type->name);
8905
8906   if (node_length > length)
8907     goto broken_atom_size;
8908
8909   if (type->flags & QT_FLAG_CONTAINER) {
8910     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8911   } else {
8912     switch (fourcc) {
8913       case FOURCC_stsd:
8914       {
8915         if (node_length < 20) {
8916           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8917           break;
8918         }
8919         GST_DEBUG_OBJECT (qtdemux,
8920             "parsing stsd (sample table, sample description) atom");
8921         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8922         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8923         break;
8924       }
8925       case FOURCC_mp4a:
8926       case FOURCC_alac:
8927       case FOURCC_fLaC:
8928       case FOURCC_aavd:
8929       case FOURCC_opus:
8930       {
8931         guint32 version;
8932         guint32 offset;
8933         guint min_size;
8934
8935         /* also read alac (or whatever) in stead of mp4a in the following,
8936          * since a similar layout is used in other cases as well */
8937         if (fourcc == FOURCC_mp4a)
8938           min_size = 20;
8939         else if (fourcc == FOURCC_fLaC)
8940           min_size = 86;
8941         else if (fourcc == FOURCC_opus)
8942           min_size = 55;
8943         else
8944           min_size = 40;
8945
8946         /* There are two things we might encounter here: a true mp4a atom, and
8947            an mp4a entry in an stsd atom. The latter is what we're interested
8948            in, and it looks like an atom, but isn't really one. The true mp4a
8949            atom is short, so we detect it based on length here. */
8950         if (length < min_size) {
8951           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8952               GST_FOURCC_ARGS (fourcc));
8953           break;
8954         }
8955
8956         /* 'version' here is the sound sample description version. Types 0 and
8957            1 are documented in the QTFF reference, but type 2 is not: it's
8958            described in Apple header files instead (struct SoundDescriptionV2
8959            in Movies.h) */
8960         version = QT_UINT16 (buffer + 16);
8961
8962         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8963             GST_FOURCC_ARGS (fourcc), version);
8964
8965         /* parse any esds descriptors */
8966         switch (version) {
8967           case 0:
8968             offset = 0x24;
8969             break;
8970           case 1:
8971             offset = 0x34;
8972             break;
8973           case 2:
8974             offset = 0x48;
8975             break;
8976           default:
8977             GST_WARNING_OBJECT (qtdemux,
8978                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8979                 GST_FOURCC_ARGS (fourcc), version);
8980             offset = 0;
8981             break;
8982         }
8983         if (offset)
8984           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8985         break;
8986       }
8987       case FOURCC_mp4v:
8988       case FOURCC_MP4V:
8989       case FOURCC_fmp4:
8990       case FOURCC_FMP4:
8991       case FOURCC_apcs:
8992       case FOURCC_apch:
8993       case FOURCC_apcn:
8994       case FOURCC_apco:
8995       case FOURCC_ap4h:
8996       case FOURCC_xvid:
8997       case FOURCC_XVID:
8998       case FOURCC_H264:
8999       case FOURCC_avc1:
9000       case FOURCC_avc3:
9001       case FOURCC_H265:
9002       case FOURCC_hvc1:
9003       case FOURCC_hev1:
9004       case FOURCC_dvh1:
9005       case FOURCC_dvhe:
9006       case FOURCC_mjp2:
9007       case FOURCC_encv:
9008       {
9009         guint32 version;
9010         guint32 str_len;
9011
9012         /* codec_data is contained inside these atoms, which all have
9013          * the same format. */
9014         /* video sample description size is 86 bytes without extension.
9015          * node_length have to be bigger than 86 bytes because video sample
9016          * description can include extensions such as esds, fiel, glbl, etc. */
9017         if (node_length < 86) {
9018           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
9019               " sample description length too short (%u < 86)",
9020               GST_FOURCC_ARGS (fourcc), node_length);
9021           break;
9022         }
9023
9024         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
9025             GST_FOURCC_ARGS (fourcc));
9026
9027         /* version (2 bytes) : this is set to 0, unless a compressor has changed
9028          *              its data format.
9029          * revision level (2 bytes) : must be set to 0. */
9030         version = QT_UINT32 (buffer + 16);
9031         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
9032
9033         /* compressor name : PASCAL string and informative purposes
9034          * first byte : the number of bytes to be displayed.
9035          *              it has to be less than 32 because it is reserved
9036          *              space of 32 bytes total including itself. */
9037         str_len = QT_UINT8 (buffer + 50);
9038         if (str_len < 32)
9039           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
9040               (char *) buffer + 51);
9041         else
9042           GST_WARNING_OBJECT (qtdemux,
9043               "compressorname length too big (%u > 31)", str_len);
9044
9045         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
9046             end - buffer);
9047         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
9048         break;
9049       }
9050       case FOURCC_meta:
9051       {
9052         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
9053
9054         /* You are reading this correctly. QTFF specifies that the
9055          * metadata atom is a short atom, whereas ISO BMFF specifies
9056          * it's a full atom. But since so many people are doing things
9057          * differently, we actually peek into the atom to see which
9058          * variant it is */
9059         if (length < 16) {
9060           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
9061               GST_FOURCC_ARGS (fourcc));
9062           break;
9063         }
9064         if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
9065           /* Variant 1: What QTFF specifies. 'meta' is a short header which
9066            * starts with a 'hdlr' atom */
9067           qtdemux_parse_container (qtdemux, node, buffer + 8, end);
9068         } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
9069           /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
9070            * with version/flags both set to zero */
9071           qtdemux_parse_container (qtdemux, node, buffer + 12, end);
9072         } else
9073           GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
9074         break;
9075       }
9076       case FOURCC_mp4s:
9077       {
9078         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
9079         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
9080         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
9081         break;
9082       }
9083       case FOURCC_XiTh:
9084       {
9085         guint32 version;
9086         guint32 offset;
9087
9088         if (length < 16) {
9089           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
9090               GST_FOURCC_ARGS (fourcc));
9091           break;
9092         }
9093
9094         version = QT_UINT32 (buffer + 12);
9095         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
9096
9097         switch (version) {
9098           case 0x00000001:
9099             offset = 0x62;
9100             break;
9101           default:
9102             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
9103             offset = 0;
9104             break;
9105         }
9106         if (offset) {
9107           if (length < offset) {
9108             GST_WARNING_OBJECT (qtdemux,
9109                 "skipping too small %" GST_FOURCC_FORMAT " box",
9110                 GST_FOURCC_ARGS (fourcc));
9111             break;
9112           }
9113           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
9114         }
9115         break;
9116       }
9117       case FOURCC_in24:
9118       {
9119         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
9120         break;
9121       }
9122       case FOURCC_uuid:
9123       {
9124         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
9125         break;
9126       }
9127       case FOURCC_enca:
9128       {
9129         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
9130         break;
9131       }
9132 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
9133       case FOURCC_SA3D:
9134       {
9135         qtdemux_parse_SA3D (qtdemux, buffer, end - buffer);
9136         break;
9137       }
9138 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
9139       default:
9140         if (!strcmp (type->name, "unknown"))
9141           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
9142         break;
9143     }
9144   }
9145   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
9146       GST_FOURCC_ARGS (fourcc));
9147   return TRUE;
9148
9149 /* ERRORS */
9150 not_enough_data:
9151   {
9152     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9153         (_("This file is corrupt and cannot be played.")),
9154         ("Not enough data for an atom header, got only %u bytes", length));
9155     return FALSE;
9156   }
9157 broken_atom_size:
9158   {
9159     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9160         (_("This file is corrupt and cannot be played.")),
9161         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
9162             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
9163             length));
9164     return FALSE;
9165   }
9166 }
9167
9168 static void
9169 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
9170 {
9171 /* FIXME: This can only reliably work if demuxers have a
9172  * separate streaming thread per srcpad. This should be
9173  * done in a demuxer base class, which integrates parts
9174  * of multiqueue
9175  *
9176  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
9177  */
9178 #if 0
9179   GstQuery *query;
9180
9181   query = gst_query_new_allocation (stream->caps, FALSE);
9182
9183   if (!gst_pad_peer_query (stream->pad, query)) {
9184     /* not a problem, just debug a little */
9185     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
9186   }
9187
9188   if (stream->allocator)
9189     gst_object_unref (stream->allocator);
9190
9191   if (gst_query_get_n_allocation_params (query) > 0) {
9192     /* try the allocator */
9193     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
9194         &stream->params);
9195     stream->use_allocator = TRUE;
9196   } else {
9197     stream->allocator = NULL;
9198     gst_allocation_params_init (&stream->params);
9199     stream->use_allocator = FALSE;
9200   }
9201   gst_query_unref (query);
9202 #endif
9203 }
9204
9205 static gboolean
9206 pad_query (const GValue * item, GValue * value, gpointer user_data)
9207 {
9208   GstPad *pad = g_value_get_object (item);
9209   GstQuery *query = user_data;
9210   gboolean res;
9211
9212   res = gst_pad_peer_query (pad, query);
9213
9214   if (res) {
9215     g_value_set_boolean (value, TRUE);
9216     return FALSE;
9217   }
9218
9219   GST_INFO_OBJECT (pad, "pad peer query failed");
9220   return TRUE;
9221 }
9222
9223 static gboolean
9224 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
9225     GstPadDirection direction)
9226 {
9227   GstIterator *it;
9228   GstIteratorFoldFunction func = pad_query;
9229   GValue res = { 0, };
9230
9231   g_value_init (&res, G_TYPE_BOOLEAN);
9232   g_value_set_boolean (&res, FALSE);
9233
9234   /* Ask neighbor */
9235   if (direction == GST_PAD_SRC)
9236     it = gst_element_iterate_src_pads (element);
9237   else
9238     it = gst_element_iterate_sink_pads (element);
9239
9240   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
9241     gst_iterator_resync (it);
9242
9243   gst_iterator_free (it);
9244
9245   return g_value_get_boolean (&res);
9246 }
9247
9248 static void
9249 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
9250     QtDemuxStream * stream)
9251 {
9252   GstQuery *query;
9253   GstContext *ctxt;
9254   GstElement *element = GST_ELEMENT (qtdemux);
9255   GstStructure *st;
9256   gchar **filtered_sys_ids;
9257   GValue event_list = G_VALUE_INIT;
9258   GList *walk;
9259
9260   /* 1. Check if we already have the context. */
9261   if (qtdemux->preferred_protection_system_id != NULL) {
9262     GST_LOG_OBJECT (element,
9263         "already have the protection context, no need to request it again");
9264     return;
9265   }
9266
9267   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
9268   filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
9269       (const gchar **) qtdemux->protection_system_ids->pdata);
9270
9271   g_ptr_array_remove_index (qtdemux->protection_system_ids,
9272       qtdemux->protection_system_ids->len - 1);
9273   GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
9274       "decryptors for %u of them, running context request",
9275       qtdemux->protection_system_ids->len,
9276       filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
9277
9278
9279   if (stream->protection_scheme_event_queue.length) {
9280     GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
9281         stream->protection_scheme_event_queue.length);
9282     walk = stream->protection_scheme_event_queue.tail;
9283   } else {
9284     GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
9285         qtdemux->protection_event_queue.length);
9286     walk = qtdemux->protection_event_queue.tail;
9287   }
9288
9289   g_value_init (&event_list, GST_TYPE_LIST);
9290   for (; walk; walk = g_list_previous (walk)) {
9291     GValue event_value = G_VALUE_INIT;
9292     g_value_init (&event_value, GST_TYPE_EVENT);
9293     g_value_set_boxed (&event_value, walk->data);
9294     gst_value_list_append_and_take_value (&event_list, &event_value);
9295   }
9296
9297   /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
9298    *      check if downstream already has a context of the specific type
9299    *  2b) Query upstream as above.
9300    */
9301   query = gst_query_new_context ("drm-preferred-decryption-system-id");
9302   st = gst_query_writable_structure (query);
9303   gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
9304       "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
9305       NULL);
9306   gst_structure_set_value (st, "stream-encryption-events", &event_list);
9307   if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
9308     gst_query_parse_context (query, &ctxt);
9309     GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
9310     gst_element_set_context (element, ctxt);
9311   } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
9312     gst_query_parse_context (query, &ctxt);
9313     GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
9314     gst_element_set_context (element, ctxt);
9315   } else {
9316     /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
9317      *    the required context type and afterwards check if a
9318      *    usable context was set now as in 1). The message could
9319      *    be handled by the parent bins of the element and the
9320      *    application.
9321      */
9322     GstMessage *msg;
9323
9324     GST_INFO_OBJECT (element, "posting need context message");
9325     msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
9326         "drm-preferred-decryption-system-id");
9327     st = (GstStructure *) gst_message_get_structure (msg);
9328     gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
9329         "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
9330         NULL);
9331
9332     gst_structure_set_value (st, "stream-encryption-events", &event_list);
9333     gst_element_post_message (element, msg);
9334   }
9335
9336   g_strfreev (filtered_sys_ids);
9337   g_value_unset (&event_list);
9338   gst_query_unref (query);
9339 }
9340
9341 static gboolean
9342 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
9343     QtDemuxStream * stream)
9344 {
9345   GstStructure *s;
9346   const gchar *selected_system = NULL;
9347
9348   g_return_val_if_fail (qtdemux != NULL, FALSE);
9349   g_return_val_if_fail (stream != NULL, FALSE);
9350   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
9351       FALSE);
9352
9353   if (stream->protection_scheme_type == FOURCC_aavd) {
9354     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9355     if (!gst_structure_has_name (s, "application/x-aavd")) {
9356       gst_structure_set (s,
9357           "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
9358           NULL);
9359       gst_structure_set_name (s, "application/x-aavd");
9360     }
9361     return TRUE;
9362   }
9363
9364   if (stream->protection_scheme_type != FOURCC_cenc
9365       && stream->protection_scheme_type != FOURCC_cbcs) {
9366     GST_ERROR_OBJECT (qtdemux,
9367         "unsupported protection scheme: %" GST_FOURCC_FORMAT,
9368         GST_FOURCC_ARGS (stream->protection_scheme_type));
9369     return FALSE;
9370   }
9371
9372   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9373   if (!gst_structure_has_name (s, "application/x-cenc")) {
9374     gst_structure_set (s,
9375         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s), NULL);
9376     gst_structure_set (s, "cipher-mode", G_TYPE_STRING,
9377         (stream->protection_scheme_type == FOURCC_cbcs) ? "cbcs" : "cenc",
9378         NULL);
9379     gst_structure_set_name (s, "application/x-cenc");
9380   }
9381
9382   if (qtdemux->protection_system_ids == NULL) {
9383     GST_DEBUG_OBJECT (qtdemux, "stream is protected using cenc, but no "
9384         "cenc protection system information has been found, not setting a "
9385         "protection system UUID");
9386     return TRUE;
9387   }
9388
9389   gst_qtdemux_request_protection_context (qtdemux, stream);
9390   if (qtdemux->preferred_protection_system_id != NULL) {
9391     const gchar *preferred_system_array[] =
9392         { qtdemux->preferred_protection_system_id, NULL };
9393
9394     selected_system = gst_protection_select_system (preferred_system_array);
9395
9396     if (selected_system) {
9397       GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
9398           qtdemux->preferred_protection_system_id);
9399     } else {
9400       GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
9401           "because there is no available decryptor",
9402           qtdemux->preferred_protection_system_id);
9403     }
9404   }
9405
9406   if (!selected_system) {
9407     g_ptr_array_add (qtdemux->protection_system_ids, NULL);
9408     selected_system = gst_protection_select_system ((const gchar **)
9409         qtdemux->protection_system_ids->pdata);
9410     g_ptr_array_remove_index (qtdemux->protection_system_ids,
9411         qtdemux->protection_system_ids->len - 1);
9412   }
9413
9414   if (!selected_system) {
9415     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
9416         "suitable decryptor element has been found");
9417     return FALSE;
9418   }
9419
9420   GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
9421       selected_system);
9422
9423   gst_structure_set (s,
9424       GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
9425       NULL);
9426
9427   return TRUE;
9428 }
9429
9430 static gboolean
9431 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
9432 {
9433   /* fps is calculated base on the duration of the average framerate since
9434    * qt does not have a fixed framerate. */
9435   gboolean fps_available = TRUE;
9436   guint32 first_duration = 0;
9437
9438   if (stream->n_samples > 0)
9439     first_duration = stream->samples[0].duration;
9440
9441   if ((stream->n_samples == 1 && first_duration == 0)
9442       || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
9443     /* still frame */
9444     CUR_STREAM (stream)->fps_n = 0;
9445     CUR_STREAM (stream)->fps_d = 1;
9446   } else {
9447     if (stream->duration == 0 || stream->n_samples < 2) {
9448       CUR_STREAM (stream)->fps_n = stream->timescale;
9449       CUR_STREAM (stream)->fps_d = 1;
9450       fps_available = FALSE;
9451     } else {
9452       GstClockTime avg_duration;
9453       guint64 duration;
9454       guint32 n_samples;
9455
9456       /* duration and n_samples can be updated for fragmented format
9457        * so, framerate of fragmented format is calculated using data in a moof */
9458       if (qtdemux->fragmented && stream->n_samples_moof > 0
9459           && stream->duration_moof > 0) {
9460         n_samples = stream->n_samples_moof;
9461         duration = stream->duration_moof;
9462       } else {
9463         n_samples = stream->n_samples;
9464         duration = stream->duration;
9465       }
9466
9467       /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
9468       /* stream->duration is guint64, timescale, n_samples are guint32 */
9469       avg_duration =
9470           gst_util_uint64_scale_round (duration -
9471           first_duration, GST_SECOND,
9472           (guint64) (stream->timescale) * (n_samples - 1));
9473
9474       GST_LOG_OBJECT (qtdemux,
9475           "Calculating avg sample duration based on stream (or moof) duration %"
9476           G_GUINT64_FORMAT
9477           " minus first sample %u, leaving %d samples gives %"
9478           GST_TIME_FORMAT, duration, first_duration,
9479           n_samples - 1, GST_TIME_ARGS (avg_duration));
9480
9481 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
9482       gst_video_guess_framerate (avg_duration,
9483         &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
9484       if (CUR_STREAM (stream)->fps_d == 0)
9485         fps_available = FALSE;
9486 #else
9487       fps_available =
9488           gst_video_guess_framerate (avg_duration,
9489           &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
9490 #endif
9491
9492       GST_DEBUG_OBJECT (qtdemux,
9493           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
9494           stream->timescale, CUR_STREAM (stream)->fps_n,
9495           CUR_STREAM (stream)->fps_d);
9496     }
9497   }
9498
9499   return fps_available;
9500 }
9501
9502 static gboolean
9503 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
9504 {
9505   if (stream->subtype == FOURCC_vide) {
9506     gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9507
9508     if (CUR_STREAM (stream)->caps) {
9509       CUR_STREAM (stream)->caps =
9510           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9511
9512       if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
9513         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9514             "width", G_TYPE_INT, CUR_STREAM (stream)->width,
9515             "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
9516
9517       /* set framerate if calculated framerate is reliable */
9518       if (fps_available) {
9519         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9520             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9521             CUR_STREAM (stream)->fps_d, NULL);
9522       }
9523
9524       /* calculate pixel-aspect-ratio using display width and height */
9525       GST_DEBUG_OBJECT (qtdemux,
9526           "video size %dx%d, target display size %dx%d",
9527           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
9528           stream->display_width, stream->display_height);
9529       /* qt file might have pasp atom */
9530       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9531         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
9532             CUR_STREAM (stream)->par_h);
9533         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9534             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9535             CUR_STREAM (stream)->par_h, NULL);
9536       } else if (stream->display_width > 0 && stream->display_height > 0
9537           && CUR_STREAM (stream)->width > 0
9538           && CUR_STREAM (stream)->height > 0) {
9539         gint n, d;
9540
9541         /* calculate the pixel aspect ratio using the display and pixel w/h */
9542         n = stream->display_width * CUR_STREAM (stream)->height;
9543         d = stream->display_height * CUR_STREAM (stream)->width;
9544         if (n == d)
9545           n = d = 1;
9546         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
9547         CUR_STREAM (stream)->par_w = n;
9548         CUR_STREAM (stream)->par_h = d;
9549         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9550             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9551             CUR_STREAM (stream)->par_h, NULL);
9552       }
9553
9554       if (CUR_STREAM (stream)->interlace_mode > 0) {
9555         if (CUR_STREAM (stream)->interlace_mode == 1) {
9556           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9557               G_TYPE_STRING, "progressive", NULL);
9558         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
9559           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9560               G_TYPE_STRING, "interleaved", NULL);
9561           if (CUR_STREAM (stream)->field_order == 9) {
9562             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9563                 G_TYPE_STRING, "top-field-first", NULL);
9564           } else if (CUR_STREAM (stream)->field_order == 14) {
9565             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9566                 G_TYPE_STRING, "bottom-field-first", NULL);
9567           }
9568         }
9569       }
9570
9571       /* Create incomplete colorimetry here if needed */
9572       if (CUR_STREAM (stream)->colorimetry.range ||
9573           CUR_STREAM (stream)->colorimetry.matrix ||
9574           CUR_STREAM (stream)->colorimetry.transfer
9575           || CUR_STREAM (stream)->colorimetry.primaries) {
9576         gchar *colorimetry =
9577             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
9578         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
9579             G_TYPE_STRING, colorimetry, NULL);
9580         g_free (colorimetry);
9581       }
9582
9583       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
9584         guint par_w = 1, par_h = 1;
9585
9586         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9587           par_w = CUR_STREAM (stream)->par_w;
9588           par_h = CUR_STREAM (stream)->par_h;
9589         }
9590
9591         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
9592                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
9593                 par_h)) {
9594           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
9595         }
9596
9597         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9598             "multiview-mode", G_TYPE_STRING,
9599             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
9600             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
9601             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
9602       }
9603     }
9604   }
9605
9606   else if (stream->subtype == FOURCC_soun) {
9607     if (CUR_STREAM (stream)->caps) {
9608       CUR_STREAM (stream)->caps =
9609           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9610       if (CUR_STREAM (stream)->rate > 0)
9611         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9612             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
9613       if (CUR_STREAM (stream)->n_channels > 0)
9614         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9615             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
9616       if (CUR_STREAM (stream)->n_channels > 2) {
9617         /* FIXME: Need to parse the 'chan' atom to get channel layouts
9618          * correctly; this is just the minimum we can do - assume
9619          * we don't actually have any channel positions. */
9620         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9621             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
9622       }
9623     }
9624   }
9625
9626   else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
9627     const GstStructure *s;
9628     QtDemuxStream *fps_stream = NULL;
9629     gboolean fps_available = FALSE;
9630
9631     /* CEA608 closed caption tracks are a bit special in that each sample
9632      * can contain CCs for multiple frames, and CCs can be omitted and have to
9633      * be inferred from the duration of the sample then.
9634      *
9635      * As such we take the framerate from the (first) video track here for
9636      * CEA608 as there must be one CC byte pair for every video frame
9637      * according to the spec.
9638      *
9639      * For CEA708 all is fine and there is one sample per frame.
9640      */
9641
9642     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9643     if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
9644       gint i;
9645
9646       for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
9647         QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
9648
9649         if (tmp->subtype == FOURCC_vide) {
9650           fps_stream = tmp;
9651           break;
9652         }
9653       }
9654
9655       if (fps_stream) {
9656         fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
9657         CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
9658         CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
9659       }
9660     } else {
9661       fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9662       fps_stream = stream;
9663     }
9664
9665     CUR_STREAM (stream)->caps =
9666         gst_caps_make_writable (CUR_STREAM (stream)->caps);
9667
9668     /* set framerate if calculated framerate is reliable */
9669     if (fps_available) {
9670       gst_caps_set_simple (CUR_STREAM (stream)->caps,
9671           "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9672           CUR_STREAM (stream)->fps_d, NULL);
9673     }
9674   }
9675
9676   if (stream->pad) {
9677     gboolean forward_collection = FALSE;
9678     GstCaps *prev_caps = NULL;
9679
9680     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9681     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9682     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9683     gst_pad_set_active (stream->pad, TRUE);
9684
9685     gst_pad_use_fixed_caps (stream->pad);
9686
9687     if (stream->protected) {
9688       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9689         GST_ERROR_OBJECT (qtdemux,
9690             "Failed to configure protected stream caps.");
9691         return FALSE;
9692       }
9693     }
9694
9695     if (stream->new_stream) {
9696       GstEvent *event;
9697       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9698
9699       event =
9700           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9701           0);
9702       if (event) {
9703         gst_event_parse_stream_flags (event, &stream_flags);
9704         if (gst_event_parse_group_id (event, &qtdemux->group_id))
9705           qtdemux->have_group_id = TRUE;
9706         else
9707           qtdemux->have_group_id = FALSE;
9708         gst_event_unref (event);
9709       } else if (!qtdemux->have_group_id) {
9710         qtdemux->have_group_id = TRUE;
9711         qtdemux->group_id = gst_util_group_id_next ();
9712       }
9713
9714       stream->new_stream = FALSE;
9715       event = gst_event_new_stream_start (stream->stream_id);
9716       if (qtdemux->have_group_id)
9717         gst_event_set_group_id (event, qtdemux->group_id);
9718       if (stream->disabled)
9719         stream_flags |= GST_STREAM_FLAG_UNSELECT;
9720       if (CUR_STREAM (stream)->sparse) {
9721         stream_flags |= GST_STREAM_FLAG_SPARSE;
9722       } else {
9723         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9724       }
9725       gst_event_set_stream_flags (event, stream_flags);
9726       gst_pad_push_event (stream->pad, event);
9727
9728       forward_collection = TRUE;
9729     }
9730
9731     prev_caps = gst_pad_get_current_caps (stream->pad);
9732
9733     if (CUR_STREAM (stream)->caps) {
9734       if (!prev_caps
9735           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9736         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9737             CUR_STREAM (stream)->caps);
9738         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9739       } else {
9740         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9741       }
9742     } else {
9743       GST_WARNING_OBJECT (qtdemux, "stream without caps");
9744     }
9745
9746     if (prev_caps)
9747       gst_caps_unref (prev_caps);
9748     stream->new_caps = FALSE;
9749
9750     if (forward_collection) {
9751       /* Forward upstream collection and selection if any */
9752       GstEvent *upstream_event = gst_pad_get_sticky_event (qtdemux->sinkpad,
9753           GST_EVENT_STREAM_COLLECTION, 0);
9754       if (upstream_event)
9755         gst_pad_push_event (stream->pad, upstream_event);
9756     }
9757   }
9758   return TRUE;
9759 }
9760
9761 static void
9762 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9763     QtDemuxStream * stream)
9764 {
9765   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9766     return;
9767
9768   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9769       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9770   if (G_UNLIKELY (stream->stsd_sample_description_id >=
9771           stream->stsd_entries_length)) {
9772     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9773         (_("This file is invalid and cannot be played.")),
9774         ("New sample description id is out of bounds (%d >= %d)",
9775             stream->stsd_sample_description_id, stream->stsd_entries_length));
9776   } else {
9777     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9778     stream->new_caps = TRUE;
9779   }
9780 }
9781
9782 static gboolean
9783 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9784     QtDemuxStream * stream, GstTagList * list)
9785 {
9786   gboolean ret = TRUE;
9787
9788   if (stream->subtype == FOURCC_vide) {
9789     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9790
9791     stream->pad =
9792         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9793     g_free (name);
9794
9795     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9796       gst_object_unref (stream->pad);
9797       stream->pad = NULL;
9798       ret = FALSE;
9799       goto done;
9800     }
9801
9802     qtdemux->n_video_streams++;
9803   } else if (stream->subtype == FOURCC_soun) {
9804     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9805
9806     stream->pad =
9807         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9808     g_free (name);
9809     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9810       gst_object_unref (stream->pad);
9811       stream->pad = NULL;
9812       ret = FALSE;
9813       goto done;
9814     }
9815     qtdemux->n_audio_streams++;
9816   } else if (stream->subtype == FOURCC_strm) {
9817     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9818   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9819       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9820       || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
9821     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9822
9823     stream->pad =
9824         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9825     g_free (name);
9826     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9827       gst_object_unref (stream->pad);
9828       stream->pad = NULL;
9829       ret = FALSE;
9830       goto done;
9831     }
9832     qtdemux->n_sub_streams++;
9833   } else if (stream->subtype == FOURCC_meta) {
9834     gchar *name = g_strdup_printf ("meta_%u", qtdemux->n_meta_streams);
9835
9836     stream->pad =
9837         gst_pad_new_from_static_template (&gst_qtdemux_metasrc_template, name);
9838     g_free (name);
9839     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9840       gst_object_unref (stream->pad);
9841       stream->pad = NULL;
9842       ret = FALSE;
9843       goto done;
9844     }
9845     qtdemux->n_meta_streams++;
9846   } else if (CUR_STREAM (stream)->caps) {
9847     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9848
9849     stream->pad =
9850         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9851     g_free (name);
9852     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9853       gst_object_unref (stream->pad);
9854       stream->pad = NULL;
9855       ret = FALSE;
9856       goto done;
9857     }
9858     qtdemux->n_video_streams++;
9859   } else {
9860     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9861     goto done;
9862   }
9863
9864   if (stream->pad) {
9865     GList *l;
9866
9867     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9868         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9869     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9870     GST_OBJECT_LOCK (qtdemux);
9871     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9872     GST_OBJECT_UNLOCK (qtdemux);
9873
9874     if (stream->stream_tags)
9875       gst_tag_list_unref (stream->stream_tags);
9876     stream->stream_tags = list;
9877     list = NULL;
9878     /* global tags go on each pad anyway */
9879     stream->send_global_tags = TRUE;
9880     /* send upstream GST_EVENT_PROTECTION events that were received before
9881        this source pad was created */
9882     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9883       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9884   }
9885 done:
9886   if (list)
9887     gst_tag_list_unref (list);
9888   return ret;
9889 }
9890
9891 /* find next atom with @fourcc starting at @offset */
9892 static GstFlowReturn
9893 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9894     guint64 * length, guint32 fourcc)
9895 {
9896   GstFlowReturn ret;
9897   guint32 lfourcc;
9898   GstBuffer *buf;
9899
9900   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9901       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9902
9903   while (TRUE) {
9904     GstMapInfo map;
9905
9906     buf = NULL;
9907     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9908     if (G_UNLIKELY (ret != GST_FLOW_OK))
9909       goto locate_failed;
9910     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9911       /* likely EOF */
9912       ret = GST_FLOW_EOS;
9913       gst_buffer_unref (buf);
9914       goto locate_failed;
9915     }
9916     gst_buffer_map (buf, &map, GST_MAP_READ);
9917     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9918     gst_buffer_unmap (buf, &map);
9919     gst_buffer_unref (buf);
9920
9921     if (G_UNLIKELY (*length == 0)) {
9922       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9923       ret = GST_FLOW_ERROR;
9924       goto locate_failed;
9925     }
9926
9927     if (lfourcc == fourcc) {
9928       GST_DEBUG_OBJECT (qtdemux, "found '%" GST_FOURCC_FORMAT " at offset %"
9929           G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9930       break;
9931     } else {
9932       GST_LOG_OBJECT (qtdemux,
9933           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9934           GST_FOURCC_ARGS (lfourcc), *offset);
9935       if (*offset == G_MAXUINT64)
9936         goto locate_failed;
9937       *offset += *length;
9938     }
9939   }
9940
9941   return GST_FLOW_OK;
9942
9943 locate_failed:
9944   {
9945     /* might simply have had last one */
9946     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9947     return ret;
9948   }
9949 }
9950
9951 /* should only do something in pull mode */
9952 /* call with OBJECT lock */
9953 static GstFlowReturn
9954 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9955 {
9956   guint64 length, offset;
9957   GstBuffer *buf = NULL;
9958   GstFlowReturn ret = GST_FLOW_OK;
9959   GstFlowReturn res = GST_FLOW_OK;
9960   GstMapInfo map;
9961
9962   offset = qtdemux->moof_offset;
9963   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9964
9965   if (!offset) {
9966     GST_DEBUG_OBJECT (qtdemux, "no next moof");
9967     return GST_FLOW_EOS;
9968   }
9969
9970   /* best not do pull etc with lock held */
9971   GST_OBJECT_UNLOCK (qtdemux);
9972
9973   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9974   if (ret != GST_FLOW_OK)
9975     goto flow_failed;
9976
9977   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9978   if (G_UNLIKELY (ret != GST_FLOW_OK))
9979     goto flow_failed;
9980   gst_buffer_map (buf, &map, GST_MAP_READ);
9981   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9982     gst_buffer_unmap (buf, &map);
9983     gst_buffer_unref (buf);
9984     buf = NULL;
9985     goto parse_failed;
9986   }
9987
9988   gst_buffer_unmap (buf, &map);
9989   gst_buffer_unref (buf);
9990   buf = NULL;
9991
9992   offset += length;
9993   /* look for next moof */
9994   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9995   if (G_UNLIKELY (ret != GST_FLOW_OK))
9996     goto flow_failed;
9997
9998 exit:
9999   GST_OBJECT_LOCK (qtdemux);
10000
10001   qtdemux->moof_offset = offset;
10002
10003   return res;
10004
10005 parse_failed:
10006   {
10007     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
10008     offset = 0;
10009     res = GST_FLOW_ERROR;
10010     goto exit;
10011   }
10012 flow_failed:
10013   {
10014     /* maybe upstream temporarily flushing */
10015     if (ret != GST_FLOW_FLUSHING) {
10016       GST_DEBUG_OBJECT (qtdemux, "no next moof");
10017       offset = 0;
10018     } else {
10019       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
10020       /* resume at current position next time */
10021     }
10022     res = ret;
10023     goto exit;
10024   }
10025 }
10026
10027 static void
10028 qtdemux_merge_sample_table (GstQTDemux * qtdemux, QtDemuxStream * stream)
10029 {
10030   guint i;
10031   guint32 num_chunks;
10032   gint32 stts_duration;
10033   GstByteWriter stsc, stts, stsz;
10034
10035   /* Each sample has a different size, which we don't support for merging */
10036   if (stream->sample_size == 0) {
10037     GST_DEBUG_OBJECT (qtdemux,
10038         "Not all samples have the same size, not merging");
10039     return;
10040   }
10041
10042   /* The stream has a ctts table, we don't support that */
10043   if (stream->ctts_present) {
10044     GST_DEBUG_OBJECT (qtdemux, "Have ctts, not merging");
10045     return;
10046   }
10047
10048   /* If there's a sync sample table also ignore this stream */
10049   if (stream->stps_present || stream->stss_present) {
10050     GST_DEBUG_OBJECT (qtdemux, "Have stss/stps, not merging");
10051     return;
10052   }
10053
10054   /* If chunks are considered samples already ignore this stream */
10055   if (stream->chunks_are_samples) {
10056     GST_DEBUG_OBJECT (qtdemux, "Chunks are samples, not merging");
10057     return;
10058   }
10059
10060   /* Require that all samples have the same duration */
10061   if (stream->n_sample_times > 1) {
10062     GST_DEBUG_OBJECT (qtdemux, "Not all samples have the same duration");
10063     return;
10064   }
10065
10066   /* Parse the stts to get the sample duration and number of samples */
10067   gst_byte_reader_skip_unchecked (&stream->stts, 4);
10068   stts_duration = gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10069
10070   /* Parse the number of chunks from the stco manually because the
10071    * reader is already behind that */
10072   num_chunks = GST_READ_UINT32_BE (stream->stco.data + 4);
10073
10074   GST_DEBUG_OBJECT (qtdemux, "sample_duration %d, num_chunks %u", stts_duration,
10075       num_chunks);
10076
10077   /* Now parse stsc, convert chunks into single samples and generate a
10078    * new stsc, stts and stsz from this information */
10079   gst_byte_writer_init (&stsc);
10080   gst_byte_writer_init (&stts);
10081   gst_byte_writer_init (&stsz);
10082
10083   /* Note: we skip fourccs, size, version, flags and other fields of the new
10084    * atoms as the byte readers with them are already behind that position
10085    * anyway and only update the values of those inside the stream directly.
10086    */
10087   stream->n_sample_times = 0;
10088   stream->n_samples = 0;
10089   for (i = 0; i < stream->n_samples_per_chunk; i++) {
10090     guint j;
10091     guint32 first_chunk, last_chunk, samples_per_chunk, sample_description_id;
10092
10093     first_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
10094     samples_per_chunk = gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
10095     sample_description_id =
10096         gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
10097
10098     if (i == stream->n_samples_per_chunk - 1) {
10099       /* +1 because first_chunk is 1-based */
10100       last_chunk = num_chunks + 1;
10101     } else {
10102       last_chunk = gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
10103     }
10104
10105     GST_DEBUG_OBJECT (qtdemux,
10106         "Merging first_chunk: %u, last_chunk: %u, samples_per_chunk: %u, sample_description_id: %u",
10107         first_chunk, last_chunk, samples_per_chunk, sample_description_id);
10108
10109     gst_byte_writer_put_uint32_be (&stsc, first_chunk);
10110     /* One sample in this chunk */
10111     gst_byte_writer_put_uint32_be (&stsc, 1);
10112     gst_byte_writer_put_uint32_be (&stsc, sample_description_id);
10113
10114     /* For each chunk write a stts and stsz entry now */
10115     gst_byte_writer_put_uint32_be (&stts, last_chunk - first_chunk);
10116     gst_byte_writer_put_uint32_be (&stts, stts_duration * samples_per_chunk);
10117     for (j = first_chunk; j < last_chunk; j++) {
10118       gst_byte_writer_put_uint32_be (&stsz,
10119           stream->sample_size * samples_per_chunk);
10120     }
10121
10122     stream->n_sample_times += 1;
10123     stream->n_samples += last_chunk - first_chunk;
10124   }
10125
10126   g_assert_cmpint (stream->n_samples, ==, num_chunks);
10127
10128   GST_DEBUG_OBJECT (qtdemux, "Have %u samples and %u sample times",
10129       stream->n_samples, stream->n_sample_times);
10130
10131   /* We don't have a fixed sample size anymore */
10132   stream->sample_size = 0;
10133
10134   /* Free old data for the atoms */
10135   g_free ((gpointer) stream->stsz.data);
10136   stream->stsz.data = NULL;
10137   g_free ((gpointer) stream->stsc.data);
10138   stream->stsc.data = NULL;
10139   g_free ((gpointer) stream->stts.data);
10140   stream->stts.data = NULL;
10141
10142   /* Store new data and replace byte readers */
10143   stream->stsz.size = gst_byte_writer_get_size (&stsz);
10144   stream->stsz.data = gst_byte_writer_reset_and_get_data (&stsz);
10145   gst_byte_reader_init (&stream->stsz, stream->stsz.data, stream->stsz.size);
10146   stream->stts.size = gst_byte_writer_get_size (&stts);
10147   stream->stts.data = gst_byte_writer_reset_and_get_data (&stts);
10148   gst_byte_reader_init (&stream->stts, stream->stts.data, stream->stts.size);
10149   stream->stsc.size = gst_byte_writer_get_size (&stsc);
10150   stream->stsc.data = gst_byte_writer_reset_and_get_data (&stsc);
10151   gst_byte_reader_init (&stream->stsc, stream->stsc.data, stream->stsc.size);
10152 }
10153
10154 /* initialise bytereaders for stbl sub-atoms */
10155 static gboolean
10156 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
10157 {
10158   stream->stbl_index = -1;      /* no samples have yet been parsed */
10159   stream->sample_index = -1;
10160
10161   /* time-to-sample atom */
10162   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
10163     goto corrupt_file;
10164
10165   /* copy atom data into a new buffer for later use */
10166   stream->stts.data = g_memdup2 (stream->stts.data, stream->stts.size);
10167
10168   /* skip version + flags */
10169   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
10170       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
10171     goto corrupt_file;
10172   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
10173
10174   /* make sure there's enough data */
10175   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
10176     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
10177     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
10178         stream->n_sample_times);
10179     if (!stream->n_sample_times)
10180       goto corrupt_file;
10181   }
10182
10183   /* sync sample atom */
10184   stream->stps_present = FALSE;
10185   if ((stream->stss_present =
10186           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
10187               &stream->stss) ? TRUE : FALSE) == TRUE) {
10188     /* copy atom data into a new buffer for later use */
10189     stream->stss.data = g_memdup2 (stream->stss.data, stream->stss.size);
10190
10191     /* skip version + flags */
10192     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
10193         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
10194       goto corrupt_file;
10195
10196     if (stream->n_sample_syncs) {
10197       /* make sure there's enough data */
10198       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
10199         goto corrupt_file;
10200     }
10201
10202     /* partial sync sample atom */
10203     if ((stream->stps_present =
10204             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
10205                 &stream->stps) ? TRUE : FALSE) == TRUE) {
10206       /* copy atom data into a new buffer for later use */
10207       stream->stps.data = g_memdup2 (stream->stps.data, stream->stps.size);
10208
10209       /* skip version + flags */
10210       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
10211           !gst_byte_reader_get_uint32_be (&stream->stps,
10212               &stream->n_sample_partial_syncs))
10213         goto corrupt_file;
10214
10215       /* if there are no entries, the stss table contains the real
10216        * sync samples */
10217       if (stream->n_sample_partial_syncs) {
10218         /* make sure there's enough data */
10219         if (!qt_atom_parser_has_chunks (&stream->stps,
10220                 stream->n_sample_partial_syncs, 4))
10221           goto corrupt_file;
10222       }
10223     }
10224   }
10225
10226   /* sample size */
10227   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
10228     goto no_samples;
10229
10230   /* copy atom data into a new buffer for later use */
10231   stream->stsz.data = g_memdup2 (stream->stsz.data, stream->stsz.size);
10232
10233   /* skip version + flags */
10234   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
10235       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
10236     goto corrupt_file;
10237
10238   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
10239     goto corrupt_file;
10240
10241   if (!stream->n_samples)
10242     goto no_samples;
10243
10244   /* sample-to-chunk atom */
10245   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
10246     goto corrupt_file;
10247
10248   /* copy atom data into a new buffer for later use */
10249   stream->stsc.data = g_memdup2 (stream->stsc.data, stream->stsc.size);
10250
10251   /* skip version + flags */
10252   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
10253       !gst_byte_reader_get_uint32_be (&stream->stsc,
10254           &stream->n_samples_per_chunk))
10255     goto corrupt_file;
10256
10257   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
10258       stream->n_samples_per_chunk);
10259
10260   /* make sure there's enough data */
10261   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
10262           12))
10263     goto corrupt_file;
10264
10265
10266   /* chunk offset */
10267   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
10268     stream->co_size = sizeof (guint32);
10269   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
10270           &stream->stco))
10271     stream->co_size = sizeof (guint64);
10272   else
10273     goto corrupt_file;
10274
10275   /* copy atom data into a new buffer for later use */
10276   stream->stco.data = g_memdup2 (stream->stco.data, stream->stco.size);
10277
10278   /* skip version + flags */
10279   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
10280     goto corrupt_file;
10281
10282   /* chunks_are_samples == TRUE means treat chunks as samples */
10283   stream->chunks_are_samples = stream->sample_size
10284       && !CUR_STREAM (stream)->sampled;
10285   if (stream->chunks_are_samples) {
10286     /* treat chunks as samples */
10287     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
10288       goto corrupt_file;
10289   } else {
10290     /* skip number of entries */
10291     if (!gst_byte_reader_skip (&stream->stco, 4))
10292       goto corrupt_file;
10293
10294     /* make sure there are enough data in the stsz atom */
10295     if (!stream->sample_size) {
10296       /* different sizes for each sample */
10297       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
10298         goto corrupt_file;
10299     }
10300   }
10301
10302   /* composition time-to-sample */
10303   if ((stream->ctts_present =
10304           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
10305               &stream->ctts) ? TRUE : FALSE) == TRUE) {
10306     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
10307     guint8 ctts_version;
10308     gboolean checked_ctts = FALSE;
10309
10310     /* copy atom data into a new buffer for later use */
10311     stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
10312
10313     /* version 1 has signed offsets */
10314     if (!gst_byte_reader_get_uint8 (&stream->ctts, &ctts_version))
10315       goto corrupt_file;
10316
10317     /* flags */
10318     if (!gst_byte_reader_skip (&stream->ctts, 3)
10319         || !gst_byte_reader_get_uint32_be (&stream->ctts,
10320             &stream->n_composition_times))
10321       goto corrupt_file;
10322
10323     /* make sure there's enough data */
10324     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
10325             4 + 4))
10326       goto corrupt_file;
10327
10328     /* This is optional, if missing we iterate the ctts */
10329     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
10330       guint8 cslg_version;
10331
10332       /* cslg version 1 has 64 bit fields */
10333       if (!gst_byte_reader_get_uint8 (&cslg, &cslg_version))
10334         goto corrupt_file;
10335
10336       /* skip flags */
10337       if (!gst_byte_reader_skip (&cslg, 3))
10338         goto corrupt_file;
10339
10340       if (cslg_version == 0) {
10341         gint32 composition_to_dts_shift;
10342
10343         if (!gst_byte_reader_get_int32_be (&cslg, &composition_to_dts_shift))
10344           goto corrupt_file;
10345
10346         stream->cslg_shift = MAX (0, composition_to_dts_shift);
10347       } else {
10348         gint64 composition_to_dts_shift;
10349
10350         if (!gst_byte_reader_get_int64_be (&cslg, &composition_to_dts_shift))
10351           goto corrupt_file;
10352
10353         stream->cslg_shift = MAX (0, composition_to_dts_shift);
10354       }
10355     } else {
10356       gint32 cslg_least = 0;
10357       guint num_entries, pos;
10358       gint i;
10359
10360       pos = gst_byte_reader_get_pos (&stream->ctts);
10361       num_entries = stream->n_composition_times;
10362
10363       checked_ctts = TRUE;
10364
10365       stream->cslg_shift = 0;
10366
10367       for (i = 0; i < num_entries; i++) {
10368         gint32 offset;
10369
10370         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
10371         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10372         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
10373          * slightly inaccurate PTS could be more usable than corrupted one */
10374         if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
10375                 && ABS (offset) / 2 > stream->duration)) {
10376           GST_WARNING_OBJECT (qtdemux,
10377               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
10378               " larger than duration %" G_GUINT64_FORMAT, offset,
10379               stream->duration);
10380
10381           stream->cslg_shift = 0;
10382           stream->ctts_present = FALSE;
10383           goto done;
10384         }
10385
10386         /* Don't consider "no decode samples" with offset G_MININT32
10387          * for the DTS/PTS shift */
10388         if (offset != G_MININT32 && offset < cslg_least)
10389           cslg_least = offset;
10390       }
10391
10392       if (cslg_least < 0)
10393         stream->cslg_shift = -cslg_least;
10394       else
10395         stream->cslg_shift = 0;
10396
10397       /* reset the reader so we can generate sample table */
10398       gst_byte_reader_set_pos (&stream->ctts, pos);
10399     }
10400
10401     /* Check if ctts values are looking reasonable if that didn't happen above */
10402     if (!checked_ctts) {
10403       guint num_entries, pos;
10404       gint i;
10405
10406       pos = gst_byte_reader_get_pos (&stream->ctts);
10407       num_entries = stream->n_composition_times;
10408
10409       for (i = 0; i < num_entries; i++) {
10410         gint32 offset;
10411
10412         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
10413         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10414         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
10415          * slightly inaccurate PTS could be more usable than corrupted one */
10416         if (G_UNLIKELY ((ctts_version == 0 || offset != G_MININT32)
10417                 && ABS (offset) / 2 > stream->duration)) {
10418           GST_WARNING_OBJECT (qtdemux,
10419               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
10420               " larger than duration %" G_GUINT64_FORMAT, offset,
10421               stream->duration);
10422
10423           stream->cslg_shift = 0;
10424           stream->ctts_present = FALSE;
10425           goto done;
10426         }
10427       }
10428
10429       /* reset the reader so we can generate sample table */
10430       gst_byte_reader_set_pos (&stream->ctts, pos);
10431     }
10432   } else {
10433     /* Ensure the cslg_shift value is consistent so we can use it
10434      * unconditionally to produce TS and Segment */
10435     stream->cslg_shift = 0;
10436   }
10437
10438   GST_DEBUG_OBJECT (qtdemux, "Using clsg_shift %" G_GUINT64_FORMAT,
10439       stream->cslg_shift);
10440
10441   /* For raw audio streams especially we might want to merge the samples
10442    * to not output one audio sample per buffer. We're doing this here
10443    * before allocating the sample tables so that from this point onwards
10444    * the number of container samples are static */
10445   if (stream->min_buffer_size > 0) {
10446     qtdemux_merge_sample_table (qtdemux, stream);
10447   }
10448
10449 done:
10450   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
10451       stream->n_samples, (guint) sizeof (QtDemuxSample),
10452       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
10453
10454   if (stream->n_samples >=
10455       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
10456     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
10457         "be larger than %uMB (broken file?)", stream->n_samples,
10458         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
10459     return FALSE;
10460   }
10461
10462   g_assert (stream->samples == NULL);
10463   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
10464   if (!stream->samples) {
10465     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
10466         stream->n_samples);
10467     return FALSE;
10468   }
10469
10470   return TRUE;
10471
10472 corrupt_file:
10473   {
10474     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10475         (_("This file is corrupt and cannot be played.")), (NULL));
10476     return FALSE;
10477   }
10478 no_samples:
10479   {
10480     gst_qtdemux_stbl_free (stream);
10481     if (!qtdemux->fragmented) {
10482       /* not quite good */
10483       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
10484       return FALSE;
10485     } else {
10486       /* may pick up samples elsewhere */
10487       return TRUE;
10488     }
10489   }
10490 }
10491
10492 /* collect samples from the next sample to be parsed up to sample @n for @stream
10493  * by reading the info from @stbl
10494  *
10495  * This code can be executed from both the streaming thread and the seeking
10496  * thread so it takes the object lock to protect itself
10497  */
10498 static gboolean
10499 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
10500 {
10501   gint i, j, k;
10502   QtDemuxSample *samples, *first, *cur, *last;
10503   guint32 n_samples_per_chunk;
10504   guint32 n_samples;
10505
10506   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
10507       GST_FOURCC_FORMAT ", pad %s",
10508       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
10509       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
10510
10511   n_samples = stream->n_samples;
10512
10513   if (n >= n_samples)
10514     goto out_of_samples;
10515
10516   GST_OBJECT_LOCK (qtdemux);
10517   if (n <= stream->stbl_index)
10518     goto already_parsed;
10519
10520   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
10521
10522   if (!stream->stsz.data) {
10523     /* so we already parsed and passed all the moov samples;
10524      * onto fragmented ones */
10525     g_assert (qtdemux->fragmented);
10526     goto done;
10527   }
10528
10529   /* pointer to the sample table */
10530   samples = stream->samples;
10531
10532   /* starts from -1, moves to the next sample index to parse */
10533   stream->stbl_index++;
10534
10535   /* keep track of the first and last sample to fill */
10536   first = &samples[stream->stbl_index];
10537   last = &samples[n];
10538
10539   if (!stream->chunks_are_samples) {
10540     /* set the sample sizes */
10541     if (stream->sample_size == 0) {
10542       /* different sizes for each sample */
10543       for (cur = first; cur <= last; cur++) {
10544         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
10545         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
10546             (guint) (cur - samples), cur->size);
10547       }
10548     } else {
10549       /* samples have the same size */
10550       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
10551       for (cur = first; cur <= last; cur++)
10552         cur->size = stream->sample_size;
10553     }
10554   }
10555
10556   n_samples_per_chunk = stream->n_samples_per_chunk;
10557   cur = first;
10558
10559   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
10560     guint32 last_chunk;
10561
10562     if (stream->stsc_chunk_index >= stream->last_chunk
10563         || stream->stsc_chunk_index < stream->first_chunk) {
10564       stream->first_chunk =
10565           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
10566       stream->samples_per_chunk =
10567           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
10568       /* starts from 1 */
10569       stream->stsd_sample_description_id =
10570           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
10571
10572       /* chunk numbers are counted from 1 it seems */
10573       if (G_UNLIKELY (stream->first_chunk == 0))
10574         goto corrupt_file;
10575
10576       --stream->first_chunk;
10577
10578       /* the last chunk of each entry is calculated by taking the first chunk
10579        * of the next entry; except if there is no next, where we fake it with
10580        * INT_MAX */
10581       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
10582         stream->last_chunk = G_MAXUINT32;
10583       } else {
10584         stream->last_chunk =
10585             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
10586         if (G_UNLIKELY (stream->last_chunk == 0))
10587           goto corrupt_file;
10588
10589         --stream->last_chunk;
10590       }
10591
10592       GST_LOG_OBJECT (qtdemux,
10593           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
10594           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
10595           stream->samples_per_chunk, stream->stsd_sample_description_id);
10596
10597       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
10598         goto corrupt_file;
10599
10600       if (stream->last_chunk != G_MAXUINT32) {
10601         if (!qt_atom_parser_peek_sub (&stream->stco,
10602                 stream->first_chunk * stream->co_size,
10603                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
10604                 &stream->co_chunk))
10605           goto corrupt_file;
10606
10607       } else {
10608         stream->co_chunk = stream->stco;
10609         if (!gst_byte_reader_skip (&stream->co_chunk,
10610                 stream->first_chunk * stream->co_size))
10611           goto corrupt_file;
10612       }
10613
10614       stream->stsc_chunk_index = stream->first_chunk;
10615     }
10616
10617     last_chunk = stream->last_chunk;
10618
10619     if (stream->chunks_are_samples) {
10620       cur = &samples[stream->stsc_chunk_index];
10621
10622       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10623         if (j > n) {
10624           /* save state */
10625           stream->stsc_chunk_index = j;
10626           goto done;
10627         }
10628
10629         cur->offset =
10630             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
10631             stream->co_size);
10632
10633         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
10634             "%" G_GUINT64_FORMAT, j, cur->offset);
10635
10636         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
10637             CUR_STREAM (stream)->bytes_per_frame > 0) {
10638           cur->size =
10639               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
10640               CUR_STREAM (stream)->samples_per_frame *
10641               CUR_STREAM (stream)->bytes_per_frame;
10642         } else {
10643           cur->size = stream->samples_per_chunk;
10644         }
10645
10646         GST_DEBUG_OBJECT (qtdemux,
10647             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
10648             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
10649                     stream->stco_sample_index)), cur->size);
10650
10651         cur->timestamp = stream->stco_sample_index;
10652         cur->duration = stream->samples_per_chunk;
10653         cur->keyframe = TRUE;
10654         cur++;
10655
10656         stream->stco_sample_index += stream->samples_per_chunk;
10657       }
10658       stream->stsc_chunk_index = j;
10659     } else {
10660       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10661         guint32 samples_per_chunk;
10662         guint64 chunk_offset;
10663
10664         if (!stream->stsc_sample_index
10665             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
10666                 &stream->chunk_offset))
10667           goto corrupt_file;
10668
10669         samples_per_chunk = stream->samples_per_chunk;
10670         chunk_offset = stream->chunk_offset;
10671
10672         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
10673           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
10674               G_GUINT64_FORMAT " and size %d",
10675               (guint) (cur - samples), chunk_offset, cur->size);
10676
10677           cur->offset = chunk_offset;
10678           chunk_offset += cur->size;
10679           cur++;
10680
10681           if (G_UNLIKELY (cur > last)) {
10682             /* save state */
10683             stream->stsc_sample_index = k + 1;
10684             stream->chunk_offset = chunk_offset;
10685             stream->stsc_chunk_index = j;
10686             goto done2;
10687           }
10688         }
10689         stream->stsc_sample_index = 0;
10690       }
10691       stream->stsc_chunk_index = j;
10692     }
10693     stream->stsc_index++;
10694   }
10695
10696   if (stream->chunks_are_samples)
10697     goto ctts;
10698 done2:
10699   {
10700     guint32 n_sample_times;
10701
10702     n_sample_times = stream->n_sample_times;
10703     cur = first;
10704
10705     for (i = stream->stts_index; i < n_sample_times; i++) {
10706       guint32 stts_samples;
10707       gint32 stts_duration;
10708       gint64 stts_time;
10709
10710       if (stream->stts_sample_index >= stream->stts_samples
10711           || !stream->stts_sample_index) {
10712
10713         stream->stts_samples =
10714             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10715         stream->stts_duration =
10716             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10717
10718         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10719             i, stream->stts_samples, stream->stts_duration);
10720
10721         stream->stts_sample_index = 0;
10722       }
10723
10724       stts_samples = stream->stts_samples;
10725       stts_duration = stream->stts_duration;
10726       stts_time = stream->stts_time;
10727
10728       for (j = stream->stts_sample_index; j < stts_samples; j++) {
10729         GST_DEBUG_OBJECT (qtdemux,
10730             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10731             (guint) (cur - samples), j,
10732             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10733
10734         cur->timestamp = stts_time;
10735         cur->duration = stts_duration;
10736
10737         /* avoid 32-bit wrap-around,
10738          * but still mind possible 'negative' duration */
10739         stts_time += (gint64) stts_duration;
10740         cur++;
10741
10742         if (G_UNLIKELY (cur > last)) {
10743           /* save values */
10744           stream->stts_time = stts_time;
10745           stream->stts_sample_index = j + 1;
10746           if (stream->stts_sample_index >= stream->stts_samples)
10747             stream->stts_index++;
10748           goto done3;
10749         }
10750       }
10751       stream->stts_sample_index = 0;
10752       stream->stts_time = stts_time;
10753       stream->stts_index++;
10754     }
10755     /* fill up empty timestamps with the last timestamp, this can happen when
10756      * the last samples do not decode and so we don't have timestamps for them.
10757      * We however look at the last timestamp to estimate the track length so we
10758      * need something in here. */
10759     for (; cur < last; cur++) {
10760       GST_DEBUG_OBJECT (qtdemux,
10761           "fill sample %d: timestamp %" GST_TIME_FORMAT,
10762           (guint) (cur - samples),
10763           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10764       cur->timestamp = stream->stts_time;
10765       cur->duration = -1;
10766     }
10767   }
10768 done3:
10769   {
10770     /* sample sync, can be NULL */
10771     if (stream->stss_present == TRUE) {
10772       guint32 n_sample_syncs;
10773
10774       n_sample_syncs = stream->n_sample_syncs;
10775
10776       if (!n_sample_syncs) {
10777         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10778         stream->all_keyframe = TRUE;
10779       } else {
10780         for (i = stream->stss_index; i < n_sample_syncs; i++) {
10781           /* note that the first sample is index 1, not 0 */
10782           guint32 index;
10783
10784           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10785
10786           if (G_LIKELY (index > 0 && index <= n_samples)) {
10787             index -= 1;
10788             samples[index].keyframe = TRUE;
10789             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10790             /* and exit if we have enough samples */
10791             if (G_UNLIKELY (index >= n)) {
10792               i++;
10793               break;
10794             }
10795           }
10796         }
10797         /* save state */
10798         stream->stss_index = i;
10799       }
10800
10801       /* stps marks partial sync frames like open GOP I-Frames */
10802       if (stream->stps_present == TRUE) {
10803         guint32 n_sample_partial_syncs;
10804
10805         n_sample_partial_syncs = stream->n_sample_partial_syncs;
10806
10807         /* if there are no entries, the stss table contains the real
10808          * sync samples */
10809         if (n_sample_partial_syncs) {
10810           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10811             /* note that the first sample is index 1, not 0 */
10812             guint32 index;
10813
10814             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10815
10816             if (G_LIKELY (index > 0 && index <= n_samples)) {
10817               index -= 1;
10818               samples[index].keyframe = TRUE;
10819               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10820               /* and exit if we have enough samples */
10821               if (G_UNLIKELY (index >= n)) {
10822                 i++;
10823                 break;
10824               }
10825             }
10826           }
10827           /* save state */
10828           stream->stps_index = i;
10829         }
10830       }
10831     } else {
10832       /* no stss, all samples are keyframes */
10833       stream->all_keyframe = TRUE;
10834       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10835     }
10836   }
10837
10838 ctts:
10839   /* composition time to sample */
10840   if (stream->ctts_present == TRUE) {
10841     guint32 n_composition_times;
10842     guint32 ctts_count;
10843     gint32 ctts_soffset;
10844
10845     /* Fill in the pts_offsets */
10846     cur = first;
10847     n_composition_times = stream->n_composition_times;
10848
10849     for (i = stream->ctts_index; i < n_composition_times; i++) {
10850       if (stream->ctts_sample_index >= stream->ctts_count
10851           || !stream->ctts_sample_index) {
10852         stream->ctts_count =
10853             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10854         stream->ctts_soffset =
10855             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10856         stream->ctts_sample_index = 0;
10857       }
10858
10859       ctts_count = stream->ctts_count;
10860       ctts_soffset = stream->ctts_soffset;
10861
10862       /* FIXME: Set offset to 0 for "no decode samples". This needs
10863        * to be handled in a codec specific manner ideally. */
10864       if (ctts_soffset == G_MININT32)
10865         ctts_soffset = 0;
10866
10867       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10868         cur->pts_offset = ctts_soffset;
10869         cur++;
10870
10871         if (G_UNLIKELY (cur > last)) {
10872           /* save state */
10873           stream->ctts_sample_index = j + 1;
10874           goto done;
10875         }
10876       }
10877       stream->ctts_sample_index = 0;
10878       stream->ctts_index++;
10879     }
10880   }
10881 done:
10882   stream->stbl_index = n;
10883   /* if index has been completely parsed, free data that is no-longer needed */
10884   if (n + 1 == stream->n_samples) {
10885     gst_qtdemux_stbl_free (stream);
10886     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10887     if (qtdemux->pullbased) {
10888       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10889       while (n + 1 == stream->n_samples)
10890         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10891           break;
10892     }
10893   }
10894   GST_OBJECT_UNLOCK (qtdemux);
10895
10896   return TRUE;
10897
10898   /* SUCCESS */
10899 already_parsed:
10900   {
10901     GST_LOG_OBJECT (qtdemux,
10902         "Tried to parse up to sample %u but this sample has already been parsed",
10903         n);
10904     /* if fragmented, there may be more */
10905     if (qtdemux->fragmented && n == stream->stbl_index)
10906       goto done;
10907     GST_OBJECT_UNLOCK (qtdemux);
10908     return TRUE;
10909   }
10910   /* ERRORS */
10911 out_of_samples:
10912   {
10913     GST_LOG_OBJECT (qtdemux,
10914         "Tried to parse up to sample %u but there are only %u samples", n + 1,
10915         stream->n_samples);
10916     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10917         (_("This file is corrupt and cannot be played.")), (NULL));
10918     return FALSE;
10919   }
10920 corrupt_file:
10921   {
10922     GST_OBJECT_UNLOCK (qtdemux);
10923     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10924         (_("This file is corrupt and cannot be played.")), (NULL));
10925     return FALSE;
10926   }
10927 }
10928
10929 /* collect all segment info for @stream.
10930  */
10931 static gboolean
10932 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10933     GNode * trak)
10934 {
10935   GNode *edts;
10936   /* accept edts if they contain gaps at start and there is only
10937    * one media segment */
10938   gboolean allow_pushbased_edts = TRUE;
10939   gint media_segments_count = 0;
10940
10941   /* parse and prepare segment info from the edit list */
10942   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10943   stream->n_segments = 0;
10944   stream->segments = NULL;
10945   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10946     GNode *elst;
10947     guint n_segments;
10948     guint segment_number, entry_size;
10949     guint64 time;
10950     GstClockTime stime;
10951     const guint8 *buffer;
10952     guint8 version;
10953     guint32 size;
10954
10955     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10956     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10957       goto done;
10958
10959     buffer = elst->data;
10960
10961     size = QT_UINT32 (buffer);
10962     /* version, flags, n_segments */
10963     if (size < 16) {
10964       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10965       goto done;
10966     }
10967     version = QT_UINT8 (buffer + 8);
10968     entry_size = (version == 1) ? 20 : 12;
10969
10970     n_segments = QT_UINT32 (buffer + 12);
10971
10972     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10973       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10974       goto done;
10975     }
10976
10977     /* we might allocate a bit too much, at least allocate 1 segment */
10978     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10979
10980     /* segments always start from 0 */
10981     time = 0;
10982     stime = 0;
10983     buffer += 16;
10984     for (segment_number = 0; segment_number < n_segments; segment_number++) {
10985       guint64 duration;
10986       guint64 media_time;
10987       gboolean empty_edit = FALSE;
10988       QtDemuxSegment *segment;
10989       guint32 rate_int;
10990       GstClockTime media_start = GST_CLOCK_TIME_NONE;
10991
10992       if (version == 1) {
10993         media_time = QT_UINT64 (buffer + 8);
10994         duration = QT_UINT64 (buffer);
10995         if (media_time == G_MAXUINT64)
10996           empty_edit = TRUE;
10997       } else {
10998         media_time = QT_UINT32 (buffer + 4);
10999         duration = QT_UINT32 (buffer);
11000         if (media_time == G_MAXUINT32)
11001           empty_edit = TRUE;
11002       }
11003
11004       if (!empty_edit)
11005         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
11006
11007       segment = &stream->segments[segment_number];
11008
11009       /* time and duration expressed in global timescale */
11010       segment->time = stime;
11011       if (duration != 0 || empty_edit) {
11012         /* edge case: empty edits with duration=zero are treated here.
11013          * (files should not have these anyway). */
11014
11015         /* add non scaled values so we don't cause roundoff errors */
11016         time += duration;
11017         stime = QTTIME_TO_GSTTIME (qtdemux, time);
11018         segment->duration = stime - segment->time;
11019       } else {
11020         /* zero duration does not imply media_start == media_stop
11021          * but, only specify media_start. The edit ends with the track. */
11022         stime = segment->duration = GST_CLOCK_TIME_NONE;
11023         /* Don't allow more edits after this one. */
11024         n_segments = segment_number + 1;
11025       }
11026       segment->stop_time = stime;
11027
11028       segment->trak_media_start = media_time;
11029       /* media_time expressed in stream timescale */
11030       if (!empty_edit) {
11031         segment->media_start = media_start;
11032         segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
11033             ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
11034         media_segments_count++;
11035       } else {
11036         segment->media_start = GST_CLOCK_TIME_NONE;
11037         segment->media_stop = GST_CLOCK_TIME_NONE;
11038       }
11039       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
11040
11041       if (rate_int <= 1) {
11042         /* 0 is not allowed, some programs write 1 instead of the floating point
11043          * value */
11044         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
11045             rate_int);
11046         segment->rate = 1;
11047       } else {
11048         segment->rate = rate_int / 65536.0;
11049       }
11050
11051       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
11052           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
11053           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
11054           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
11055           segment_number, GST_TIME_ARGS (segment->time),
11056           GST_TIME_ARGS (segment->duration),
11057           GST_TIME_ARGS (segment->media_start), media_time,
11058           GST_TIME_ARGS (segment->media_stop),
11059           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
11060           stream->timescale);
11061       if (segment->stop_time > qtdemux->segment.stop &&
11062           !qtdemux->upstream_format_is_time) {
11063         GST_WARNING_OBJECT (qtdemux, "Segment %d "
11064             " extends to %" GST_TIME_FORMAT
11065             " past the end of the declared movie duration %" GST_TIME_FORMAT
11066             " movie segment will be extended", segment_number,
11067             GST_TIME_ARGS (segment->stop_time),
11068             GST_TIME_ARGS (qtdemux->segment.stop));
11069         qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
11070       }
11071
11072       buffer += entry_size;
11073     }
11074     GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
11075     stream->n_segments = n_segments;
11076     if (media_segments_count != 1)
11077       allow_pushbased_edts = FALSE;
11078   }
11079 done:
11080
11081   /* push based does not handle segments, so act accordingly here,
11082    * and warn if applicable */
11083   if (!qtdemux->pullbased && !allow_pushbased_edts) {
11084     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
11085     /* remove and use default one below, we stream like it anyway */
11086     g_free (stream->segments);
11087     stream->segments = NULL;
11088     stream->n_segments = 0;
11089   }
11090
11091   /* no segments, create one to play the complete trak */
11092   if (stream->n_segments == 0) {
11093     GstClockTime stream_duration =
11094         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
11095
11096     if (stream->segments == NULL)
11097       stream->segments = g_new (QtDemuxSegment, 1);
11098
11099     /* represent unknown our way */
11100     if (stream_duration == 0)
11101       stream_duration = GST_CLOCK_TIME_NONE;
11102
11103     stream->segments[0].time = 0;
11104     stream->segments[0].stop_time = stream_duration;
11105     stream->segments[0].duration = stream_duration;
11106     stream->segments[0].media_start = 0;
11107     stream->segments[0].media_stop = stream_duration;
11108     stream->segments[0].rate = 1.0;
11109     stream->segments[0].trak_media_start = 0;
11110
11111     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
11112         GST_TIME_ARGS (stream_duration));
11113     stream->n_segments = 1;
11114     stream->dummy_segment = TRUE;
11115   }
11116   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
11117
11118   return TRUE;
11119 }
11120
11121 /*
11122  * Parses the stsd atom of a svq3 trak looking for
11123  * the SMI and gama atoms.
11124  */
11125 static void
11126 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
11127     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
11128 {
11129   const guint8 *_gamma = NULL;
11130   GstBuffer *_seqh = NULL;
11131   const guint8 *stsd_data = stsd_entry_data;
11132   guint32 length = QT_UINT32 (stsd_data);
11133   guint16 version;
11134
11135   if (length < 32) {
11136     GST_WARNING_OBJECT (qtdemux, "stsd too short");
11137     goto end;
11138   }
11139
11140   stsd_data += 16;
11141   length -= 16;
11142   version = QT_UINT16 (stsd_data);
11143   if (version == 3) {
11144     if (length >= 70) {
11145       length -= 70;
11146       stsd_data += 70;
11147       while (length > 8) {
11148         guint32 fourcc, size;
11149         const guint8 *data;
11150         size = QT_UINT32 (stsd_data);
11151         fourcc = QT_FOURCC (stsd_data + 4);
11152         data = stsd_data + 8;
11153
11154         if (size == 0) {
11155           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
11156               "svq3 atom parsing");
11157           goto end;
11158         }
11159
11160         switch (fourcc) {
11161           case FOURCC_gama:{
11162             if (size == 12) {
11163               _gamma = data;
11164             } else {
11165               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
11166                   " for gama atom, expected 12", size);
11167             }
11168             break;
11169           }
11170           case FOURCC_SMI_:{
11171             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
11172               guint32 seqh_size;
11173               if (_seqh != NULL) {
11174                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
11175                     " found, ignoring");
11176               } else {
11177                 seqh_size = QT_UINT32 (data + 4);
11178                 if (seqh_size > 0) {
11179                   _seqh = gst_buffer_new_and_alloc (seqh_size);
11180                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
11181                 }
11182               }
11183             }
11184             break;
11185           }
11186           default:{
11187             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
11188                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
11189           }
11190         }
11191
11192         if (size <= length) {
11193           length -= size;
11194           stsd_data += size;
11195         }
11196       }
11197     } else {
11198       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
11199     }
11200   } else {
11201     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
11202         G_GUINT16_FORMAT, version);
11203     goto end;
11204   }
11205
11206 end:
11207   if (gamma) {
11208     *gamma = _gamma;
11209   }
11210   if (seqh) {
11211     *seqh = _seqh;
11212   } else if (_seqh) {
11213     gst_buffer_unref (_seqh);
11214   }
11215 }
11216
11217 static gchar *
11218 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
11219 {
11220   GNode *dinf;
11221   GstByteReader dref;
11222   gchar *uri = NULL;
11223
11224   /*
11225    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
11226    * atom that might contain a 'data' atom with the rtsp uri.
11227    * This case was reported in bug #597497, some info about
11228    * the hndl atom can be found in TN1195
11229    */
11230   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
11231   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
11232
11233   if (dinf) {
11234     guint32 dref_num_entries = 0;
11235     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
11236         gst_byte_reader_skip (&dref, 4) &&
11237         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
11238       gint i;
11239
11240       /* search dref entries for hndl atom */
11241       for (i = 0; i < dref_num_entries; i++) {
11242         guint32 size = 0, type;
11243         guint8 string_len = 0;
11244         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
11245             qt_atom_parser_get_fourcc (&dref, &type)) {
11246           if (type == FOURCC_hndl) {
11247             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
11248
11249             /* skip data reference handle bytes and the
11250              * following pascal string and some extra 4
11251              * bytes I have no idea what are */
11252             if (!gst_byte_reader_skip (&dref, 4) ||
11253                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
11254                 !gst_byte_reader_skip (&dref, string_len + 4)) {
11255               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
11256               break;
11257             }
11258
11259             /* iterate over the atoms to find the data atom */
11260             while (gst_byte_reader_get_remaining (&dref) >= 8) {
11261               guint32 atom_size;
11262               guint32 atom_type;
11263
11264               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
11265                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
11266                 if (atom_type == FOURCC_data) {
11267                   const guint8 *uri_aux = NULL;
11268
11269                   /* found the data atom that might contain the rtsp uri */
11270                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
11271                       "hndl atom, interpreting it as an URI");
11272                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
11273                           &uri_aux)) {
11274                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
11275                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
11276                     else
11277                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
11278                           "didn't contain a rtsp address");
11279                   } else {
11280                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
11281                         "atom contents");
11282                   }
11283                   break;
11284                 }
11285                 /* skipping to the next entry */
11286                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
11287                   break;
11288               } else {
11289                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
11290                     "atom header");
11291                 break;
11292               }
11293             }
11294             break;
11295           }
11296           /* skip to the next entry */
11297           if (!gst_byte_reader_skip (&dref, size - 8))
11298             break;
11299         } else {
11300           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
11301         }
11302       }
11303       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
11304     }
11305   }
11306   return uri;
11307 }
11308
11309 #define AMR_NB_ALL_MODES        0x81ff
11310 #define AMR_WB_ALL_MODES        0x83ff
11311 static guint
11312 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
11313 {
11314   /* The 'damr' atom is of the form:
11315    *
11316    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
11317    *    32 b       8 b          16 b           8 b                 8 b
11318    *
11319    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
11320    * represents the highest mode used in the stream (and thus the maximum
11321    * bitrate), with a couple of special cases as seen below.
11322    */
11323
11324   /* Map of frame type ID -> bitrate */
11325   static const guint nb_bitrates[] = {
11326     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
11327   };
11328   static const guint wb_bitrates[] = {
11329     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
11330   };
11331   GstMapInfo map;
11332   gsize max_mode;
11333   guint16 mode_set;
11334
11335   gst_buffer_map (buf, &map, GST_MAP_READ);
11336
11337   if (map.size != 0x11) {
11338     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
11339     goto bad_data;
11340   }
11341
11342   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
11343     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
11344         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
11345     goto bad_data;
11346   }
11347
11348   mode_set = QT_UINT16 (map.data + 13);
11349
11350   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
11351     max_mode = 7 + (wb ? 1 : 0);
11352   else
11353     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
11354     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
11355
11356   if (max_mode == -1) {
11357     GST_DEBUG ("No mode indication was found (mode set) = %x",
11358         (guint) mode_set);
11359     goto bad_data;
11360   }
11361
11362   gst_buffer_unmap (buf, &map);
11363   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
11364
11365 bad_data:
11366   gst_buffer_unmap (buf, &map);
11367   return 0;
11368 }
11369
11370 static gboolean
11371 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
11372     GstByteReader * reader, guint32 * matrix, const gchar * atom)
11373 {
11374   /*
11375    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
11376    * [0 1 2]
11377    * [3 4 5]
11378    * [6 7 8]
11379    */
11380
11381   if (gst_byte_reader_get_remaining (reader) < 36)
11382     return FALSE;
11383
11384   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
11385   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
11386   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
11387   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
11388   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
11389   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
11390   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
11391   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
11392   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
11393
11394   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
11395   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
11396       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
11397       matrix[2] & 0xFF);
11398   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
11399       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
11400       matrix[5] & 0xFF);
11401   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
11402       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
11403       matrix[8] & 0xFF);
11404
11405   return TRUE;
11406 }
11407
11408 static void
11409 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
11410     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
11411 {
11412
11413 /* [a b c]
11414  * [d e f]
11415  * [g h i]
11416  *
11417  * This macro will only compare value abdegh, it expects cfi to have already
11418  * been checked
11419  */
11420 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
11421                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
11422
11423   /* only handle the cases where the last column has standard values */
11424   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
11425     const gchar *rotation_tag = NULL;
11426
11427     /* no rotation needed */
11428     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
11429       /* NOP */
11430     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
11431       rotation_tag = "rotate-90";
11432     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
11433       rotation_tag = "rotate-180";
11434     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
11435       rotation_tag = "rotate-270";
11436     } else {
11437       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
11438     }
11439
11440     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
11441         GST_STR_NULL (rotation_tag));
11442     if (rotation_tag != NULL) {
11443       if (*taglist == NULL)
11444         *taglist = gst_tag_list_new_empty ();
11445       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
11446           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
11447     }
11448   } else {
11449     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
11450   }
11451 }
11452
11453 static gboolean
11454 qtdemux_parse_protection_aavd (GstQTDemux * qtdemux,
11455     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
11456 {
11457   GNode *adrm;
11458   guint32 adrm_size;
11459   GstBuffer *adrm_buf = NULL;
11460   QtDemuxAavdEncryptionInfo *info;
11461
11462   adrm = qtdemux_tree_get_child_by_type (container, FOURCC_adrm);
11463   if (G_UNLIKELY (!adrm)) {
11464     GST_ERROR_OBJECT (qtdemux, "aavd box does not contain mandatory adrm box");
11465     return FALSE;
11466   }
11467   adrm_size = QT_UINT32 (adrm->data);
11468   adrm_buf = gst_buffer_new_memdup (adrm->data, adrm_size);
11469
11470   stream->protection_scheme_type = FOURCC_aavd;
11471
11472   if (!stream->protection_scheme_info)
11473     stream->protection_scheme_info = g_new0 (QtDemuxAavdEncryptionInfo, 1);
11474
11475   info = (QtDemuxAavdEncryptionInfo *) stream->protection_scheme_info;
11476
11477   if (info->default_properties)
11478     gst_structure_free (info->default_properties);
11479   info->default_properties = gst_structure_new ("application/x-aavd",
11480       "encrypted", G_TYPE_BOOLEAN, TRUE,
11481       "adrm", GST_TYPE_BUFFER, adrm_buf, NULL);
11482   gst_buffer_unref (adrm_buf);
11483
11484   *original_fmt = FOURCC_mp4a;
11485   return TRUE;
11486 }
11487
11488 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
11489  * protected streams (sinf, frma, schm and schi); if the protection scheme is
11490  * Common Encryption (cenc), the function will also parse the tenc box (defined
11491  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
11492  * (typically an enc[v|a|t|s] sample entry); the function will set
11493  * @original_fmt to the fourcc of the original unencrypted stream format.
11494  * Returns TRUE if successful; FALSE otherwise. */
11495 static gboolean
11496 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
11497     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
11498 {
11499   GNode *sinf;
11500   GNode *frma;
11501   GNode *schm;
11502   GNode *schi;
11503   QtDemuxCencSampleSetInfo *info;
11504   GNode *tenc;
11505   const guint8 *tenc_data;
11506
11507   g_return_val_if_fail (qtdemux != NULL, FALSE);
11508   g_return_val_if_fail (stream != NULL, FALSE);
11509   g_return_val_if_fail (container != NULL, FALSE);
11510   g_return_val_if_fail (original_fmt != NULL, FALSE);
11511
11512   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
11513   if (G_UNLIKELY (!sinf)) {
11514     if (stream->protection_scheme_type == FOURCC_cenc
11515         || stream->protection_scheme_type == FOURCC_cbcs) {
11516       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
11517           "mandatory for Common Encryption");
11518       return FALSE;
11519     }
11520     return TRUE;
11521   }
11522
11523   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
11524   if (G_UNLIKELY (!frma)) {
11525     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
11526     return FALSE;
11527   }
11528
11529   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
11530   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
11531       GST_FOURCC_ARGS (*original_fmt));
11532
11533   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
11534   if (!schm) {
11535     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
11536     return FALSE;
11537   }
11538   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
11539   stream->protection_scheme_version =
11540       QT_UINT32 ((const guint8 *) schm->data + 16);
11541
11542   GST_DEBUG_OBJECT (qtdemux,
11543       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
11544       "protection_scheme_version: %#010x",
11545       GST_FOURCC_ARGS (stream->protection_scheme_type),
11546       stream->protection_scheme_version);
11547
11548   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
11549   if (!schi) {
11550     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
11551     return FALSE;
11552   }
11553   if (stream->protection_scheme_type != FOURCC_cenc &&
11554       stream->protection_scheme_type != FOURCC_piff &&
11555       stream->protection_scheme_type != FOURCC_cbcs) {
11556     GST_ERROR_OBJECT (qtdemux,
11557         "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
11558         GST_FOURCC_ARGS (stream->protection_scheme_type));
11559     return FALSE;
11560   }
11561
11562   if (G_UNLIKELY (!stream->protection_scheme_info))
11563     stream->protection_scheme_info =
11564         g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
11565
11566   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
11567
11568   if (stream->protection_scheme_type == FOURCC_cenc
11569       || stream->protection_scheme_type == FOURCC_cbcs) {
11570     guint8 is_encrypted;
11571     guint8 iv_size;
11572     guint8 constant_iv_size = 0;
11573     const guint8 *default_kid;
11574     guint8 crypt_byte_block = 0;
11575     guint8 skip_byte_block = 0;
11576     const guint8 *constant_iv = NULL;
11577
11578     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
11579     if (!tenc) {
11580       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
11581           "which is mandatory for Common Encryption");
11582       return FALSE;
11583     }
11584     tenc_data = (const guint8 *) tenc->data + 12;
11585     is_encrypted = QT_UINT8 (tenc_data + 2);
11586     iv_size = QT_UINT8 (tenc_data + 3);
11587     default_kid = (tenc_data + 4);
11588     if (stream->protection_scheme_type == FOURCC_cbcs) {
11589       guint8 possible_pattern_info;
11590       if (iv_size == 0) {
11591         constant_iv_size = QT_UINT8 (tenc_data + 20);
11592         if (constant_iv_size != 8 && constant_iv_size != 16) {
11593           GST_ERROR_OBJECT (qtdemux,
11594               "constant IV size should be 8 or 16, not %hhu", constant_iv_size);
11595           return FALSE;
11596         }
11597         constant_iv = (tenc_data + 21);
11598       }
11599       possible_pattern_info = QT_UINT8 (tenc_data + 1);
11600       crypt_byte_block = (possible_pattern_info >> 4) & 0x0f;
11601       skip_byte_block = possible_pattern_info & 0x0f;
11602     }
11603     qtdemux_update_default_sample_cenc_settings (qtdemux, info,
11604         is_encrypted, stream->protection_scheme_type, iv_size, default_kid,
11605         crypt_byte_block, skip_byte_block, constant_iv_size, constant_iv);
11606   } else if (stream->protection_scheme_type == FOURCC_piff) {
11607     GstByteReader br;
11608     static const guint8 piff_track_encryption_uuid[] = {
11609       0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
11610       0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
11611     };
11612
11613     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
11614     if (!tenc) {
11615       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
11616           "which is mandatory for Common Encryption");
11617       return FALSE;
11618     }
11619
11620     tenc_data = (const guint8 *) tenc->data + 8;
11621     if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
11622       gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
11623       GST_ERROR_OBJECT (qtdemux,
11624           "Unsupported track encryption box with uuid: %s", box_uuid);
11625       g_free (box_uuid);
11626       return FALSE;
11627     }
11628     tenc_data = (const guint8 *) tenc->data + 16 + 12;
11629     gst_byte_reader_init (&br, tenc_data, 20);
11630     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
11631       GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
11632       return FALSE;
11633     }
11634     stream->protection_scheme_type = FOURCC_cenc;
11635   }
11636
11637   return TRUE;
11638 }
11639
11640 static gint
11641 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
11642     QtDemuxStream ** stream2)
11643 {
11644   return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
11645 }
11646
11647 static gboolean
11648 qtdemux_parse_stereo_svmi_atom (GstQTDemux * qtdemux, QtDemuxStream * stream,
11649     GNode * stbl)
11650 {
11651   GNode *svmi;
11652
11653   /*parse svmi header if existing */
11654   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
11655   if (svmi) {
11656     guint32 len = QT_UINT32 ((guint8 *) svmi->data);
11657     guint32 version = QT_UINT32 ((guint8 *) svmi->data + 8);
11658     if (!version) {
11659       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
11660       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
11661       guint8 frame_type, frame_layout;
11662       guint32 stereo_mono_change_count;
11663
11664       if (len < 18)
11665         return FALSE;
11666
11667       /* MPEG-A stereo video */
11668       if (qtdemux->major_brand == FOURCC_ss02)
11669         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
11670
11671       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
11672       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
11673       stereo_mono_change_count = QT_UINT32 ((guint8 *) svmi->data + 14);
11674
11675       switch (frame_type) {
11676         case 0:
11677           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11678           break;
11679         case 1:
11680           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11681           break;
11682         case 2:
11683           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11684           break;
11685         case 3:
11686           /* mode 3 is primary/secondary view sequence, ie
11687            * left/right views in separate tracks. See section 7.2
11688            * of ISO/IEC 23000-11:2009 */
11689           /* In the future this might be supported using related
11690            * streams, like an enhancement track - if files like this
11691            * ever exist */
11692           GST_FIXME_OBJECT (qtdemux,
11693               "Implement stereo video in separate streams");
11694       }
11695
11696       if ((frame_layout & 0x1) == 0)
11697         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11698
11699       GST_LOG_OBJECT (qtdemux,
11700           "StereoVideo: composition type: %u, is_left_first: %u",
11701           frame_type, frame_layout);
11702
11703       if (stereo_mono_change_count > 1) {
11704         GST_FIXME_OBJECT (qtdemux,
11705             "Mixed-mono flags are not yet supported in qtdemux.");
11706       }
11707
11708       stream->multiview_mode = mode;
11709       stream->multiview_flags = flags;
11710     }
11711   }
11712
11713   return TRUE;
11714 }
11715
11716 /* parse the traks.
11717  * With each track we associate a new QtDemuxStream that contains all the info
11718  * about the trak.
11719  * traks that do not decode to something (like strm traks) will not have a pad.
11720  */
11721 static gboolean
11722 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
11723 {
11724   GstByteReader tkhd;
11725   int offset;
11726   GNode *mdia;
11727   GNode *mdhd;
11728   GNode *hdlr;
11729   GNode *minf;
11730   GNode *stbl;
11731   GNode *stsd;
11732   GNode *mp4a;
11733   GNode *mp4v;
11734   GNode *esds;
11735   GNode *tref;
11736   GNode *udta;
11737
11738   QtDemuxStream *stream = NULL;
11739   const guint8 *stsd_data;
11740   const guint8 *stsd_entry_data;
11741   guint remaining_stsd_len;
11742   guint stsd_entry_count;
11743   guint stsd_index;
11744   guint16 lang_code;            /* quicktime lang code or packed iso code */
11745   guint32 version;
11746   guint32 tkhd_flags = 0;
11747   guint8 tkhd_version = 0;
11748   guint32 w = 0, h = 0;
11749   guint value_size, stsd_len, len;
11750   guint32 track_id;
11751   guint32 dummy;
11752
11753   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11754
11755   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11756       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11757       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11758     goto corrupt_file;
11759
11760   /* pick between 64 or 32 bits */
11761   value_size = tkhd_version == 1 ? 8 : 4;
11762   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11763       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11764     goto corrupt_file;
11765
11766   /* Check if current moov has duplicated track_id */
11767   if (qtdemux_find_stream (qtdemux, track_id))
11768     goto existing_stream;
11769
11770   stream = _create_stream (qtdemux, track_id);
11771   stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11772
11773 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
11774   if (!gst_byte_reader_skip (&tkhd, 4))
11775     goto corrupt_file;
11776
11777   if (tkhd_version == 1) {
11778     if (!gst_byte_reader_get_uint64_be (&tkhd, &stream->tkhd_duration))
11779       goto corrupt_file;
11780   } else {
11781     guint32 dur = 0;
11782     if (!gst_byte_reader_get_uint32_be (&tkhd, &dur))
11783       goto corrupt_file;
11784     stream->tkhd_duration = dur;
11785   }
11786   GST_INFO_OBJECT (qtdemux, "tkhd duration: %" G_GUINT64_FORMAT,
11787       stream->tkhd_duration);
11788 #endif
11789   /* need defaults for fragments */
11790   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11791
11792   if ((tkhd_flags & 1) == 0)
11793     stream->disabled = TRUE;
11794
11795   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11796       tkhd_version, tkhd_flags, stream->track_id);
11797
11798   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11799     goto corrupt_file;
11800
11801   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11802     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11803     if (qtdemux->major_brand != FOURCC_mjp2 ||
11804         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11805       goto corrupt_file;
11806   }
11807
11808   len = QT_UINT32 ((guint8 *) mdhd->data);
11809   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11810   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11811   if (version == 0x01000000) {
11812     if (len < 42)
11813       goto corrupt_file;
11814     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11815     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11816     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11817   } else {
11818     if (len < 30)
11819       goto corrupt_file;
11820     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11821     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11822     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11823   }
11824
11825   if (lang_code < 0x400) {
11826     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11827   } else if (lang_code == 0x7fff) {
11828     stream->lang_id[0] = 0;     /* unspecified */
11829   } else {
11830     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11831     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11832     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11833     stream->lang_id[3] = 0;
11834   }
11835
11836   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11837       stream->timescale);
11838   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11839       stream->duration);
11840   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11841       lang_code, stream->lang_id);
11842
11843   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11844     goto corrupt_file;
11845
11846   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11847     /* chapters track reference */
11848     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11849     if (chap) {
11850       gsize length = GST_READ_UINT32_BE (chap->data);
11851       if (qtdemux->chapters_track_id)
11852         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11853
11854       if (length >= 12) {
11855         qtdemux->chapters_track_id =
11856             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11857       }
11858     }
11859   }
11860
11861   /* fragmented files may have bogus duration in moov */
11862   if (!qtdemux->fragmented &&
11863       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11864     guint64 tdur1, tdur2;
11865
11866     /* don't overflow */
11867     tdur1 = stream->timescale * (guint64) qtdemux->duration;
11868     tdur2 = qtdemux->timescale * (guint64) stream->duration;
11869
11870     /* HACK:
11871      * some of those trailers, nowadays, have prologue images that are
11872      * themselves video tracks as well. I haven't really found a way to
11873      * identify those yet, except for just looking at their duration. */
11874     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11875       GST_WARNING_OBJECT (qtdemux,
11876           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11877           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11878           "found, assuming preview image or something; skipping track",
11879           stream->duration, stream->timescale, qtdemux->duration,
11880           qtdemux->timescale);
11881       gst_qtdemux_stream_unref (stream);
11882       return TRUE;
11883     }
11884   }
11885
11886   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11887     goto corrupt_file;
11888
11889   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11890       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11891
11892   len = QT_UINT32 ((guint8 *) hdlr->data);
11893   if (len >= 20)
11894     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11895   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11896       GST_FOURCC_ARGS (stream->subtype));
11897
11898   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11899     goto corrupt_file;
11900
11901   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11902     goto corrupt_file;
11903
11904   /* Parse out svmi (and later st3d/sv3d) atoms */
11905   if (!qtdemux_parse_stereo_svmi_atom (qtdemux, stream, stbl))
11906     goto corrupt_file;
11907
11908   /* parse rest of tkhd */
11909   if (stream->subtype == FOURCC_vide) {
11910     guint32 matrix[9];
11911
11912     /* version 1 uses some 64-bit ints */
11913 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
11914     if (!gst_byte_reader_skip (&tkhd, 16))
11915 #else
11916     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11917 #endif
11918       goto corrupt_file;
11919
11920     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11921       goto corrupt_file;
11922
11923     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11924         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11925       goto corrupt_file;
11926
11927     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11928         &stream->stream_tags);
11929   }
11930
11931   /* parse stsd */
11932   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11933     goto corrupt_file;
11934   stsd_data = (const guint8 *) stsd->data;
11935
11936   /* stsd should at least have one entry */
11937   stsd_len = QT_UINT32 (stsd_data);
11938   if (stsd_len < 24) {
11939     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11940     if (stream->subtype == FOURCC_vivo) {
11941       gst_qtdemux_stream_unref (stream);
11942       return TRUE;
11943     } else {
11944       goto corrupt_file;
11945     }
11946   }
11947
11948   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11949   /* each stsd entry must contain at least 8 bytes */
11950   if (stream->stsd_entries_length == 0
11951       || stream->stsd_entries_length > stsd_len / 8) {
11952     stream->stsd_entries_length = 0;
11953     goto corrupt_file;
11954   }
11955   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11956   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
11957   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
11958
11959   stsd_entry_data = stsd_data + 16;
11960   remaining_stsd_len = stsd_len - 16;
11961   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11962     guint32 fourcc;
11963     gchar *codec = NULL;
11964     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11965
11966     /* and that entry should fit within stsd */
11967     len = QT_UINT32 (stsd_entry_data);
11968     if (len > remaining_stsd_len)
11969       goto corrupt_file;
11970
11971     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11972     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
11973         GST_FOURCC_ARGS (entry->fourcc));
11974     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
11975
11976     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11977       goto error_encrypted;
11978
11979     if (fourcc == FOURCC_aavd) {
11980       if (stream->subtype != FOURCC_soun) {
11981         GST_ERROR_OBJECT (qtdemux,
11982             "Unexpeced stsd type 'aavd' outside 'soun' track");
11983       } else {
11984         /* encrypted audio with sound sample description v0 */
11985         GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11986         stream->protected = TRUE;
11987         if (!qtdemux_parse_protection_aavd (qtdemux, stream, enc, &fourcc))
11988           GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11989       }
11990     }
11991
11992     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11993       /* FIXME this looks wrong, there might be multiple children
11994        * with the same type */
11995       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11996       stream->protected = TRUE;
11997       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11998         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11999     }
12000
12001     if (stream->subtype == FOURCC_vide) {
12002       GNode *colr;
12003       GNode *fiel;
12004       GNode *pasp;
12005       gboolean gray;
12006       gint depth, palette_size, palette_count;
12007       guint32 *palette_data = NULL;
12008
12009       entry->sampled = TRUE;
12010
12011       stream->display_width = w >> 16;
12012       stream->display_height = h >> 16;
12013
12014       offset = 16;
12015       if (len < 86)             /* TODO verify */
12016         goto corrupt_file;
12017
12018       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
12019       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
12020       entry->fps_n = 0;         /* this is filled in later */
12021       entry->fps_d = 0;         /* this is filled in later */
12022       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
12023       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
12024
12025       /* if color_table_id is 0, ctab atom must follow; however some files
12026        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
12027        * if color table is not present we'll correct the value */
12028       if (entry->color_table_id == 0 &&
12029           (len < 90
12030               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
12031         entry->color_table_id = -1;
12032       }
12033
12034       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
12035           entry->width, entry->height, entry->bits_per_sample,
12036           entry->color_table_id);
12037
12038       depth = entry->bits_per_sample;
12039
12040       /* more than 32 bits means grayscale */
12041       gray = (depth > 32);
12042       /* low 32 bits specify the depth  */
12043       depth &= 0x1F;
12044
12045       /* different number of palette entries is determined by depth. */
12046       palette_count = 0;
12047       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
12048         palette_count = (1 << depth);
12049       palette_size = palette_count * 4;
12050
12051       if (entry->color_table_id) {
12052         switch (palette_count) {
12053           case 0:
12054             break;
12055           case 2:
12056             palette_data = g_memdup2 (ff_qt_default_palette_2, palette_size);
12057             break;
12058           case 4:
12059             palette_data = g_memdup2 (ff_qt_default_palette_4, palette_size);
12060             break;
12061           case 16:
12062             if (gray)
12063               palette_data =
12064                   g_memdup2 (ff_qt_grayscale_palette_16, palette_size);
12065             else
12066               palette_data = g_memdup2 (ff_qt_default_palette_16, palette_size);
12067             break;
12068           case 256:
12069             if (gray)
12070               palette_data =
12071                   g_memdup2 (ff_qt_grayscale_palette_256, palette_size);
12072             else
12073               palette_data =
12074                   g_memdup2 (ff_qt_default_palette_256, palette_size);
12075             break;
12076           default:
12077             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
12078                 (_("The video in this file might not play correctly.")),
12079                 ("unsupported palette depth %d", depth));
12080             break;
12081         }
12082       } else {
12083         guint i, j, start, end;
12084
12085         if (len < 94)
12086           goto corrupt_file;
12087
12088         /* read table */
12089         start = QT_UINT32 (stsd_entry_data + offset + 70);
12090         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
12091         end = QT_UINT16 (stsd_entry_data + offset + 76);
12092
12093         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
12094             start, end, palette_count);
12095
12096         if (end > 255)
12097           end = 255;
12098         if (start > end)
12099           start = end;
12100
12101         if (len < 94 + (end - start) * 8)
12102           goto corrupt_file;
12103
12104         /* palette is always the same size */
12105         palette_data = g_malloc0 (256 * 4);
12106         palette_size = 256 * 4;
12107
12108         for (j = 0, i = start; i <= end; j++, i++) {
12109           guint32 a, r, g, b;
12110
12111           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
12112           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
12113           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
12114           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
12115
12116           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
12117               (g & 0xff00) | (b >> 8);
12118         }
12119       }
12120
12121       if (entry->caps)
12122         gst_caps_unref (entry->caps);
12123
12124       entry->caps =
12125           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12126           &codec);
12127       if (G_UNLIKELY (!entry->caps)) {
12128         g_free (palette_data);
12129         goto unknown_stream;
12130       }
12131
12132       if (codec) {
12133         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12134             GST_TAG_VIDEO_CODEC, codec, NULL);
12135         g_free (codec);
12136         codec = NULL;
12137       }
12138
12139       if (palette_data) {
12140         GstStructure *s;
12141
12142         if (entry->rgb8_palette)
12143           gst_memory_unref (entry->rgb8_palette);
12144         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
12145             palette_data, palette_size, 0, palette_size, palette_data, g_free);
12146
12147         s = gst_caps_get_structure (entry->caps, 0);
12148
12149         /* non-raw video has a palette_data property. raw video has the palette as
12150          * an extra plane that we append to the output buffers before we push
12151          * them*/
12152         if (!gst_structure_has_name (s, "video/x-raw")) {
12153           GstBuffer *palette;
12154
12155           palette = gst_buffer_new ();
12156           gst_buffer_append_memory (palette, entry->rgb8_palette);
12157           entry->rgb8_palette = NULL;
12158
12159           gst_caps_set_simple (entry->caps, "palette_data",
12160               GST_TYPE_BUFFER, palette, NULL);
12161           gst_buffer_unref (palette);
12162         }
12163       } else if (palette_count != 0) {
12164         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
12165             (NULL), ("Unsupported palette depth %d", depth));
12166       }
12167
12168       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
12169           QT_UINT16 (stsd_entry_data + offset + 32));
12170
12171       esds = NULL;
12172       pasp = NULL;
12173       colr = NULL;
12174       fiel = NULL;
12175       /* pick 'the' stsd child */
12176       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12177       // We should skip parsing the stsd for non-protected streams if
12178       // the entry doesn't match the fourcc, since they don't change
12179       // format. However, for protected streams we can have partial
12180       // encryption, where parts of the stream are encrypted and parts
12181       // not. For both parts of such streams, we should ensure the
12182       // esds overrides are parsed for both from the stsd.
12183       if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
12184         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
12185           mp4v = NULL;
12186         else if (!stream->protected)
12187           mp4v = NULL;
12188       }
12189
12190       if (mp4v) {
12191         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
12192         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
12193         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
12194         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
12195       }
12196
12197       if (pasp) {
12198         const guint8 *pasp_data = (const guint8 *) pasp->data;
12199         guint len = QT_UINT32 (pasp_data);
12200
12201         if (len == 16) {
12202           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
12203           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
12204         } else {
12205           CUR_STREAM (stream)->par_w = 0;
12206           CUR_STREAM (stream)->par_h = 0;
12207         }
12208       } else {
12209         CUR_STREAM (stream)->par_w = 0;
12210         CUR_STREAM (stream)->par_h = 0;
12211       }
12212
12213       if (fiel) {
12214         const guint8 *fiel_data = (const guint8 *) fiel->data;
12215         guint len = QT_UINT32 (fiel_data);
12216
12217         if (len == 10) {
12218           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
12219           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
12220         }
12221       }
12222
12223       if (colr) {
12224         const guint8 *colr_data = (const guint8 *) colr->data;
12225         guint len = QT_UINT32 (colr_data);
12226
12227         if (len == 19 || len == 18) {
12228           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
12229
12230           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
12231             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
12232             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
12233             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
12234             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
12235
12236             CUR_STREAM (stream)->colorimetry.primaries =
12237                 gst_video_color_primaries_from_iso (primaries);
12238             CUR_STREAM (stream)->colorimetry.transfer =
12239                 gst_video_transfer_function_from_iso (transfer_function);
12240             CUR_STREAM (stream)->colorimetry.matrix =
12241                 gst_video_color_matrix_from_iso (matrix);
12242             CUR_STREAM (stream)->colorimetry.range =
12243                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
12244                 GST_VIDEO_COLOR_RANGE_16_235;
12245           } else {
12246             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
12247           }
12248         } else {
12249           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
12250         }
12251       }
12252
12253       if (esds) {
12254         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12255             stream->stream_tags);
12256       } else {
12257         switch (fourcc) {
12258           case FOURCC_H264:
12259           case FOURCC_avc1:
12260           case FOURCC_avc3:
12261           {
12262             guint len = QT_UINT32 (stsd_entry_data);
12263             len = len <= 0x56 ? 0 : len - 0x56;
12264             const guint8 *avc_data = stsd_entry_data + 0x56;
12265
12266             /* find avcC */
12267             while (len >= 0x8) {
12268               guint size;
12269
12270               if (QT_UINT32 (avc_data) <= 0x8)
12271                 size = 0;
12272               else if (QT_UINT32 (avc_data) <= len)
12273                 size = QT_UINT32 (avc_data) - 0x8;
12274               else
12275                 size = len - 0x8;
12276
12277               if (size < 1)
12278                 /* No real data, so break out */
12279                 break;
12280
12281               switch (QT_FOURCC (avc_data + 0x4)) {
12282                 case FOURCC_avcC:
12283                 {
12284                   /* parse, if found */
12285                   GstBuffer *buf;
12286
12287                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
12288
12289                   /* First 4 bytes are the length of the atom, the next 4 bytes
12290                    * are the fourcc, the next 1 byte is the version, and the
12291                    * subsequent bytes are profile_tier_level structure like data. */
12292                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
12293                       avc_data + 8 + 1, size - 1);
12294                   buf = gst_buffer_new_and_alloc (size);
12295                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
12296                   gst_caps_set_simple (entry->caps,
12297                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12298                   gst_buffer_unref (buf);
12299
12300                   break;
12301                 }
12302                 case FOURCC_strf:
12303                 {
12304                   GstBuffer *buf;
12305
12306                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
12307
12308                   /* First 4 bytes are the length of the atom, the next 4 bytes
12309                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
12310                    * next 1 byte is the version, and the
12311                    * subsequent bytes are sequence parameter set like data. */
12312
12313                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
12314                   if (size > 1) {
12315                     gst_codec_utils_h264_caps_set_level_and_profile
12316                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
12317
12318                     buf = gst_buffer_new_and_alloc (size);
12319                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
12320                     gst_caps_set_simple (entry->caps,
12321                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
12322                     gst_buffer_unref (buf);
12323                   }
12324                   break;
12325                 }
12326                 case FOURCC_btrt:
12327                 {
12328                   guint avg_bitrate, max_bitrate;
12329
12330                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
12331                   if (size < 12)
12332                     break;
12333
12334                   max_bitrate = QT_UINT32 (avc_data + 0xc);
12335                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
12336
12337                   if (!max_bitrate && !avg_bitrate)
12338                     break;
12339
12340                   /* Some muxers seem to swap the average and maximum bitrates
12341                    * (I'm looking at you, YouTube), so we swap for sanity. */
12342                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
12343                     guint temp = avg_bitrate;
12344
12345                     avg_bitrate = max_bitrate;
12346                     max_bitrate = temp;
12347                   }
12348
12349                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12350                     gst_tag_list_add (stream->stream_tags,
12351                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
12352                         max_bitrate, NULL);
12353                   }
12354                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12355                     gst_tag_list_add (stream->stream_tags,
12356                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
12357                         NULL);
12358                   }
12359
12360                   break;
12361                 }
12362
12363                 default:
12364                   break;
12365               }
12366
12367               len -= size + 8;
12368               avc_data += size + 8;
12369             }
12370
12371             break;
12372           }
12373           case FOURCC_H265:
12374           case FOURCC_hvc1:
12375           case FOURCC_hev1:
12376           case FOURCC_dvh1:
12377           case FOURCC_dvhe:
12378           {
12379             guint len = QT_UINT32 (stsd_entry_data);
12380             len = len <= 0x56 ? 0 : len - 0x56;
12381             const guint8 *hevc_data = stsd_entry_data + 0x56;
12382
12383             /* find hevc */
12384             while (len >= 0x8) {
12385               guint size;
12386
12387               if (QT_UINT32 (hevc_data) <= 0x8)
12388                 size = 0;
12389               else if (QT_UINT32 (hevc_data) <= len)
12390                 size = QT_UINT32 (hevc_data) - 0x8;
12391               else
12392                 size = len - 0x8;
12393
12394               if (size < 1)
12395                 /* No real data, so break out */
12396                 break;
12397
12398               switch (QT_FOURCC (hevc_data + 0x4)) {
12399                 case FOURCC_hvcC:
12400                 {
12401                   /* parse, if found */
12402                   GstBuffer *buf;
12403
12404                   GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
12405
12406                   /* First 4 bytes are the length of the atom, the next 4 bytes
12407                    * are the fourcc, the next 1 byte is the version, and the
12408                    * subsequent bytes are sequence parameter set like data. */
12409                   gst_codec_utils_h265_caps_set_level_tier_and_profile
12410                       (entry->caps, hevc_data + 8 + 1, size - 1);
12411
12412                   buf = gst_buffer_new_and_alloc (size);
12413                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
12414                   gst_caps_set_simple (entry->caps,
12415                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12416                   gst_buffer_unref (buf);
12417                   break;
12418                 }
12419                 default:
12420                   break;
12421               }
12422               len -= size + 8;
12423               hevc_data += size + 8;
12424             }
12425             break;
12426           }
12427           case FOURCC_mp4v:
12428           case FOURCC_MP4V:
12429           case FOURCC_fmp4:
12430           case FOURCC_FMP4:
12431           case FOURCC_xvid:
12432           case FOURCC_XVID:
12433           {
12434             GNode *glbl;
12435
12436             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
12437                 GST_FOURCC_ARGS (fourcc));
12438
12439             /* codec data might be in glbl extension atom */
12440             glbl = mp4v ?
12441                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
12442             if (glbl) {
12443               guint8 *data;
12444               GstBuffer *buf;
12445               guint len;
12446
12447               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
12448               data = glbl->data;
12449               len = QT_UINT32 (data);
12450               if (len > 0x8) {
12451                 len -= 0x8;
12452                 buf = gst_buffer_new_and_alloc (len);
12453                 gst_buffer_fill (buf, 0, data + 8, len);
12454                 gst_caps_set_simple (entry->caps,
12455                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12456                 gst_buffer_unref (buf);
12457               }
12458             }
12459             break;
12460           }
12461           case FOURCC_mjp2:
12462           {
12463             /* see annex I of the jpeg2000 spec */
12464             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
12465             const guint8 *data;
12466             const gchar *colorspace = NULL;
12467             gint ncomp = 0;
12468             guint32 ncomp_map = 0;
12469             gint32 *comp_map = NULL;
12470             guint32 nchan_def = 0;
12471             gint32 *chan_def = NULL;
12472
12473             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
12474             /* some required atoms */
12475             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12476             if (!mjp2)
12477               break;
12478             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
12479             if (!jp2h)
12480               break;
12481
12482             /* number of components; redundant with info in codestream, but useful
12483                to a muxer */
12484             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
12485             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
12486               break;
12487             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
12488
12489             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
12490             if (!colr)
12491               break;
12492             GST_DEBUG_OBJECT (qtdemux, "found colr");
12493             /* extract colour space info */
12494             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
12495               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
12496                 case 16:
12497                   colorspace = "sRGB";
12498                   break;
12499                 case 17:
12500                   colorspace = "GRAY";
12501                   break;
12502                 case 18:
12503                   colorspace = "sYUV";
12504                   break;
12505                 default:
12506                   colorspace = NULL;
12507                   break;
12508               }
12509             }
12510             if (!colorspace)
12511               /* colr is required, and only values 16, 17, and 18 are specified,
12512                  so error if we have no colorspace */
12513               break;
12514
12515             /* extract component mapping */
12516             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
12517             if (cmap) {
12518               guint32 cmap_len = 0;
12519               int i;
12520               cmap_len = QT_UINT32 (cmap->data);
12521               if (cmap_len >= 8) {
12522                 /* normal box, subtract off header */
12523                 cmap_len -= 8;
12524                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
12525                 if (cmap_len % 4 == 0) {
12526                   ncomp_map = (cmap_len / 4);
12527                   comp_map = g_new0 (gint32, ncomp_map);
12528                   for (i = 0; i < ncomp_map; i++) {
12529                     guint16 cmp;
12530                     guint8 mtyp, pcol;
12531                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
12532                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
12533                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
12534                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
12535                   }
12536                 }
12537               }
12538             }
12539             /* extract channel definitions */
12540             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
12541             if (cdef) {
12542               guint32 cdef_len = 0;
12543               int i;
12544               cdef_len = QT_UINT32 (cdef->data);
12545               if (cdef_len >= 10) {
12546                 /* normal box, subtract off header and len */
12547                 cdef_len -= 10;
12548                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
12549                 if (cdef_len % 6 == 0) {
12550                   nchan_def = (cdef_len / 6);
12551                   chan_def = g_new0 (gint32, nchan_def);
12552                   for (i = 0; i < nchan_def; i++)
12553                     chan_def[i] = -1;
12554                   for (i = 0; i < nchan_def; i++) {
12555                     guint16 cn, typ, asoc;
12556                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
12557                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
12558                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
12559                     if (cn < nchan_def) {
12560                       switch (typ) {
12561                         case 0:
12562                           chan_def[cn] = asoc;
12563                           break;
12564                         case 1:
12565                           chan_def[cn] = 0;     /* alpha */
12566                           break;
12567                         default:
12568                           chan_def[cn] = -typ;
12569                       }
12570                     }
12571                   }
12572                 }
12573               }
12574             }
12575
12576             gst_caps_set_simple (entry->caps,
12577                 "num-components", G_TYPE_INT, ncomp, NULL);
12578             gst_caps_set_simple (entry->caps,
12579                 "colorspace", G_TYPE_STRING, colorspace, NULL);
12580
12581             if (comp_map) {
12582               GValue arr = { 0, };
12583               GValue elt = { 0, };
12584               int i;
12585               g_value_init (&arr, GST_TYPE_ARRAY);
12586               g_value_init (&elt, G_TYPE_INT);
12587               for (i = 0; i < ncomp_map; i++) {
12588                 g_value_set_int (&elt, comp_map[i]);
12589                 gst_value_array_append_value (&arr, &elt);
12590               }
12591               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
12592                   "component-map", &arr);
12593               g_value_unset (&elt);
12594               g_value_unset (&arr);
12595               g_free (comp_map);
12596             }
12597
12598             if (chan_def) {
12599               GValue arr = { 0, };
12600               GValue elt = { 0, };
12601               int i;
12602               g_value_init (&arr, GST_TYPE_ARRAY);
12603               g_value_init (&elt, G_TYPE_INT);
12604               for (i = 0; i < nchan_def; i++) {
12605                 g_value_set_int (&elt, chan_def[i]);
12606                 gst_value_array_append_value (&arr, &elt);
12607               }
12608               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
12609                   "channel-definitions", &arr);
12610               g_value_unset (&elt);
12611               g_value_unset (&arr);
12612               g_free (chan_def);
12613             }
12614
12615             /* some optional atoms */
12616             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
12617             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
12618
12619             /* indicate possible fields in caps */
12620             if (field) {
12621               data = (guint8 *) field->data + 8;
12622               if (*data != 1)
12623                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
12624                     (gint) * data, NULL);
12625             }
12626             /* add codec_data if provided */
12627             if (prefix) {
12628               GstBuffer *buf;
12629               guint len;
12630
12631               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
12632               data = prefix->data;
12633               len = QT_UINT32 (data);
12634               if (len > 0x8) {
12635                 len -= 0x8;
12636                 buf = gst_buffer_new_and_alloc (len);
12637                 gst_buffer_fill (buf, 0, data + 8, len);
12638                 gst_caps_set_simple (entry->caps,
12639                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12640                 gst_buffer_unref (buf);
12641               }
12642             }
12643             break;
12644           }
12645           case FOURCC_SVQ3:
12646           case FOURCC_VP31:
12647           {
12648             GstBuffer *buf;
12649             GstBuffer *seqh = NULL;
12650             const guint8 *gamma_data = NULL;
12651             guint len = QT_UINT32 (stsd_data);  /* FIXME review - why put the whole stsd in codec data? */
12652
12653             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
12654                 &seqh);
12655             if (gamma_data) {
12656               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
12657                   QT_FP32 (gamma_data), NULL);
12658             }
12659             if (seqh) {
12660               /* sorry for the bad name, but we don't know what this is, other
12661                * than its own fourcc */
12662               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
12663                   NULL);
12664               gst_buffer_unref (seqh);
12665             }
12666
12667             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
12668             buf = gst_buffer_new_and_alloc (len);
12669             gst_buffer_fill (buf, 0, stsd_data, len);
12670             gst_caps_set_simple (entry->caps,
12671                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12672             gst_buffer_unref (buf);
12673             break;
12674           }
12675           case FOURCC_jpeg:
12676           {
12677             /* https://developer.apple.com/standards/qtff-2001.pdf,
12678              * page 92, "Video Sample Description", under table 3.1 */
12679             GstByteReader br;
12680
12681             const gint compressor_offset =
12682                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
12683             const gint min_size = compressor_offset + 32 + 2 + 2;
12684             GNode *jpeg;
12685             guint32 len;
12686             guint16 color_table_id = 0;
12687             gboolean ok;
12688
12689             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
12690
12691             /* recover information on interlaced/progressive */
12692             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
12693             if (!jpeg)
12694               break;
12695
12696             len = QT_UINT32 (jpeg->data);
12697             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
12698                 min_size);
12699             if (len >= min_size) {
12700               gst_byte_reader_init (&br, jpeg->data, len);
12701
12702               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
12703               gst_byte_reader_get_uint16_le (&br, &color_table_id);
12704               if (color_table_id != 0) {
12705                 /* the spec says there can be concatenated chunks in the data, and we want
12706                  * to find one called field. Walk through them. */
12707                 gint offset = min_size;
12708                 while (offset + 8 < len) {
12709                   guint32 size = 0, tag;
12710                   ok = gst_byte_reader_get_uint32_le (&br, &size);
12711                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12712                   if (!ok || size < 8) {
12713                     GST_WARNING_OBJECT (qtdemux,
12714                         "Failed to walk optional chunk list");
12715                     break;
12716                   }
12717                   GST_DEBUG_OBJECT (qtdemux,
12718                       "Found optional %4.4s chunk, size %u",
12719                       (const char *) &tag, size);
12720                   if (tag == FOURCC_fiel) {
12721                     guint8 n_fields = 0, ordering = 0;
12722                     gst_byte_reader_get_uint8 (&br, &n_fields);
12723                     gst_byte_reader_get_uint8 (&br, &ordering);
12724                     if (n_fields == 1 || n_fields == 2) {
12725                       GST_DEBUG_OBJECT (qtdemux,
12726                           "Found fiel tag with %u fields, ordering %u",
12727                           n_fields, ordering);
12728                       if (n_fields == 2)
12729                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
12730                             "interlace-mode", G_TYPE_STRING, "interleaved",
12731                             NULL);
12732                     } else {
12733                       GST_WARNING_OBJECT (qtdemux,
12734                           "Found fiel tag with invalid fields (%u)", n_fields);
12735                     }
12736                   }
12737                   offset += size;
12738                 }
12739               } else {
12740                 GST_DEBUG_OBJECT (qtdemux,
12741                     "Color table ID is 0, not trying to get interlacedness");
12742               }
12743             } else {
12744               GST_WARNING_OBJECT (qtdemux,
12745                   "Length of jpeg chunk is too small, not trying to get interlacedness");
12746             }
12747
12748             break;
12749           }
12750           case FOURCC_rle_:
12751           case FOURCC_WRLE:
12752           {
12753             gst_caps_set_simple (entry->caps,
12754                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12755                 NULL);
12756             break;
12757           }
12758           case FOURCC_XiTh:
12759           {
12760             GNode *xith, *xdxt;
12761
12762             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12763             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12764             if (!xith)
12765               break;
12766
12767             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12768             if (!xdxt)
12769               break;
12770
12771             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12772             /* collect the headers and store them in a stream list so that we can
12773              * send them out first */
12774             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12775             break;
12776           }
12777           case FOURCC_ovc1:
12778           {
12779             GNode *ovc1;
12780             guint8 *ovc1_data;
12781             guint ovc1_len;
12782             GstBuffer *buf;
12783
12784             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12785             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12786             if (!ovc1)
12787               break;
12788             ovc1_data = ovc1->data;
12789             ovc1_len = QT_UINT32 (ovc1_data);
12790             if (ovc1_len <= 198) {
12791               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12792               break;
12793             }
12794             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12795             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12796             gst_caps_set_simple (entry->caps,
12797                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12798             gst_buffer_unref (buf);
12799             break;
12800           }
12801           case FOURCC_vc_1:
12802           {
12803             guint len = QT_UINT32 (stsd_entry_data);
12804             len = len <= 0x56 ? 0 : len - 0x56;
12805             const guint8 *vc1_data = stsd_entry_data + 0x56;
12806
12807             /* find dvc1 */
12808             while (len >= 8) {
12809               guint size;
12810
12811               if (QT_UINT32 (vc1_data) <= 8)
12812                 size = 0;
12813               else if (QT_UINT32 (vc1_data) <= len)
12814                 size = QT_UINT32 (vc1_data) - 8;
12815               else
12816                 size = len - 8;
12817
12818               if (size < 1)
12819                 /* No real data, so break out */
12820                 break;
12821
12822               switch (QT_FOURCC (vc1_data + 0x4)) {
12823                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12824                 {
12825                   GstBuffer *buf;
12826
12827                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12828                   buf = gst_buffer_new_and_alloc (size);
12829                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
12830                   gst_caps_set_simple (entry->caps,
12831                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12832                   gst_buffer_unref (buf);
12833                   break;
12834                 }
12835                 default:
12836                   break;
12837               }
12838               len -= size + 8;
12839               vc1_data += size + 8;
12840             }
12841             break;
12842           }
12843           case FOURCC_av01:
12844           {
12845             guint len = QT_UINT32 (stsd_entry_data);
12846             len = len <= 0x56 ? 0 : len - 0x56;
12847             const guint8 *av1_data = stsd_entry_data + 0x56;
12848
12849             /* find av1C */
12850             while (len >= 0x8) {
12851               guint size;
12852
12853               if (QT_UINT32 (av1_data) <= 0x8)
12854                 size = 0;
12855               else if (QT_UINT32 (av1_data) <= len)
12856                 size = QT_UINT32 (av1_data) - 0x8;
12857               else
12858                 size = len - 0x8;
12859
12860               if (size < 1)
12861                 /* No real data, so break out */
12862                 break;
12863
12864               switch (QT_FOURCC (av1_data + 0x4)) {
12865                 case FOURCC_av1C:
12866                 {
12867                   /* parse, if found */
12868                   GstBuffer *buf;
12869
12870                   GST_DEBUG_OBJECT (qtdemux,
12871                       "found av1C codec_data in stsd of size %d", size);
12872
12873                   /* not enough data, just ignore and hope for the best */
12874                   if (size < 4)
12875                     break;
12876
12877                   /* Content is:
12878                    * 4 bytes: atom length
12879                    * 4 bytes: fourcc
12880                    *
12881                    * version 1 (marker=1):
12882                    *
12883                    *  unsigned int (1) marker = 1;
12884                    *  unsigned int (7) version = 1;
12885                    *  unsigned int (3) seq_profile;
12886                    *  unsigned int (5) seq_level_idx_0;
12887                    *  unsigned int (1) seq_tier_0;
12888                    *  unsigned int (1) high_bitdepth;
12889                    *  unsigned int (1) twelve_bit;
12890                    *  unsigned int (1) monochrome;
12891                    *  unsigned int (1) chroma_subsampling_x;
12892                    *  unsigned int (1) chroma_subsampling_y;
12893                    *  unsigned int (2) chroma_sample_position;
12894                    *  unsigned int (3) reserved = 0;
12895                    *
12896                    *  unsigned int (1) initial_presentation_delay_present;
12897                    *  if (initial_presentation_delay_present) {
12898                    *    unsigned int (4) initial_presentation_delay_minus_one;
12899                    *  } else {
12900                    *    unsigned int (4) reserved = 0;
12901                    *  }
12902                    *
12903                    *  unsigned int (8) configOBUs[];
12904                    *
12905                    * rest: OBUs.
12906                    */
12907
12908                   switch (av1_data[8]) {
12909                     case 0x81:{
12910                       guint8 pres_delay_field;
12911
12912                       /* We let profile and the other parts be figured out by
12913                        * av1parse and only include the presentation delay here
12914                        * if present */
12915                       /* We skip initial_presentation_delay* for now */
12916                       pres_delay_field = *(av1_data + 11);
12917                       if (pres_delay_field & (1 << 5)) {
12918                         gst_caps_set_simple (entry->caps,
12919                             "presentation-delay", G_TYPE_INT,
12920                             (gint) (pres_delay_field & 0x0F) + 1, NULL);
12921                       }
12922
12923                       buf = gst_buffer_new_and_alloc (size);
12924                       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12925                       gst_buffer_fill (buf, 0, av1_data + 8, size);
12926                       gst_caps_set_simple (entry->caps,
12927                           "codec_data", GST_TYPE_BUFFER, buf, NULL);
12928                       gst_buffer_unref (buf);
12929                       break;
12930                     }
12931                     default:
12932                       GST_WARNING ("Unknown version 0x%02x of av1C box",
12933                           av1_data[8]);
12934                       break;
12935                   }
12936
12937                   break;
12938                 }
12939                 default:
12940                   break;
12941               }
12942
12943               len -= size + 8;
12944               av1_data += size + 8;
12945             }
12946
12947             break;
12948           }
12949
12950             /* TODO: Need to parse vpcC for VP8 codec too.
12951              * Note that VPCodecConfigurationBox (vpcC) is defined for
12952              * vp08, vp09, and vp10 fourcc. */
12953           case FOURCC_vp09:
12954           {
12955             guint len = QT_UINT32 (stsd_entry_data);
12956             len = len <= 0x56 ? 0 : len - 0x56;
12957             const guint8 *vpcc_data = stsd_entry_data + 0x56;
12958
12959             /* find vpcC */
12960             while (len >= 0x8) {
12961               guint size;
12962
12963               if (QT_UINT32 (vpcc_data) <= 0x8)
12964                 size = 0;
12965               else if (QT_UINT32 (vpcc_data) <= len)
12966                 size = QT_UINT32 (vpcc_data) - 0x8;
12967               else
12968                 size = len - 0x8;
12969
12970               if (size < 1)
12971                 /* No real data, so break out */
12972                 break;
12973
12974               switch (QT_FOURCC (vpcc_data + 0x4)) {
12975                 case FOURCC_vpcC:
12976                 {
12977                   const gchar *profile_str = NULL;
12978                   const gchar *chroma_format_str = NULL;
12979                   guint8 profile;
12980                   guint8 bitdepth;
12981                   guint8 chroma_format;
12982                   GstVideoColorimetry cinfo;
12983
12984                   /* parse, if found */
12985                   GST_DEBUG_OBJECT (qtdemux,
12986                       "found vp codec_data in stsd of size %d", size);
12987
12988                   /* the meaning of "size" is length of the atom body, excluding
12989                    * atom length and fourcc fields */
12990                   if (size < 12)
12991                     break;
12992
12993                   /* Content is:
12994                    * 4 bytes: atom length
12995                    * 4 bytes: fourcc
12996                    * 1 byte: version
12997                    * 3 bytes: flags
12998                    * 1 byte: profile
12999                    * 1 byte: level
13000                    * 4 bits: bitDepth
13001                    * 3 bits: chromaSubsampling
13002                    * 1 bit: videoFullRangeFlag
13003                    * 1 byte: colourPrimaries
13004                    * 1 byte: transferCharacteristics
13005                    * 1 byte: matrixCoefficients
13006                    * 2 bytes: codecIntializationDataSize (should be zero for vp8 and vp9)
13007                    * rest: codecIntializationData (not used for vp8 and vp9)
13008                    */
13009
13010                   if (vpcc_data[8] != 1) {
13011                     GST_WARNING_OBJECT (qtdemux,
13012                         "unknown vpcC version %d", vpcc_data[8]);
13013                     break;
13014                   }
13015
13016                   profile = vpcc_data[12];
13017                   switch (profile) {
13018                     case 0:
13019                       profile_str = "0";
13020                       break;
13021                     case 1:
13022                       profile_str = "1";
13023                       break;
13024                     case 2:
13025                       profile_str = "2";
13026                       break;
13027                     case 3:
13028                       profile_str = "3";
13029                       break;
13030                     default:
13031                       break;
13032                   }
13033
13034                   if (profile_str) {
13035                     gst_caps_set_simple (entry->caps,
13036                         "profile", G_TYPE_STRING, profile_str, NULL);
13037                   }
13038
13039                   /* skip level, the VP9 spec v0.6 defines only one level atm,
13040                    * but webm spec define various ones. Add level to caps
13041                    * if we really need it then */
13042
13043                   bitdepth = (vpcc_data[14] & 0xf0) >> 4;
13044                   if (bitdepth == 8 || bitdepth == 10 || bitdepth == 12) {
13045                     gst_caps_set_simple (entry->caps,
13046                         "bit-depth-luma", G_TYPE_UINT, bitdepth,
13047                         "bit-depth-chroma", G_TYPE_UINT, bitdepth, NULL);
13048                   }
13049
13050                   chroma_format = (vpcc_data[14] & 0xe) >> 1;
13051                   switch (chroma_format) {
13052                     case 0:
13053                     case 1:
13054                       chroma_format_str = "4:2:0";
13055                       break;
13056                     case 2:
13057                       chroma_format_str = "4:2:2";
13058                       break;
13059                     case 3:
13060                       chroma_format_str = "4:4:4";
13061                       break;
13062                     default:
13063                       break;
13064                   }
13065
13066                   if (chroma_format_str) {
13067                     gst_caps_set_simple (entry->caps,
13068                         "chroma-format", G_TYPE_STRING, chroma_format_str,
13069                         NULL);
13070                   }
13071
13072                   if ((vpcc_data[14] & 0x1) != 0)
13073                     cinfo.range = GST_VIDEO_COLOR_RANGE_0_255;
13074                   else
13075                     cinfo.range = GST_VIDEO_COLOR_RANGE_16_235;
13076                   cinfo.primaries =
13077                       gst_video_color_primaries_from_iso (vpcc_data[15]);
13078                   cinfo.transfer =
13079                       gst_video_transfer_function_from_iso (vpcc_data[16]);
13080                   cinfo.matrix =
13081                       gst_video_color_matrix_from_iso (vpcc_data[17]);
13082
13083                   if (cinfo.primaries != GST_VIDEO_COLOR_PRIMARIES_UNKNOWN &&
13084                       cinfo.transfer != GST_VIDEO_TRANSFER_UNKNOWN &&
13085                       cinfo.matrix != GST_VIDEO_COLOR_MATRIX_UNKNOWN) {
13086                     /* set this only if all values are known, otherwise this
13087                      * might overwrite valid ones parsed from other color box */
13088                     CUR_STREAM (stream)->colorimetry = cinfo;
13089                   }
13090                   break;
13091                 }
13092                 default:
13093                   break;
13094               }
13095
13096               len -= size + 8;
13097               vpcc_data += size + 8;
13098             }
13099
13100             break;
13101           }
13102           default:
13103             break;
13104         }
13105       }
13106
13107       GST_INFO_OBJECT (qtdemux,
13108           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13109           GST_FOURCC_ARGS (fourcc), entry->caps);
13110
13111     } else if (stream->subtype == FOURCC_soun) {
13112       GNode *wave;
13113       guint version, samplesize;
13114       guint16 compression_id;
13115       gboolean amrwb = FALSE;
13116
13117       offset = 16;
13118       /* sample description entry (16) + sound sample description v0 (20) */
13119       if (len < 36)
13120         goto corrupt_file;
13121
13122       version = QT_UINT32 (stsd_entry_data + offset);
13123       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
13124       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
13125       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
13126       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
13127
13128       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
13129       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
13130           QT_UINT32 (stsd_entry_data + offset + 4));
13131       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
13132       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
13133       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
13134       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
13135           QT_UINT16 (stsd_entry_data + offset + 14));
13136       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
13137
13138       if (compression_id == 0xfffe)
13139         entry->sampled = TRUE;
13140
13141       /* first assume uncompressed audio */
13142       entry->bytes_per_sample = samplesize / 8;
13143       entry->samples_per_frame = entry->n_channels;
13144       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
13145       entry->samples_per_packet = entry->samples_per_frame;
13146       entry->bytes_per_packet = entry->bytes_per_sample;
13147
13148       offset = 36;
13149
13150       if (version == 0x00010000) {
13151         /* sample description entry (16) + sound sample description v1 (20+16) */
13152         if (len < 52)
13153           goto corrupt_file;
13154
13155         /* take information from here over the normal sample description */
13156         entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
13157         entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
13158         entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
13159         entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
13160
13161         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 1");
13162         GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
13163             entry->samples_per_packet);
13164         GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
13165             entry->bytes_per_packet);
13166         GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
13167             entry->bytes_per_frame);
13168         GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
13169             entry->bytes_per_sample);
13170
13171         if (!entry->sampled && entry->bytes_per_packet) {
13172           entry->samples_per_frame = (entry->bytes_per_frame /
13173               entry->bytes_per_packet) * entry->samples_per_packet;
13174           GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
13175               entry->samples_per_frame);
13176         }
13177       } else if (version == 0x00020000) {
13178         /* sample description entry (16) + sound sample description v2 (56) */
13179         if (len < 72)
13180           goto corrupt_file;
13181
13182         /* take information from here over the normal sample description */
13183         entry->rate = GST_READ_DOUBLE_BE (stsd_entry_data + offset + 4);
13184         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
13185         entry->samples_per_frame = entry->n_channels;
13186         entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 20) / 8;
13187         entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 28);
13188         entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset + 32);
13189         entry->bytes_per_frame = entry->bytes_per_sample * entry->n_channels;
13190
13191         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
13192         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
13193         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
13194         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
13195             entry->bytes_per_sample * 8);
13196         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
13197             QT_UINT32 (stsd_entry_data + offset + 24));
13198         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
13199             entry->bytes_per_packet);
13200         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
13201             entry->samples_per_packet);
13202       } else if (version != 0x00000) {
13203         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
13204             version);
13205       }
13206
13207       switch (fourcc) {
13208           /* Yes, these have to be hard-coded */
13209         case FOURCC_MAC6:
13210         {
13211           entry->samples_per_packet = 6;
13212           entry->bytes_per_packet = 1;
13213           entry->bytes_per_frame = 1 * entry->n_channels;
13214           entry->bytes_per_sample = 1;
13215           entry->samples_per_frame = 6 * entry->n_channels;
13216           break;
13217         }
13218         case FOURCC_MAC3:
13219         {
13220           entry->samples_per_packet = 3;
13221           entry->bytes_per_packet = 1;
13222           entry->bytes_per_frame = 1 * entry->n_channels;
13223           entry->bytes_per_sample = 1;
13224           entry->samples_per_frame = 3 * entry->n_channels;
13225           break;
13226         }
13227         case FOURCC_ima4:
13228         {
13229           entry->samples_per_packet = 64;
13230           entry->bytes_per_packet = 34;
13231           entry->bytes_per_frame = 34 * entry->n_channels;
13232           entry->bytes_per_sample = 2;
13233           entry->samples_per_frame = 64 * entry->n_channels;
13234           break;
13235         }
13236         case FOURCC_ulaw:
13237         case FOURCC_alaw:
13238         {
13239           entry->samples_per_packet = 1;
13240           entry->bytes_per_packet = 1;
13241           entry->bytes_per_frame = 1 * entry->n_channels;
13242           entry->bytes_per_sample = 1;
13243           entry->samples_per_frame = 1 * entry->n_channels;
13244           break;
13245         }
13246         case FOURCC_agsm:
13247         {
13248           entry->samples_per_packet = 160;
13249           entry->bytes_per_packet = 33;
13250           entry->bytes_per_frame = 33 * entry->n_channels;
13251           entry->bytes_per_sample = 2;
13252           entry->samples_per_frame = 160 * entry->n_channels;
13253           break;
13254         }
13255           /* fix up any invalid header information from above */
13256         case FOURCC_twos:
13257         case FOURCC_sowt:
13258         case FOURCC_raw_:
13259         case FOURCC_lpcm:
13260           /* Sometimes these are set to 0 in the sound sample descriptions so
13261            * let's try to infer useful values from the other information we
13262            * have available */
13263           if (entry->bytes_per_sample == 0)
13264             entry->bytes_per_sample =
13265                 entry->bytes_per_frame / entry->n_channels;
13266           if (entry->bytes_per_sample == 0)
13267             entry->bytes_per_sample = samplesize / 8;
13268
13269           if (entry->bytes_per_frame == 0)
13270             entry->bytes_per_frame =
13271                 entry->bytes_per_sample * entry->n_channels;
13272
13273           if (entry->bytes_per_packet == 0)
13274             entry->bytes_per_packet = entry->bytes_per_sample;
13275
13276           if (entry->samples_per_frame == 0)
13277             entry->samples_per_frame = entry->n_channels;
13278
13279           if (entry->samples_per_packet == 0)
13280             entry->samples_per_packet = entry->samples_per_frame;
13281
13282           break;
13283         case FOURCC_in24:
13284         case FOURCC_in32:
13285         case FOURCC_fl32:
13286         case FOURCC_fl64:
13287         case FOURCC_s16l:{
13288           switch (fourcc) {
13289             case FOURCC_in24:
13290               entry->bytes_per_sample = 3;
13291               break;
13292             case FOURCC_in32:
13293             case FOURCC_fl32:
13294               entry->bytes_per_sample = 4;
13295               break;
13296             case FOURCC_fl64:
13297               entry->bytes_per_sample = 8;
13298               break;
13299             case FOURCC_s16l:
13300               entry->bytes_per_sample = 2;
13301               break;
13302             default:
13303               g_assert_not_reached ();
13304               break;
13305           }
13306           entry->samples_per_frame = entry->n_channels;
13307           entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
13308           entry->samples_per_packet = entry->samples_per_frame;
13309           entry->bytes_per_packet = entry->bytes_per_sample;
13310           break;
13311         }
13312
13313           /* According to TS 102 366, the channel count in
13314            * a (E)AC3SampleEntry box is to be ignored */
13315         case 0x20736d:
13316         case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13317         case GST_MAKE_FOURCC ('s', 'a', 'c', '3'):     // Nero Recode
13318         case FOURCC_ac_3:
13319           entry->n_channels = 0;
13320           break;
13321
13322         default:
13323           break;
13324       }
13325
13326       if (entry->caps)
13327         gst_caps_unref (entry->caps);
13328
13329       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
13330           stsd_entry_data + 32, len - 16, &codec);
13331
13332       switch (fourcc) {
13333         case FOURCC_in24:
13334         case FOURCC_in32:
13335         case FOURCC_fl32:
13336         case FOURCC_fl64:
13337         {
13338           GNode *enda;
13339           GNode *fmt;
13340
13341           fmt = qtdemux_tree_get_child_by_type (stsd, fourcc);
13342
13343           enda = qtdemux_tree_get_child_by_type (fmt, FOURCC_enda);
13344           if (!enda) {
13345             wave = qtdemux_tree_get_child_by_type (fmt, FOURCC_wave);
13346             if (wave)
13347               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
13348           }
13349           if (enda) {
13350             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
13351             const gchar *format_str;
13352
13353             switch (fourcc) {
13354               case FOURCC_in24:
13355                 format_str = (enda_value) ? "S24LE" : "S24BE";
13356                 break;
13357               case FOURCC_in32:
13358                 format_str = (enda_value) ? "S32LE" : "S32BE";
13359                 break;
13360               case FOURCC_fl32:
13361                 format_str = (enda_value) ? "F32LE" : "F32BE";
13362                 break;
13363               case FOURCC_fl64:
13364                 format_str = (enda_value) ? "F64LE" : "F64BE";
13365                 break;
13366               default:
13367                 g_assert_not_reached ();
13368                 break;
13369             }
13370             gst_caps_set_simple (entry->caps,
13371                 "format", G_TYPE_STRING, format_str, NULL);
13372           }
13373           break;
13374         }
13375         case FOURCC_owma:
13376         {
13377           const guint8 *owma_data;
13378           const gchar *codec_name = NULL;
13379           guint owma_len;
13380           GstBuffer *buf;
13381           gint version = 1;
13382           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
13383           /* FIXME this should also be gst_riff_strf_auds,
13384            * but the latter one is actually missing bits-per-sample :( */
13385           typedef struct
13386           {
13387             gint16 wFormatTag;
13388             gint16 nChannels;
13389             gint32 nSamplesPerSec;
13390             gint32 nAvgBytesPerSec;
13391             gint16 nBlockAlign;
13392             gint16 wBitsPerSample;
13393             gint16 cbSize;
13394           } WAVEFORMATEX;
13395           WAVEFORMATEX *wfex;
13396
13397           GST_DEBUG_OBJECT (qtdemux, "parse owma");
13398           owma_data = stsd_entry_data;
13399           owma_len = QT_UINT32 (owma_data);
13400           if (owma_len <= 54) {
13401             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
13402             break;
13403           }
13404           wfex = (WAVEFORMATEX *) (owma_data + 36);
13405           buf = gst_buffer_new_and_alloc (owma_len - 54);
13406           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
13407           if (wfex->wFormatTag == 0x0161) {
13408             codec_name = "Windows Media Audio";
13409             version = 2;
13410           } else if (wfex->wFormatTag == 0x0162) {
13411             codec_name = "Windows Media Audio 9 Pro";
13412             version = 3;
13413           } else if (wfex->wFormatTag == 0x0163) {
13414             codec_name = "Windows Media Audio 9 Lossless";
13415             /* is that correct? gstffmpegcodecmap.c is missing it, but
13416              * fluendo codec seems to support it */
13417             version = 4;
13418           }
13419
13420           gst_caps_set_simple (entry->caps,
13421               "codec_data", GST_TYPE_BUFFER, buf,
13422               "wmaversion", G_TYPE_INT, version,
13423               "block_align", G_TYPE_INT,
13424               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
13425               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
13426               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
13427               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
13428           gst_buffer_unref (buf);
13429
13430           if (codec_name) {
13431             g_free (codec);
13432             codec = g_strdup (codec_name);
13433           }
13434           break;
13435         }
13436         case FOURCC_wma_:
13437         {
13438           guint len = QT_UINT32 (stsd_entry_data);
13439           len = len <= offset ? 0 : len - offset;
13440           const guint8 *wfex_data = stsd_entry_data + offset;
13441           const gchar *codec_name = NULL;
13442           gint version = 1;
13443           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
13444           /* FIXME this should also be gst_riff_strf_auds,
13445            * but the latter one is actually missing bits-per-sample :( */
13446           typedef struct
13447           {
13448             gint16 wFormatTag;
13449             gint16 nChannels;
13450             gint32 nSamplesPerSec;
13451             gint32 nAvgBytesPerSec;
13452             gint16 nBlockAlign;
13453             gint16 wBitsPerSample;
13454             gint16 cbSize;
13455           } WAVEFORMATEX;
13456           WAVEFORMATEX wfex;
13457
13458           /* FIXME: unify with similar wavformatex parsing code above */
13459           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
13460
13461           /* find wfex */
13462           while (len >= 8) {
13463             guint size;
13464
13465             if (QT_UINT32 (wfex_data) <= 0x8)
13466               size = 0;
13467             else if (QT_UINT32 (wfex_data) <= len)
13468               size = QT_UINT32 (wfex_data) - 8;
13469             else
13470               size = len - 8;
13471
13472             if (size < 1)
13473               /* No real data, so break out */
13474               break;
13475
13476             switch (QT_FOURCC (wfex_data + 4)) {
13477               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
13478               {
13479                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
13480
13481                 if (size < 8 + 18)
13482                   break;
13483
13484                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
13485                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
13486                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
13487                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
13488                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
13489                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
13490                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
13491
13492                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
13493                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
13494                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
13495                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
13496                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
13497                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
13498
13499                 if (wfex.wFormatTag == 0x0161) {
13500                   codec_name = "Windows Media Audio";
13501                   version = 2;
13502                 } else if (wfex.wFormatTag == 0x0162) {
13503                   codec_name = "Windows Media Audio 9 Pro";
13504                   version = 3;
13505                 } else if (wfex.wFormatTag == 0x0163) {
13506                   codec_name = "Windows Media Audio 9 Lossless";
13507                   /* is that correct? gstffmpegcodecmap.c is missing it, but
13508                    * fluendo codec seems to support it */
13509                   version = 4;
13510                 }
13511
13512                 gst_caps_set_simple (entry->caps,
13513                     "wmaversion", G_TYPE_INT, version,
13514                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
13515                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
13516                     "width", G_TYPE_INT, wfex.wBitsPerSample,
13517                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
13518
13519                 if (size > wfex.cbSize) {
13520                   GstBuffer *buf;
13521
13522                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
13523                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
13524                       size - wfex.cbSize);
13525                   gst_caps_set_simple (entry->caps,
13526                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
13527                   gst_buffer_unref (buf);
13528                 } else {
13529                   GST_WARNING_OBJECT (qtdemux, "no codec data");
13530                 }
13531
13532                 if (codec_name) {
13533                   g_free (codec);
13534                   codec = g_strdup (codec_name);
13535                 }
13536                 break;
13537               }
13538               default:
13539                 break;
13540             }
13541             len -= size + 8;
13542             wfex_data += size + 8;
13543           }
13544           break;
13545         }
13546         case FOURCC_opus:
13547         {
13548           guint8 *channel_mapping = NULL;
13549           guint32 dops_len, rate;
13550           guint8 n_channels;
13551           guint8 channel_mapping_family;
13552           guint8 stream_count;
13553           guint8 coupled_count;
13554           guint8 i;
13555
13556           GNode *opus;
13557           GNode *dops;
13558
13559           opus = qtdemux_tree_get_child_by_type (stsd, FOURCC_opus);
13560           if (opus == NULL) {
13561             GST_WARNING_OBJECT (qtdemux, "Opus Sample Entry not found");
13562             goto corrupt_file;
13563           }
13564
13565           dops = qtdemux_tree_get_child_by_type (opus, FOURCC_dops);
13566           if (dops == NULL) {
13567             GST_WARNING_OBJECT (qtdemux, "Opus Specific Box not found");
13568             goto corrupt_file;
13569           }
13570
13571           /* Opus Specific Box content:
13572            * 4 bytes: length
13573            * 4 bytes: "dOps"
13574            * 1 byte: Version;
13575            * 1 byte: OutputChannelCount;
13576            * 2 bytes: PreSkip (big-endians);
13577            * 4 bytes: InputSampleRate (big-endians);
13578            * 2 bytes: OutputGain (big-endians);
13579            * 1 byte: ChannelMappingFamily;
13580            * if (ChannelMappingFamily != 0) {
13581            *   1 byte: StreamCount;
13582            *   1 byte: CoupledCount;
13583            *   for (OutputChannel in 0..OutputChannelCount) {
13584            *     1 byte: ChannelMapping;
13585            *   }
13586            * }
13587            */
13588
13589           dops_len = QT_UINT32 ((guint8 *) dops->data);
13590           if (len < offset + dops_len) {
13591             GST_WARNING_OBJECT (qtdemux,
13592                 "Opus Sample Entry has bogus size %" G_GUINT32_FORMAT, len);
13593             goto corrupt_file;
13594           }
13595           if (dops_len < 19) {
13596             GST_WARNING_OBJECT (qtdemux,
13597                 "Opus Specific Box has bogus size %" G_GUINT32_FORMAT,
13598                 dops_len);
13599             goto corrupt_file;
13600           }
13601
13602           n_channels = GST_READ_UINT8 ((guint8 *) dops->data + 9);
13603           rate = GST_READ_UINT32_BE ((guint8 *) dops->data + 12);
13604           channel_mapping_family = GST_READ_UINT8 ((guint8 *) dops->data + 18);
13605
13606           if (channel_mapping_family != 0) {
13607             if (dops_len < 21 + n_channels) {
13608               GST_WARNING_OBJECT (qtdemux,
13609                   "Opus Specific Box has bogus size %" G_GUINT32_FORMAT,
13610                   dops_len);
13611               goto corrupt_file;
13612             }
13613
13614             stream_count = GST_READ_UINT8 ((guint8 *) dops->data + 19);
13615             coupled_count = GST_READ_UINT8 ((guint8 *) dops->data + 20);
13616
13617             if (n_channels > 0) {
13618               channel_mapping = g_malloc (n_channels * sizeof (guint8));
13619               for (i = 0; i < n_channels; i++)
13620                 channel_mapping[i] =
13621                     GST_READ_UINT8 ((guint8 *) dops->data + i + 21);
13622             }
13623           } else if (n_channels == 1) {
13624             stream_count = 1;
13625             coupled_count = 0;
13626           } else if (n_channels == 2) {
13627             stream_count = 1;
13628             coupled_count = 1;
13629           } else {
13630             GST_WARNING_OBJECT (qtdemux,
13631                 "Opus unexpected nb of channels %d without channel mapping",
13632                 n_channels);
13633             goto corrupt_file;
13634           }
13635
13636           entry->caps = gst_codec_utils_opus_create_caps (rate, n_channels,
13637               channel_mapping_family, stream_count, coupled_count,
13638               channel_mapping);
13639           g_free (channel_mapping);
13640
13641           entry->sampled = TRUE;
13642
13643           break;
13644         }
13645         default:
13646           break;
13647       }
13648
13649       if (codec) {
13650         GstStructure *s;
13651         gint bitrate = 0;
13652
13653         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13654             GST_TAG_AUDIO_CODEC, codec, NULL);
13655         g_free (codec);
13656         codec = NULL;
13657
13658         /* some bitrate info may have ended up in caps */
13659         s = gst_caps_get_structure (entry->caps, 0);
13660         gst_structure_get_int (s, "bitrate", &bitrate);
13661         if (bitrate > 0)
13662           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13663               GST_TAG_BITRATE, bitrate, NULL);
13664       }
13665
13666       esds = NULL;
13667       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
13668       if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
13669         if (stream->protected) {
13670           if (QTDEMUX_TREE_NODE_FOURCC (mp4a) == FOURCC_aavd) {
13671             esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
13672           }
13673           if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
13674             mp4a = NULL;
13675           }
13676         } else {
13677           mp4a = NULL;
13678         }
13679       }
13680
13681       wave = NULL;
13682       if (mp4a) {
13683         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
13684         if (wave)
13685           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
13686         if (!esds)
13687           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
13688       }
13689
13690
13691       /* If the fourcc's bottom 16 bits gives 'sm', then the top
13692          16 bits is a byte-swapped wave-style codec identifier,
13693          and we can find a WAVE header internally to a 'wave' atom here.
13694          This can more clearly be thought of as 'ms' as the top 16 bits, and a
13695          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
13696          is big-endian).
13697        */
13698       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
13699         if (len < offset + 20) {
13700           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
13701         } else {
13702           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
13703           const guint8 *data = stsd_entry_data + offset + 16;
13704           GNode *wavenode;
13705           GNode *waveheadernode;
13706
13707           wavenode = g_node_new ((guint8 *) data);
13708           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
13709             const guint8 *waveheader;
13710             guint32 headerlen;
13711
13712             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
13713             if (waveheadernode) {
13714               waveheader = (const guint8 *) waveheadernode->data;
13715               headerlen = QT_UINT32 (waveheader);
13716
13717               if (headerlen > 8) {
13718                 gst_riff_strf_auds *header = NULL;
13719                 GstBuffer *headerbuf;
13720                 GstBuffer *extra;
13721
13722                 waveheader += 8;
13723                 headerlen -= 8;
13724
13725                 headerbuf = gst_buffer_new_and_alloc (headerlen);
13726                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
13727
13728                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
13729                         headerbuf, &header, &extra)) {
13730                   gst_caps_unref (entry->caps);
13731                   /* FIXME: Need to do something with the channel reorder map */
13732                   entry->caps =
13733                       gst_riff_create_audio_caps (header->format, NULL, header,
13734                       extra, NULL, NULL, NULL);
13735
13736                   if (extra)
13737                     gst_buffer_unref (extra);
13738                   g_free (header);
13739                 }
13740               }
13741             } else
13742               GST_DEBUG ("Didn't find waveheadernode for this codec");
13743           }
13744           g_node_destroy (wavenode);
13745         }
13746       } else if (esds) {
13747         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13748             stream->stream_tags);
13749       } else {
13750         switch (fourcc) {
13751 #if 0
13752             /* FIXME: what is in the chunk? */
13753           case FOURCC_QDMC:
13754           {
13755             gint len = QT_UINT32 (stsd_data);
13756
13757             /* seems to be always = 116 = 0x74 */
13758             break;
13759           }
13760 #endif
13761           case FOURCC_QDM2:
13762           {
13763             gint len = QT_UINT32 (stsd_entry_data);
13764
13765             if (len > 0x3C) {
13766               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
13767
13768               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
13769               gst_caps_set_simple (entry->caps,
13770                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
13771               gst_buffer_unref (buf);
13772             }
13773             gst_caps_set_simple (entry->caps,
13774                 "samplesize", G_TYPE_INT, samplesize, NULL);
13775             break;
13776           }
13777           case FOURCC_alac:
13778           {
13779             GNode *alac, *wave = NULL;
13780
13781             /* apparently, m4a has this atom appended directly in the stsd entry,
13782              * while mov has it in a wave atom */
13783             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
13784             if (alac) {
13785               /* alac now refers to stsd entry atom */
13786               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
13787               if (wave)
13788                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
13789               else
13790                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
13791             }
13792             if (alac) {
13793               const guint8 *alac_data = alac->data;
13794               gint len = QT_UINT32 (alac->data);
13795               GstBuffer *buf;
13796
13797               if (len < 36) {
13798                 GST_DEBUG_OBJECT (qtdemux,
13799                     "discarding alac atom with unexpected len %d", len);
13800               } else {
13801                 /* codec-data contains alac atom size and prefix,
13802                  * ffmpeg likes it that way, not quite gst-ish though ...*/
13803                 buf = gst_buffer_new_and_alloc (len);
13804                 gst_buffer_fill (buf, 0, alac->data, len);
13805                 gst_caps_set_simple (entry->caps,
13806                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
13807                 gst_buffer_unref (buf);
13808
13809                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
13810                 entry->n_channels = QT_UINT8 (alac_data + 21);
13811                 entry->rate = QT_UINT32 (alac_data + 32);
13812                 samplesize = QT_UINT8 (alac_data + 16 + 1);
13813               }
13814             }
13815             gst_caps_set_simple (entry->caps,
13816                 "samplesize", G_TYPE_INT, samplesize, NULL);
13817             break;
13818           }
13819           case FOURCC_fLaC:
13820           {
13821             /* The codingname of the sample entry is 'fLaC' */
13822             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
13823
13824             if (flac) {
13825               /* The 'dfLa' box is added to the sample entry to convey
13826                  initializing information for the decoder. */
13827               const GNode *dfla =
13828                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
13829
13830               if (dfla) {
13831                 const guint32 len = QT_UINT32 (dfla->data);
13832
13833                 /* Must contain at least dfLa box header (12),
13834                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
13835                 if (len < 50) {
13836                   GST_DEBUG_OBJECT (qtdemux,
13837                       "discarding dfla atom with unexpected len %d", len);
13838                 } else {
13839                   /* skip dfLa header to get the METADATA_BLOCKs */
13840                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
13841                   const guint32 metadata_blocks_len = len - 12;
13842
13843                   gchar *stream_marker = g_strdup ("fLaC");
13844                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
13845                       strlen (stream_marker));
13846
13847                   guint32 index = 0;
13848                   guint32 remainder = 0;
13849                   guint32 block_size = 0;
13850                   gboolean is_last = FALSE;
13851
13852                   GValue array = G_VALUE_INIT;
13853                   GValue value = G_VALUE_INIT;
13854
13855                   g_value_init (&array, GST_TYPE_ARRAY);
13856                   g_value_init (&value, GST_TYPE_BUFFER);
13857
13858                   gst_value_set_buffer (&value, block);
13859                   gst_value_array_append_value (&array, &value);
13860                   g_value_reset (&value);
13861
13862                   gst_buffer_unref (block);
13863
13864                   /* check there's at least one METADATA_BLOCK_HEADER's worth
13865                    * of data, and we haven't already finished parsing */
13866                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
13867                     remainder = metadata_blocks_len - index;
13868
13869                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
13870                     block_size = 4 +
13871                         (metadata_blocks[index + 1] << 16) +
13872                         (metadata_blocks[index + 2] << 8) +
13873                         metadata_blocks[index + 3];
13874
13875                     /* be careful not to read off end of box */
13876                     if (block_size > remainder) {
13877                       break;
13878                     }
13879
13880                     is_last = metadata_blocks[index] >> 7;
13881
13882                     block = gst_buffer_new_and_alloc (block_size);
13883
13884                     gst_buffer_fill (block, 0, &metadata_blocks[index],
13885                         block_size);
13886
13887                     gst_value_set_buffer (&value, block);
13888                     gst_value_array_append_value (&array, &value);
13889                     g_value_reset (&value);
13890
13891                     gst_buffer_unref (block);
13892
13893                     index += block_size;
13894                   }
13895
13896                   /* only append the metadata if we successfully read all of it */
13897                   if (is_last) {
13898                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
13899                             (stream)->caps, 0), "streamheader", &array);
13900                   } else {
13901                     GST_WARNING_OBJECT (qtdemux,
13902                         "discarding all METADATA_BLOCKs due to invalid "
13903                         "block_size %d at idx %d, rem %d", block_size, index,
13904                         remainder);
13905                   }
13906
13907                   g_value_unset (&value);
13908                   g_value_unset (&array);
13909
13910                   /* The sample rate obtained from the stsd may not be accurate
13911                    * since it cannot represent rates greater than 65535Hz, so
13912                    * override that value with the sample rate from the
13913                    * METADATA_BLOCK_STREAMINFO block */
13914                   CUR_STREAM (stream)->rate =
13915                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
13916                 }
13917               }
13918             }
13919             break;
13920           }
13921           case FOURCC_sawb:
13922             /* Fallthrough! */
13923             amrwb = TRUE;
13924           case FOURCC_samr:
13925           {
13926             gint len = QT_UINT32 (stsd_entry_data);
13927
13928             if (len > 0x24) {
13929               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
13930               guint bitrate;
13931
13932               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
13933
13934               /* If we have enough data, let's try to get the 'damr' atom. See
13935                * the 3GPP container spec (26.244) for more details. */
13936               if ((len - 0x34) > 8 &&
13937                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
13938                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13939                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
13940               }
13941
13942               gst_caps_set_simple (entry->caps,
13943                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
13944               gst_buffer_unref (buf);
13945             }
13946             break;
13947           }
13948           case FOURCC_mp4a:
13949           {
13950             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
13951             gint len = QT_UINT32 (stsd_entry_data);
13952             guint16 sound_version = 0;
13953             /* FIXME: Can this be determined somehow? There doesn't seem to be
13954              * anything in mp4a atom that specifis compression */
13955             gint profile = 2;
13956             guint16 channels = entry->n_channels;
13957             guint32 time_scale = (guint32) entry->rate;
13958             gint sample_rate_index = -1;
13959
13960             if (len >= 34) {
13961               sound_version = QT_UINT16 (stsd_entry_data + 16);
13962
13963               if (sound_version == 1) {
13964                 channels = QT_UINT16 (stsd_entry_data + 24);
13965                 time_scale = QT_UINT32 (stsd_entry_data + 30);
13966               } else {
13967                 GST_FIXME_OBJECT (qtdemux, "Unhandled mp4a atom version %d",
13968                     sound_version);
13969               }
13970             } else {
13971               GST_DEBUG_OBJECT (qtdemux, "Too small stsd entry data len %d",
13972                   len);
13973             }
13974
13975             sample_rate_index =
13976                 gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
13977             if (sample_rate_index >= 0 && channels > 0) {
13978               guint8 codec_data[2];
13979               GstBuffer *buf;
13980
13981               /* build AAC codec data */
13982               codec_data[0] = profile << 3;
13983               codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
13984               codec_data[1] = (sample_rate_index & 0x01) << 7;
13985               codec_data[1] |= (channels & 0xF) << 3;
13986
13987               buf = gst_buffer_new_and_alloc (2);
13988               gst_buffer_fill (buf, 0, codec_data, 2);
13989               gst_caps_set_simple (entry->caps,
13990                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
13991               gst_buffer_unref (buf);
13992             }
13993             break;
13994           }
13995           case FOURCC_opus:
13996           case FOURCC_lpcm:
13997           case FOURCC_in24:
13998           case FOURCC_in32:
13999           case FOURCC_fl32:
14000           case FOURCC_fl64:
14001           case FOURCC_s16l:
14002             /* Fully handled elsewhere */
14003             break;
14004           default:
14005             GST_INFO_OBJECT (qtdemux,
14006                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14007             break;
14008         }
14009       }
14010       GST_INFO_OBJECT (qtdemux,
14011           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
14012           GST_FOURCC_ARGS (fourcc), entry->caps);
14013
14014     } else if (stream->subtype == FOURCC_strm) {
14015       if (fourcc == FOURCC_rtsp) {
14016         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
14017       } else {
14018         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
14019             GST_FOURCC_ARGS (fourcc));
14020         goto unknown_stream;
14021       }
14022       entry->sampled = TRUE;
14023     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
14024         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
14025         || stream->subtype == FOURCC_clcp || stream->subtype == FOURCC_wvtt) {
14026
14027       entry->sampled = TRUE;
14028       entry->sparse = TRUE;
14029
14030       entry->caps =
14031           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
14032           &codec);
14033       if (codec) {
14034         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
14035             GST_TAG_SUBTITLE_CODEC, codec, NULL);
14036         g_free (codec);
14037         codec = NULL;
14038       }
14039
14040       /* hunt for sort-of codec data */
14041       switch (fourcc) {
14042         case FOURCC_mp4s:
14043         {
14044           GNode *mp4s = NULL;
14045           GNode *esds = NULL;
14046
14047           /* look for palette in a stsd->mp4s->esds sub-atom */
14048           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
14049           if (mp4s)
14050             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
14051           if (esds == NULL) {
14052             /* Invalid STSD */
14053             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
14054             break;
14055           }
14056
14057           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
14058               stream->stream_tags);
14059           break;
14060         }
14061         default:
14062           GST_INFO_OBJECT (qtdemux,
14063               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14064           break;
14065       }
14066       GST_INFO_OBJECT (qtdemux,
14067           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
14068           GST_FOURCC_ARGS (fourcc), entry->caps);
14069     } else if (stream->subtype == FOURCC_meta) {
14070       entry->sampled = TRUE;
14071       entry->sparse = TRUE;
14072
14073       entry->caps =
14074           qtdemux_meta_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
14075           &codec);
14076       if (codec) {
14077         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
14078             GST_TAG_CODEC, codec, NULL);
14079         g_free (codec);
14080         codec = NULL;
14081       }
14082
14083       GST_INFO_OBJECT (qtdemux,
14084           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
14085           GST_FOURCC_ARGS (fourcc), entry->caps);
14086     } else {
14087       /* everything in 1 sample */
14088       entry->sampled = TRUE;
14089
14090       entry->caps =
14091           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
14092           &codec);
14093
14094       if (entry->caps == NULL)
14095         goto unknown_stream;
14096
14097       if (codec) {
14098         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
14099             GST_TAG_SUBTITLE_CODEC, codec, NULL);
14100         g_free (codec);
14101         codec = NULL;
14102       }
14103     }
14104
14105     /* promote to sampled format */
14106     if (entry->fourcc == FOURCC_samr) {
14107       /* force mono 8000 Hz for AMR */
14108       entry->sampled = TRUE;
14109       entry->n_channels = 1;
14110       entry->rate = 8000;
14111     } else if (entry->fourcc == FOURCC_sawb) {
14112       /* force mono 16000 Hz for AMR-WB */
14113       entry->sampled = TRUE;
14114       entry->n_channels = 1;
14115       entry->rate = 16000;
14116     } else if (entry->fourcc == FOURCC_mp4a) {
14117       entry->sampled = TRUE;
14118     }
14119
14120
14121     stsd_entry_data += len;
14122     remaining_stsd_len -= len;
14123
14124   }
14125
14126   /* collect sample information */
14127   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
14128     goto samples_failed;
14129
14130   if (qtdemux->fragmented) {
14131     guint64 offset;
14132
14133     /* need all moov samples as basis; probably not many if any at all */
14134     /* prevent moof parsing taking of at this time */
14135     offset = qtdemux->moof_offset;
14136     qtdemux->moof_offset = 0;
14137     if (stream->n_samples &&
14138         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
14139       qtdemux->moof_offset = offset;
14140       goto samples_failed;
14141     }
14142     qtdemux->moof_offset = offset;
14143     /* movie duration more reliable in this case (e.g. mehd) */
14144     if (qtdemux->segment.duration &&
14145         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
14146       stream->duration =
14147           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
14148   }
14149
14150   /* configure segments */
14151   if (!qtdemux_parse_segments (qtdemux, stream, trak))
14152     goto segments_failed;
14153
14154   /* add some language tag, if useful */
14155   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
14156       strcmp (stream->lang_id, "und")) {
14157     const gchar *lang_code;
14158
14159     /* convert ISO 639-2 code to ISO 639-1 */
14160     lang_code = gst_tag_get_language_code (stream->lang_id);
14161     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
14162         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
14163   }
14164
14165   /* Check for UDTA tags */
14166   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
14167     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
14168   }
14169
14170   /* Insert and sort new stream in track-id order.
14171    * This will help in comparing old/new streams during stream update check */
14172   g_ptr_array_add (qtdemux->active_streams, stream);
14173   g_ptr_array_sort (qtdemux->active_streams,
14174       (GCompareFunc) qtdemux_track_id_compare_func);
14175   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
14176       QTDEMUX_N_STREAMS (qtdemux));
14177
14178   return TRUE;
14179
14180 /* ERRORS */
14181 corrupt_file:
14182   {
14183     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
14184         (_("This file is corrupt and cannot be played.")), (NULL));
14185     if (stream)
14186       gst_qtdemux_stream_unref (stream);
14187     return FALSE;
14188   }
14189 error_encrypted:
14190   {
14191     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
14192     gst_qtdemux_stream_unref (stream);
14193     return FALSE;
14194   }
14195 samples_failed:
14196 segments_failed:
14197   {
14198     /* we posted an error already */
14199     /* free stbl sub-atoms */
14200     gst_qtdemux_stbl_free (stream);
14201     gst_qtdemux_stream_unref (stream);
14202     return FALSE;
14203   }
14204 existing_stream:
14205   {
14206     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
14207         track_id);
14208     return TRUE;
14209   }
14210 unknown_stream:
14211   {
14212     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
14213         GST_FOURCC_ARGS (stream->subtype));
14214     gst_qtdemux_stream_unref (stream);
14215     return TRUE;
14216   }
14217 }
14218
14219 /* If we can estimate the overall bitrate, and don't have information about the
14220  * stream bitrate for exactly one stream, this guesses the stream bitrate as
14221  * the overall bitrate minus the sum of the bitrates of all other streams. This
14222  * should be useful for the common case where we have one audio and one video
14223  * stream and can estimate the bitrate of one, but not the other. */
14224 static void
14225 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
14226 {
14227   QtDemuxStream *stream = NULL;
14228   gint64 size, sys_bitrate, sum_bitrate = 0;
14229   GstClockTime duration;
14230   guint bitrate;
14231   gint i;
14232
14233   if (qtdemux->fragmented)
14234     return;
14235
14236   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
14237
14238   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
14239       || size <= 0) {
14240     GST_DEBUG_OBJECT (qtdemux,
14241         "Size in bytes of the stream not known - bailing");
14242     return;
14243   }
14244
14245   /* Subtract the header size */
14246   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
14247       size, qtdemux->header_size);
14248
14249   if (size < qtdemux->header_size)
14250     return;
14251
14252   size = size - qtdemux->header_size;
14253
14254   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
14255     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
14256     return;
14257   }
14258
14259   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
14260     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
14261     switch (str->subtype) {
14262       case FOURCC_soun:
14263       case FOURCC_vide:
14264         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
14265             CUR_STREAM (str)->caps);
14266         /* retrieve bitrate, prefer avg then max */
14267         bitrate = 0;
14268         if (str->stream_tags) {
14269           if (gst_tag_list_get_uint (str->stream_tags,
14270                   GST_TAG_MAXIMUM_BITRATE, &bitrate))
14271             GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
14272           if (gst_tag_list_get_uint (str->stream_tags,
14273                   GST_TAG_NOMINAL_BITRATE, &bitrate))
14274             GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
14275           if (gst_tag_list_get_uint (str->stream_tags,
14276                   GST_TAG_BITRATE, &bitrate))
14277             GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
14278         }
14279         if (bitrate)
14280           sum_bitrate += bitrate;
14281         else {
14282           if (stream) {
14283             GST_DEBUG_OBJECT (qtdemux,
14284                 ">1 stream with unknown bitrate - bailing");
14285             return;
14286           } else
14287             stream = str;
14288         }
14289
14290       default:
14291         /* For other subtypes, we assume no significant impact on bitrate */
14292         break;
14293     }
14294   }
14295
14296   if (!stream) {
14297     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
14298     return;
14299   }
14300
14301   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
14302
14303   if (sys_bitrate < sum_bitrate) {
14304     /* This can happen, since sum_bitrate might be derived from maximum
14305      * bitrates and not average bitrates */
14306     GST_DEBUG_OBJECT (qtdemux,
14307         "System bitrate less than sum bitrate - bailing");
14308     return;
14309   }
14310
14311   bitrate = sys_bitrate - sum_bitrate;
14312   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
14313       ", Stream bitrate = %u", sys_bitrate, bitrate);
14314
14315   if (!stream->stream_tags)
14316     stream->stream_tags = gst_tag_list_new_empty ();
14317   else
14318     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
14319
14320   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
14321       GST_TAG_BITRATE, bitrate, NULL);
14322 }
14323
14324 static GstFlowReturn
14325 qtdemux_prepare_streams (GstQTDemux * qtdemux)
14326 {
14327   GstFlowReturn ret = GST_FLOW_OK;
14328 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
14329   guint64 tkhd_max_duration = 0;
14330 #endif
14331   gint i;
14332
14333   GST_DEBUG_OBJECT (qtdemux, "prepare %u streams", QTDEMUX_N_STREAMS (qtdemux));
14334
14335   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
14336     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
14337     guint32 sample_num = 0;
14338
14339     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
14340         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
14341
14342     if (qtdemux->fragmented && qtdemux->pullbased) {
14343       /* need all moov samples first */
14344       GST_OBJECT_LOCK (qtdemux);
14345       while (stream->n_samples == 0)
14346         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
14347           break;
14348       GST_OBJECT_UNLOCK (qtdemux);
14349     } else {
14350       /* discard any stray moof */
14351       qtdemux->moof_offset = 0;
14352 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
14353       if (tkhd_max_duration < stream->tkhd_duration)
14354         tkhd_max_duration = stream->tkhd_duration;
14355 #endif
14356     }
14357
14358     /* prepare braking */
14359     if (ret != GST_FLOW_ERROR)
14360       ret = GST_FLOW_OK;
14361
14362     /* in pull mode, we should have parsed some sample info by now;
14363      * and quite some code will not handle no samples.
14364      * in push mode, we'll just have to deal with it */
14365     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
14366       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
14367       g_ptr_array_remove_index (qtdemux->active_streams, i);
14368       i--;
14369       continue;
14370     } else if (stream->track_id == qtdemux->chapters_track_id &&
14371         (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
14372       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
14373          so that it doesn't look like a subtitle track */
14374       g_ptr_array_remove_index (qtdemux->active_streams, i);
14375       i--;
14376       continue;
14377     }
14378
14379     /* parse the initial sample for use in setting the frame rate cap */
14380     while (sample_num == 0 && sample_num < stream->n_samples) {
14381       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
14382         break;
14383       ++sample_num;
14384     }
14385   }
14386
14387 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
14388   if (!qtdemux->fragmented && (qtdemux->duration > tkhd_max_duration)) {
14389     GST_INFO_OBJECT (qtdemux,
14390         "Update duration: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT,
14391         qtdemux->duration, tkhd_max_duration);
14392     qtdemux->duration = tkhd_max_duration;
14393   }
14394 #endif
14395
14396   return ret;
14397 }
14398
14399 static gboolean
14400 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
14401 {
14402   return g_strcmp0 (stream->stream_id, stream_id) == 0;
14403 }
14404
14405 static gboolean
14406 qtdemux_is_streams_update (GstQTDemux * qtdemux)
14407 {
14408   gint i;
14409
14410   /* Different length, updated */
14411   if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
14412     return TRUE;
14413
14414   /* streams in list are sorted in track-id order */
14415   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
14416     /* Different stream-id, updated */
14417     if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
14418             QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
14419       return TRUE;
14420   }
14421
14422   return FALSE;
14423 }
14424
14425 static gboolean
14426 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
14427     QtDemuxStream * oldstream, QtDemuxStream * newstream)
14428 {
14429   /* Connect old stream's srcpad to new stream */
14430   newstream->pad = oldstream->pad;
14431   oldstream->pad = NULL;
14432
14433   /* unset new_stream to prevent stream-start event, unless we are EOS in which
14434    * case we need to force one through */
14435   newstream->new_stream = newstream->pad != NULL
14436       && GST_PAD_IS_EOS (newstream->pad);
14437
14438   return gst_qtdemux_configure_stream (qtdemux, newstream);
14439 }
14440
14441 static gboolean
14442 qtdemux_update_streams (GstQTDemux * qtdemux)
14443 {
14444   gint i;
14445   g_assert (qtdemux->streams_aware);
14446
14447   /* At below, figure out which stream in active_streams has identical stream-id
14448    * with that of in old_streams. If there is matching stream-id,
14449    * corresponding newstream will not be exposed again,
14450    * but demux will reuse srcpad of matched old stream
14451    *
14452    * active_streams : newly created streams from the latest moov
14453    * old_streams : existing streams (belong to previous moov)
14454    */
14455
14456   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
14457     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
14458     QtDemuxStream *oldstream = NULL;
14459     guint target;
14460
14461     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
14462         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
14463
14464     if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
14465             stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
14466       oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
14467
14468       /* null pad stream cannot be reused */
14469       if (oldstream->pad == NULL)
14470         oldstream = NULL;
14471     }
14472
14473     if (oldstream) {
14474       GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
14475
14476       if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
14477         return FALSE;
14478
14479       /* we don't need to preserve order of old streams */
14480       g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
14481     } else {
14482       GstTagList *list;
14483
14484       /* now we have all info and can expose */
14485       list = stream->stream_tags;
14486       stream->stream_tags = NULL;
14487       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
14488         return FALSE;
14489     }
14490   }
14491
14492   return TRUE;
14493 }
14494
14495 /* Must be called with expose lock */
14496 static GstFlowReturn
14497 qtdemux_expose_streams (GstQTDemux * qtdemux)
14498 {
14499   gint i;
14500
14501   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
14502
14503   if (!qtdemux_is_streams_update (qtdemux)) {
14504     GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
14505     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
14506       QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
14507       QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
14508       if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
14509         return GST_FLOW_ERROR;
14510     }
14511
14512     g_ptr_array_set_size (qtdemux->old_streams, 0);
14513     qtdemux->need_segment = TRUE;
14514
14515     return GST_FLOW_OK;
14516   }
14517
14518   if (qtdemux->streams_aware) {
14519     if (!qtdemux_update_streams (qtdemux))
14520       return GST_FLOW_ERROR;
14521   } else {
14522     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
14523       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
14524       GstTagList *list;
14525
14526       /* now we have all info and can expose */
14527       list = stream->stream_tags;
14528       stream->stream_tags = NULL;
14529       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
14530         return GST_FLOW_ERROR;
14531
14532     }
14533   }
14534
14535   gst_qtdemux_guess_bitrate (qtdemux);
14536
14537   /* If we have still old_streams, it's no more used stream */
14538   for (i = 0; i < qtdemux->old_streams->len; i++) {
14539     QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
14540
14541     if (stream->pad) {
14542       GstEvent *event;
14543
14544       event = gst_event_new_eos ();
14545       if (qtdemux->segment_seqnum)
14546         gst_event_set_seqnum (event, qtdemux->segment_seqnum);
14547
14548       gst_pad_push_event (stream->pad, event);
14549     }
14550   }
14551
14552   g_ptr_array_set_size (qtdemux->old_streams, 0);
14553
14554   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
14555
14556   /* check if we should post a redirect in case there is a single trak
14557    * and it is a redirecting trak */
14558   if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
14559       QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
14560     GstMessage *m;
14561
14562     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
14563         "an external content");
14564     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
14565         gst_structure_new ("redirect",
14566             "new-location", G_TYPE_STRING,
14567             QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
14568     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
14569     g_free (qtdemux->redirect_location);
14570     qtdemux->redirect_location =
14571         g_strdup (QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri);
14572   }
14573
14574   g_ptr_array_foreach (qtdemux->active_streams,
14575       (GFunc) qtdemux_do_allocation, qtdemux);
14576
14577   qtdemux->need_segment = TRUE;
14578
14579   qtdemux->exposed = TRUE;
14580   return GST_FLOW_OK;
14581 }
14582
14583 typedef struct
14584 {
14585   GstStructure *structure;      /* helper for sort function */
14586   gchar *location;
14587   guint min_req_bitrate;
14588   guint min_req_qt_version;
14589 } GstQtReference;
14590
14591 static gint
14592 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
14593 {
14594   GstQtReference *ref_a = (GstQtReference *) a;
14595   GstQtReference *ref_b = (GstQtReference *) b;
14596
14597   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
14598     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
14599
14600   /* known bitrates go before unknown; higher bitrates go first */
14601   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
14602 }
14603
14604 /* sort the redirects and post a message for the application.
14605  */
14606 static void
14607 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
14608 {
14609   GstQtReference *best;
14610   GstStructure *s;
14611   GstMessage *msg;
14612   GValue list_val = { 0, };
14613   GList *l;
14614
14615   g_assert (references != NULL);
14616
14617   references = g_list_sort (references, qtdemux_redirects_sort_func);
14618
14619   best = (GstQtReference *) references->data;
14620
14621   g_value_init (&list_val, GST_TYPE_LIST);
14622
14623   for (l = references; l != NULL; l = l->next) {
14624     GstQtReference *ref = (GstQtReference *) l->data;
14625     GValue struct_val = { 0, };
14626
14627     ref->structure = gst_structure_new ("redirect",
14628         "new-location", G_TYPE_STRING, ref->location, NULL);
14629
14630     if (ref->min_req_bitrate > 0) {
14631       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
14632           ref->min_req_bitrate, NULL);
14633     }
14634
14635     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
14636     g_value_set_boxed (&struct_val, ref->structure);
14637     gst_value_list_append_value (&list_val, &struct_val);
14638     g_value_unset (&struct_val);
14639     /* don't free anything here yet, since we need best->structure below */
14640   }
14641
14642   g_assert (best != NULL);
14643   s = gst_structure_copy (best->structure);
14644
14645   if (g_list_length (references) > 1) {
14646     gst_structure_set_value (s, "locations", &list_val);
14647   }
14648
14649   g_value_unset (&list_val);
14650
14651   for (l = references; l != NULL; l = l->next) {
14652     GstQtReference *ref = (GstQtReference *) l->data;
14653
14654     gst_structure_free (ref->structure);
14655     g_free (ref->location);
14656     g_free (ref);
14657   }
14658   g_list_free (references);
14659
14660   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
14661   g_free (qtdemux->redirect_location);
14662   qtdemux->redirect_location =
14663       g_strdup (gst_structure_get_string (s, "new-location"));
14664   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
14665   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
14666 }
14667
14668 /* look for redirect nodes, collect all redirect information and
14669  * process it.
14670  */
14671 static gboolean
14672 qtdemux_parse_redirects (GstQTDemux * qtdemux)
14673 {
14674   GNode *rmra, *rmda, *rdrf;
14675
14676   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
14677   if (rmra) {
14678     GList *redirects = NULL;
14679
14680     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
14681     while (rmda) {
14682       GstQtReference ref = { NULL, NULL, 0, 0 };
14683       GNode *rmdr, *rmvc;
14684
14685       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
14686         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
14687         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
14688             ref.min_req_bitrate);
14689       }
14690
14691       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
14692         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
14693         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
14694
14695 #ifndef GST_DISABLE_GST_DEBUG
14696         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
14697 #endif
14698         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
14699
14700         GST_LOG_OBJECT (qtdemux,
14701             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
14702             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
14703             bitmask, check_type);
14704         if (package == FOURCC_qtim && check_type == 0) {
14705           ref.min_req_qt_version = version;
14706         }
14707       }
14708
14709       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
14710       if (rdrf) {
14711         guint32 ref_type;
14712         guint8 *ref_data;
14713         guint ref_len;
14714
14715         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
14716         if (ref_len > 20) {
14717           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
14718           ref_data = (guint8 *) rdrf->data + 20;
14719           if (ref_type == FOURCC_alis) {
14720             guint record_len, record_version, fn_len;
14721
14722             if (ref_len > 70) {
14723               /* MacOSX alias record, google for alias-layout.txt */
14724               record_len = QT_UINT16 (ref_data + 4);
14725               record_version = QT_UINT16 (ref_data + 4 + 2);
14726               fn_len = QT_UINT8 (ref_data + 50);
14727               if (record_len > 50 && record_version == 2 && fn_len > 0) {
14728                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
14729               }
14730             } else {
14731               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
14732                   ref_len);
14733             }
14734           } else if (ref_type == FOURCC_url_) {
14735             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
14736           } else {
14737             GST_DEBUG_OBJECT (qtdemux,
14738                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
14739                 GST_FOURCC_ARGS (ref_type));
14740           }
14741           if (ref.location != NULL) {
14742             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
14743             redirects =
14744                 g_list_prepend (redirects, g_memdup2 (&ref, sizeof (ref)));
14745           } else {
14746             GST_WARNING_OBJECT (qtdemux,
14747                 "Failed to extract redirect location from rdrf atom");
14748           }
14749         } else {
14750           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
14751         }
14752       }
14753
14754       /* look for others */
14755       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
14756     }
14757
14758     if (redirects != NULL) {
14759       qtdemux_process_redirects (qtdemux, redirects);
14760     }
14761   }
14762   return TRUE;
14763 }
14764
14765 static GstTagList *
14766 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
14767 {
14768   const gchar *fmt;
14769
14770   if (tags == NULL) {
14771     tags = gst_tag_list_new_empty ();
14772     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
14773   }
14774
14775   if (qtdemux->major_brand == FOURCC_mjp2)
14776     fmt = "Motion JPEG 2000";
14777   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
14778     fmt = "3GP";
14779   else if (qtdemux->major_brand == FOURCC_qt__)
14780     fmt = "Quicktime";
14781   else if (qtdemux->fragmented)
14782     fmt = "ISO fMP4";
14783   else
14784     fmt = "ISO MP4/M4A";
14785
14786   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
14787       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
14788
14789   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
14790       fmt, NULL);
14791
14792   return tags;
14793 }
14794
14795 /* we have read the complete moov node now.
14796  * This function parses all of the relevant info, creates the traks and
14797  * prepares all data structures for playback
14798  */
14799 static gboolean
14800 qtdemux_parse_tree (GstQTDemux * qtdemux)
14801 {
14802   GNode *mvhd;
14803   GNode *trak;
14804   GNode *udta;
14805   GNode *mvex;
14806   GNode *pssh;
14807   guint64 creation_time;
14808   GstDateTime *datetime = NULL;
14809   gint version;
14810
14811   /* make sure we have a usable taglist */
14812   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14813
14814   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14815   if (mvhd == NULL) {
14816     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14817     return qtdemux_parse_redirects (qtdemux);
14818   }
14819
14820   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14821   if (version == 1) {
14822     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14823     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14824     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14825   } else if (version == 0) {
14826     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14827     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14828     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14829   } else {
14830     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14831     return FALSE;
14832   }
14833
14834   /* Moving qt creation time (secs since 1904) to unix time */
14835   if (creation_time != 0) {
14836     /* Try to use epoch first as it should be faster and more commonly found */
14837     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14838       gint64 now_s;
14839
14840       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14841       /* some data cleansing sanity */
14842       now_s = g_get_real_time () / G_USEC_PER_SEC;
14843       if (now_s + 24 * 3600 < creation_time) {
14844         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14845       } else {
14846         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14847       }
14848     } else {
14849       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14850       GDateTime *dt, *dt_local;
14851
14852       dt = g_date_time_add_seconds (base_dt, creation_time);
14853       dt_local = g_date_time_to_local (dt);
14854       datetime = gst_date_time_new_from_g_date_time (dt_local);
14855
14856       g_date_time_unref (base_dt);
14857       g_date_time_unref (dt);
14858     }
14859   }
14860   if (datetime) {
14861     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14862     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14863         datetime, NULL);
14864     gst_date_time_unref (datetime);
14865   }
14866
14867   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14868   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14869
14870   /* check for fragmented file and get some (default) data */
14871   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14872   if (mvex) {
14873     GNode *mehd;
14874     GstByteReader mehd_data;
14875
14876     /* let track parsing or anyone know weird stuff might happen ... */
14877     qtdemux->fragmented = TRUE;
14878
14879     /* compensate for total duration */
14880     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14881     if (mehd)
14882       qtdemux_parse_mehd (qtdemux, &mehd_data);
14883   }
14884
14885   /* Update the movie segment duration, unless it was directly given to us
14886    * by upstream. Otherwise let it as is, as we don't want to mangle the
14887    * duration provided by upstream that may come e.g. from a MPD file. */
14888   if (!qtdemux->upstream_format_is_time) {
14889     GstClockTime duration;
14890     /* set duration in the segment info */
14891     gst_qtdemux_get_duration (qtdemux, &duration);
14892     qtdemux->segment.duration = duration;
14893     /* also do not exceed duration; stop is set that way post seek anyway,
14894      * and segment activation falls back to duration,
14895      * whereas loop only checks stop, so let's align this here as well */
14896     qtdemux->segment.stop = duration;
14897   }
14898
14899   /* parse all traks */
14900   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14901   while (trak) {
14902     qtdemux_parse_trak (qtdemux, trak);
14903     /* iterate all siblings */
14904     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14905   }
14906
14907   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14908
14909   /* find tags */
14910   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14911   if (udta) {
14912     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14913   } else {
14914     GST_LOG_OBJECT (qtdemux, "No udta node found.");
14915   }
14916
14917   /* maybe also some tags in meta box */
14918   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14919   if (udta) {
14920     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14921     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14922   } else {
14923     GST_LOG_OBJECT (qtdemux, "No meta node found.");
14924   }
14925
14926   /* parse any protection system info */
14927   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14928   if (pssh) {
14929     /* Unref old protection events if we are going to receive new ones. */
14930     qtdemux_clear_protection_events_on_all_streams (qtdemux);
14931   }
14932   while (pssh) {
14933     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14934     qtdemux_parse_pssh (qtdemux, pssh);
14935     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14936   }
14937
14938   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14939
14940   return TRUE;
14941 }
14942
14943 /* taken from ffmpeg */
14944 static int
14945 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14946 {
14947   int count = 4;
14948   int len = 0;
14949
14950   while (count--) {
14951     int c;
14952
14953     if (ptr >= end)
14954       return -1;
14955
14956     c = *ptr++;
14957     len = (len << 7) | (c & 0x7f);
14958     if (!(c & 0x80))
14959       break;
14960   }
14961   *end_out = ptr;
14962   return len;
14963 }
14964
14965 static GList *
14966 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14967     gsize codec_data_size)
14968 {
14969   GList *list = NULL;
14970   guint8 *p = codec_data;
14971   gint i, offset, num_packets;
14972   guint *length, last;
14973
14974   GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14975
14976   if (codec_data == NULL || codec_data_size == 0)
14977     goto error;
14978
14979   /* start of the stream and vorbis audio or theora video, need to
14980    * send the codec_priv data as first three packets */
14981   num_packets = p[0] + 1;
14982   GST_DEBUG_OBJECT (qtdemux,
14983       "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14984       (guint) num_packets, codec_data_size);
14985
14986   /* Let's put some limits, Don't think there even is a xiph codec
14987    * with more than 3-4 headers */
14988   if (G_UNLIKELY (num_packets > 16)) {
14989     GST_WARNING_OBJECT (qtdemux,
14990         "Unlikely number of xiph headers, most likely not valid");
14991     goto error;
14992   }
14993
14994   length = g_alloca (num_packets * sizeof (guint));
14995   last = 0;
14996   offset = 1;
14997
14998   /* first packets, read length values */
14999   for (i = 0; i < num_packets - 1; i++) {
15000     length[i] = 0;
15001     while (offset < codec_data_size) {
15002       length[i] += p[offset];
15003       if (p[offset++] != 0xff)
15004         break;
15005     }
15006     last += length[i];
15007   }
15008   if (offset + last > codec_data_size)
15009     goto error;
15010
15011   /* last packet is the remaining size */
15012   length[i] = codec_data_size - offset - last;
15013
15014   for (i = 0; i < num_packets; i++) {
15015     GstBuffer *hdr;
15016
15017     GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
15018
15019     if (offset + length[i] > codec_data_size)
15020       goto error;
15021
15022     hdr = gst_buffer_new_memdup (p + offset, length[i]);
15023     list = g_list_append (list, hdr);
15024
15025     offset += length[i];
15026   }
15027
15028   return list;
15029
15030   /* ERRORS */
15031 error:
15032   {
15033     if (list != NULL)
15034       g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
15035     return NULL;
15036   }
15037
15038 }
15039
15040 /* this can change the codec originally present in @list */
15041 static void
15042 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
15043     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
15044 {
15045   int len = QT_UINT32 (esds->data);
15046   guint8 *ptr = esds->data;
15047   guint8 *end = ptr + len;
15048   int tag;
15049   guint8 *data_ptr = NULL;
15050   int data_len = 0;
15051   guint8 object_type_id = 0;
15052   guint8 stream_type = 0;
15053   const char *codec_name = NULL;
15054   GstCaps *caps = NULL;
15055
15056   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
15057   ptr += 8;
15058   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
15059   ptr += 4;
15060   while (ptr + 1 < end) {
15061     tag = QT_UINT8 (ptr);
15062     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
15063     ptr++;
15064     len = read_descr_size (ptr, end, &ptr);
15065     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
15066
15067     /* Check the stated amount of data is available for reading */
15068     if (len < 0 || ptr + len > end)
15069       break;
15070
15071     switch (tag) {
15072       case ES_DESCRIPTOR_TAG:
15073         GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
15074         GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
15075         ptr += 3;
15076         break;
15077       case DECODER_CONFIG_DESC_TAG:{
15078         guint max_bitrate, avg_bitrate;
15079
15080         object_type_id = QT_UINT8 (ptr);
15081         stream_type = QT_UINT8 (ptr + 1) >> 2;
15082         max_bitrate = QT_UINT32 (ptr + 5);
15083         avg_bitrate = QT_UINT32 (ptr + 9);
15084         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
15085         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
15086         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
15087         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
15088         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
15089         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
15090           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
15091               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
15092         }
15093         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
15094           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
15095               avg_bitrate, NULL);
15096         }
15097         ptr += 13;
15098         break;
15099       }
15100       case DECODER_SPECIFIC_INFO_TAG:
15101         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
15102         if (object_type_id == 0xe0 && len == 0x40) {
15103           guint8 *data;
15104           GstStructure *s;
15105           guint32 clut[16];
15106           gint i;
15107
15108           GST_DEBUG_OBJECT (qtdemux,
15109               "Have VOBSUB palette. Creating palette event");
15110           /* move to decConfigDescr data and read palette */
15111           data = ptr;
15112           for (i = 0; i < 16; i++) {
15113             clut[i] = QT_UINT32 (data);
15114             data += 4;
15115           }
15116
15117           s = gst_structure_new ("application/x-gst-dvd", "event",
15118               G_TYPE_STRING, "dvd-spu-clut-change",
15119               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
15120               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
15121               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
15122               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
15123               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
15124               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
15125               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
15126               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
15127               NULL);
15128
15129           /* store event and trigger custom processing */
15130           stream->pending_event =
15131               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
15132         } else {
15133           /* Generic codec_data handler puts it on the caps */
15134           data_ptr = ptr;
15135           data_len = len;
15136         }
15137
15138         ptr += len;
15139         break;
15140       case SL_CONFIG_DESC_TAG:
15141         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
15142         ptr += 1;
15143         break;
15144       default:
15145         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
15146             tag);
15147         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
15148         ptr += len;
15149         break;
15150     }
15151   }
15152
15153   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
15154    * in use, and should also be used to override some other parameters for some
15155    * codecs. */
15156   switch (object_type_id) {
15157     case 0x20:                 /* MPEG-4 */
15158       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
15159        * profile_and_level_indication */
15160       if (data_ptr != NULL && data_len >= 5 &&
15161           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
15162         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
15163             data_ptr + 4, data_len - 4);
15164       }
15165       break;                    /* Nothing special needed here */
15166     case 0x21:                 /* H.264 */
15167       codec_name = "H.264 / AVC";
15168       caps = gst_caps_new_simple ("video/x-h264",
15169           "stream-format", G_TYPE_STRING, "avc",
15170           "alignment", G_TYPE_STRING, "au", NULL);
15171       break;
15172     case 0x40:                 /* AAC (any) */
15173     case 0x66:                 /* AAC Main */
15174     case 0x67:                 /* AAC LC */
15175     case 0x68:                 /* AAC SSR */
15176       /* Override channels and rate based on the codec_data, as it's often
15177        * wrong. */
15178       /* Only do so for basic setup without HE-AAC extension */
15179       if (data_ptr && data_len == 2) {
15180         guint channels, rate;
15181
15182         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
15183         if (channels > 0)
15184           entry->n_channels = channels;
15185
15186         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
15187         if (rate > 0)
15188           entry->rate = rate;
15189       }
15190
15191       /* Set level and profile if possible */
15192       if (data_ptr != NULL && data_len >= 2) {
15193         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
15194             data_ptr, data_len);
15195       } else {
15196         const gchar *profile_str = NULL;
15197         GstBuffer *buffer;
15198         GstMapInfo map;
15199         guint8 *codec_data;
15200         gint rate_idx, profile;
15201
15202         /* No codec_data, let's invent something.
15203          * FIXME: This is wrong for SBR! */
15204
15205         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
15206
15207         buffer = gst_buffer_new_and_alloc (2);
15208         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
15209         codec_data = map.data;
15210
15211         rate_idx =
15212             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
15213             (stream)->rate);
15214
15215         switch (object_type_id) {
15216           case 0x66:
15217             profile_str = "main";
15218             profile = 0;
15219             break;
15220           case 0x67:
15221             profile_str = "lc";
15222             profile = 1;
15223             break;
15224           case 0x68:
15225             profile_str = "ssr";
15226             profile = 2;
15227             break;
15228           default:
15229             profile = 3;
15230             break;
15231         }
15232
15233         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
15234         codec_data[1] =
15235             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
15236
15237         gst_buffer_unmap (buffer, &map);
15238         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
15239             GST_TYPE_BUFFER, buffer, NULL);
15240         gst_buffer_unref (buffer);
15241
15242         if (profile_str) {
15243           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
15244               G_TYPE_STRING, profile_str, NULL);
15245         }
15246       }
15247       break;
15248     case 0x60:                 /* MPEG-2, various profiles */
15249     case 0x61:
15250     case 0x62:
15251     case 0x63:
15252     case 0x64:
15253     case 0x65:
15254       codec_name = "MPEG-2 video";
15255       caps = gst_caps_new_simple ("video/mpeg",
15256           "mpegversion", G_TYPE_INT, 2,
15257           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15258       break;
15259     case 0x69:                 /* MPEG-2 BC audio */
15260     case 0x6B:                 /* MPEG-1 audio */
15261       caps = gst_caps_new_simple ("audio/mpeg",
15262           "mpegversion", G_TYPE_INT, 1, NULL);
15263       codec_name = "MPEG-1 audio";
15264       break;
15265     case 0x6A:                 /* MPEG-1 */
15266       codec_name = "MPEG-1 video";
15267       caps = gst_caps_new_simple ("video/mpeg",
15268           "mpegversion", G_TYPE_INT, 1,
15269           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15270       break;
15271     case 0x6C:                 /* MJPEG */
15272       caps =
15273           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15274           NULL);
15275       codec_name = "Motion-JPEG";
15276       break;
15277     case 0x6D:                 /* PNG */
15278       caps =
15279           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
15280           NULL);
15281       codec_name = "PNG still images";
15282       break;
15283     case 0x6E:                 /* JPEG2000 */
15284       codec_name = "JPEG-2000";
15285       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15286       break;
15287     case 0xA4:                 /* Dirac */
15288       codec_name = "Dirac";
15289       caps = gst_caps_new_empty_simple ("video/x-dirac");
15290       break;
15291     case 0xA5:                 /* AC3 */
15292       codec_name = "AC-3 audio";
15293       caps = gst_caps_new_simple ("audio/x-ac3",
15294           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15295       break;
15296     case 0xA9:                 /* AC3 */
15297       codec_name = "DTS audio";
15298       caps = gst_caps_new_simple ("audio/x-dts",
15299           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15300       break;
15301     case 0xDD:
15302       if (stream_type == 0x05 && data_ptr) {
15303         GList *headers =
15304             parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
15305         if (headers) {
15306           GList *tmp;
15307           GValue arr_val = G_VALUE_INIT;
15308           GValue buf_val = G_VALUE_INIT;
15309           GstStructure *s;
15310
15311           /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
15312           codec_name = "Vorbis";
15313           caps = gst_caps_new_empty_simple ("audio/x-vorbis");
15314           g_value_init (&arr_val, GST_TYPE_ARRAY);
15315           g_value_init (&buf_val, GST_TYPE_BUFFER);
15316           for (tmp = headers; tmp; tmp = tmp->next) {
15317             g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
15318             gst_value_array_append_value (&arr_val, &buf_val);
15319           }
15320           s = gst_caps_get_structure (caps, 0);
15321           gst_structure_take_value (s, "streamheader", &arr_val);
15322           g_value_unset (&buf_val);
15323           g_list_free (headers);
15324
15325           data_ptr = NULL;
15326           data_len = 0;
15327         }
15328       }
15329       break;
15330     case 0xE1:                 /* QCELP */
15331       /* QCELP, the codec_data is a riff tag (little endian) with
15332        * 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). */
15333       caps = gst_caps_new_empty_simple ("audio/qcelp");
15334       codec_name = "QCELP";
15335       break;
15336     default:
15337       break;
15338   }
15339
15340   /* If we have a replacement caps, then change our caps for this stream */
15341   if (caps) {
15342     gst_caps_unref (entry->caps);
15343     entry->caps = caps;
15344   }
15345
15346   if (codec_name && list)
15347     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
15348         GST_TAG_AUDIO_CODEC, codec_name, NULL);
15349
15350   /* Add the codec_data attribute to caps, if we have it */
15351   if (data_ptr) {
15352     GstBuffer *buffer;
15353
15354     buffer = gst_buffer_new_and_alloc (data_len);
15355     gst_buffer_fill (buffer, 0, data_ptr, data_len);
15356
15357     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
15358     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
15359
15360     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
15361         buffer, NULL);
15362     gst_buffer_unref (buffer);
15363   }
15364
15365 }
15366
15367 static inline GstCaps *
15368 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
15369 {
15370   GstCaps *caps;
15371   guint i;
15372   char *s, fourstr[5];
15373
15374   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
15375   for (i = 0; i < 4; i++) {
15376     if (!g_ascii_isalnum (fourstr[i]))
15377       fourstr[i] = '_';
15378   }
15379   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
15380   caps = gst_caps_new_empty_simple (s);
15381   g_free (s);
15382   return caps;
15383 }
15384
15385 #define _codec(name) \
15386   do { \
15387     if (codec_name) { \
15388       *codec_name = g_strdup (name); \
15389     } \
15390   } while (0)
15391
15392 static GstCaps *
15393 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15394     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15395     const guint8 * stsd_entry_data, gchar ** codec_name)
15396 {
15397   GstCaps *caps = NULL;
15398   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
15399
15400   switch (fourcc) {
15401     case FOURCC_png:
15402       _codec ("PNG still images");
15403       caps = gst_caps_new_empty_simple ("image/png");
15404       break;
15405     case FOURCC_jpeg:
15406       _codec ("JPEG still images");
15407       caps =
15408           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15409           NULL);
15410       break;
15411     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
15412     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
15413     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
15414     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
15415       _codec ("Motion-JPEG");
15416       caps =
15417           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15418           NULL);
15419       break;
15420     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
15421       _codec ("Motion-JPEG format B");
15422       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
15423       break;
15424     case FOURCC_mjp2:
15425       _codec ("JPEG-2000");
15426       /* override to what it should be according to spec, avoid palette_data */
15427       entry->bits_per_sample = 24;
15428       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15429       break;
15430     case FOURCC_SVQ3:
15431       _codec ("Sorensen video v.3");
15432       caps = gst_caps_new_simple ("video/x-svq",
15433           "svqversion", G_TYPE_INT, 3, NULL);
15434       break;
15435     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
15436     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
15437       _codec ("Sorensen video v.1");
15438       caps = gst_caps_new_simple ("video/x-svq",
15439           "svqversion", G_TYPE_INT, 1, NULL);
15440       break;
15441     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
15442       caps = gst_caps_new_empty_simple ("video/x-raw");
15443       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
15444       _codec ("Windows Raw RGB");
15445       stream->alignment = 32;
15446       break;
15447     case FOURCC_raw_:
15448     {
15449       guint16 bps;
15450
15451       bps = QT_UINT16 (stsd_entry_data + 82);
15452       switch (bps) {
15453         case 15:
15454           format = GST_VIDEO_FORMAT_RGB15;
15455           break;
15456         case 16:
15457           format = GST_VIDEO_FORMAT_RGB16;
15458           break;
15459         case 24:
15460           format = GST_VIDEO_FORMAT_RGB;
15461           break;
15462         case 32:
15463           format = GST_VIDEO_FORMAT_ARGB;
15464           break;
15465         default:
15466           /* unknown */
15467           break;
15468       }
15469       break;
15470     }
15471     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
15472       format = GST_VIDEO_FORMAT_I420;
15473       break;
15474     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
15475     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
15476       format = GST_VIDEO_FORMAT_I420;
15477       break;
15478     case FOURCC_2vuy:
15479     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
15480       format = GST_VIDEO_FORMAT_UYVY;
15481       break;
15482     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
15483       format = GST_VIDEO_FORMAT_v308;
15484       break;
15485     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
15486       format = GST_VIDEO_FORMAT_v216;
15487       break;
15488     case FOURCC_v210:
15489       format = GST_VIDEO_FORMAT_v210;
15490       break;
15491     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
15492       format = GST_VIDEO_FORMAT_r210;
15493       break;
15494       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
15495          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
15496          format = GST_VIDEO_FORMAT_v410;
15497          break;
15498        */
15499       /* Packed YUV 4:4:4:4 8 bit in 32 bits
15500        * but different order than AYUV
15501        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
15502        format = GST_VIDEO_FORMAT_v408;
15503        break;
15504        */
15505     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
15506     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
15507       _codec ("MPEG-1 video");
15508       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15509           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15510       break;
15511     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
15512     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
15513     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
15514     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
15515     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
15516     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
15517     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
15518     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
15519     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
15520     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
15521     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
15522     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
15523     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
15524     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
15525     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
15526     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
15527     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
15528     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
15529     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
15530     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
15531     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
15532     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
15533     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
15534     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
15535     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
15536     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
15537     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
15538     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
15539     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
15540     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
15541     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
15542     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
15543     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
15544     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
15545     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
15546     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
15547     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15548     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15549     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
15550     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
15551     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
15552     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
15553     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
15554     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
15555     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
15556     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
15557     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
15558       _codec ("MPEG-2 video");
15559       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
15560           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15561       break;
15562     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
15563       _codec ("GIF still images");
15564       caps = gst_caps_new_empty_simple ("image/gif");
15565       break;
15566     case FOURCC_h263:
15567     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
15568     case FOURCC_s263:
15569     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
15570       _codec ("H.263");
15571       /* ffmpeg uses the height/width props, don't know why */
15572       caps = gst_caps_new_simple ("video/x-h263",
15573           "variant", G_TYPE_STRING, "itu", NULL);
15574       break;
15575     case FOURCC_mp4v:
15576     case FOURCC_MP4V:
15577       _codec ("MPEG-4 video");
15578       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15579           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15580       break;
15581     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
15582     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
15583       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
15584       caps = gst_caps_new_simple ("video/x-msmpeg",
15585           "msmpegversion", G_TYPE_INT, 43, NULL);
15586       break;
15587     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
15588       _codec ("DivX 3");
15589       caps = gst_caps_new_simple ("video/x-divx",
15590           "divxversion", G_TYPE_INT, 3, NULL);
15591       break;
15592     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
15593     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
15594       _codec ("DivX 4");
15595       caps = gst_caps_new_simple ("video/x-divx",
15596           "divxversion", G_TYPE_INT, 4, NULL);
15597       break;
15598     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
15599       _codec ("DivX 5");
15600       caps = gst_caps_new_simple ("video/x-divx",
15601           "divxversion", G_TYPE_INT, 5, NULL);
15602       break;
15603
15604     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
15605       _codec ("FFV1");
15606       caps = gst_caps_new_simple ("video/x-ffv",
15607           "ffvversion", G_TYPE_INT, 1, NULL);
15608       break;
15609
15610     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
15611     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
15612     case FOURCC_XVID:
15613     case FOURCC_xvid:
15614     case FOURCC_FMP4:
15615     case FOURCC_fmp4:
15616     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
15617       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15618           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15619       _codec ("MPEG-4");
15620       break;
15621
15622     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
15623       _codec ("Cinepak");
15624       caps = gst_caps_new_empty_simple ("video/x-cinepak");
15625       break;
15626     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
15627       _codec ("Apple QuickDraw");
15628       caps = gst_caps_new_empty_simple ("video/x-qdrw");
15629       break;
15630     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
15631       _codec ("Apple video");
15632       caps = gst_caps_new_empty_simple ("video/x-apple-video");
15633       break;
15634     case FOURCC_H264:
15635     case FOURCC_avc1:
15636     case FOURCC_dva1:
15637       _codec ("H.264 / AVC");
15638       caps = gst_caps_new_simple ("video/x-h264",
15639           "stream-format", G_TYPE_STRING, "avc",
15640           "alignment", G_TYPE_STRING, "au", NULL);
15641       break;
15642     case FOURCC_avc3:
15643     case FOURCC_dvav:
15644       _codec ("H.264 / AVC");
15645       caps = gst_caps_new_simple ("video/x-h264",
15646           "stream-format", G_TYPE_STRING, "avc3",
15647           "alignment", G_TYPE_STRING, "au", NULL);
15648       break;
15649     case FOURCC_ai12:
15650     case FOURCC_ai13:
15651     case FOURCC_ai15:
15652     case FOURCC_ai16:
15653     case FOURCC_ai1p:
15654     case FOURCC_ai1q:
15655     case FOURCC_ai52:
15656     case FOURCC_ai53:
15657     case FOURCC_ai55:
15658     case FOURCC_ai56:
15659     case FOURCC_ai5p:
15660     case FOURCC_ai5q:
15661       _codec ("H.264 / AVC");
15662       caps = gst_caps_new_simple ("video/x-h264",
15663           "stream-format", G_TYPE_STRING, "byte-stream",
15664           "alignment", G_TYPE_STRING, "au", NULL);
15665       break;
15666     case FOURCC_H265:
15667     case FOURCC_hvc1:
15668     case FOURCC_dvh1:
15669       _codec ("H.265 / HEVC");
15670       caps = gst_caps_new_simple ("video/x-h265",
15671           "stream-format", G_TYPE_STRING, "hvc1",
15672           "alignment", G_TYPE_STRING, "au", NULL);
15673       break;
15674     case FOURCC_hev1:
15675     case FOURCC_dvhe:
15676       _codec ("H.265 / HEVC");
15677       caps = gst_caps_new_simple ("video/x-h265",
15678           "stream-format", G_TYPE_STRING, "hev1",
15679           "alignment", G_TYPE_STRING, "au", NULL);
15680       break;
15681     case FOURCC_rle_:
15682       _codec ("Run-length encoding");
15683       caps = gst_caps_new_simple ("video/x-rle",
15684           "layout", G_TYPE_STRING, "quicktime", NULL);
15685       break;
15686     case FOURCC_WRLE:
15687       _codec ("Run-length encoding");
15688       caps = gst_caps_new_simple ("video/x-rle",
15689           "layout", G_TYPE_STRING, "microsoft", NULL);
15690       break;
15691     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
15692     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
15693       _codec ("Indeo Video 3");
15694       caps = gst_caps_new_simple ("video/x-indeo",
15695           "indeoversion", G_TYPE_INT, 3, NULL);
15696       break;
15697     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
15698     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
15699       _codec ("Intel Video 4");
15700       caps = gst_caps_new_simple ("video/x-indeo",
15701           "indeoversion", G_TYPE_INT, 4, NULL);
15702       break;
15703     case FOURCC_dvcp:
15704     case FOURCC_dvc_:
15705     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
15706     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
15707     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
15708     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
15709     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
15710     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
15711       _codec ("DV Video");
15712       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
15713           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15714       break;
15715     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
15716     case FOURCC_dv5p:          /* DVCPRO50 PAL */
15717       _codec ("DVCPro50 Video");
15718       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
15719           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15720       break;
15721     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
15722     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
15723       _codec ("DVCProHD Video");
15724       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
15725           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15726       break;
15727     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
15728       _codec ("Apple Graphics (SMC)");
15729       caps = gst_caps_new_empty_simple ("video/x-smc");
15730       break;
15731     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
15732       _codec ("VP3");
15733       caps = gst_caps_new_empty_simple ("video/x-vp3");
15734       break;
15735     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
15736       _codec ("VP6 Flash");
15737       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
15738       break;
15739     case FOURCC_XiTh:
15740       _codec ("Theora");
15741       caps = gst_caps_new_empty_simple ("video/x-theora");
15742       /* theora uses one byte of padding in the data stream because it does not
15743        * allow 0 sized packets while theora does */
15744       entry->padding = 1;
15745       break;
15746     case FOURCC_drac:
15747       _codec ("Dirac");
15748       caps = gst_caps_new_empty_simple ("video/x-dirac");
15749       break;
15750     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
15751       _codec ("TIFF still images");
15752       caps = gst_caps_new_empty_simple ("image/tiff");
15753       break;
15754     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
15755       _codec ("Apple Intermediate Codec");
15756       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
15757       break;
15758     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
15759       _codec ("AVID DNxHD");
15760       caps = gst_caps_from_string ("video/x-dnxhd");
15761       break;
15762     case FOURCC_VP80:
15763     case FOURCC_vp08:
15764       _codec ("On2 VP8");
15765       caps = gst_caps_from_string ("video/x-vp8");
15766       break;
15767     case FOURCC_vp09:
15768       _codec ("Google VP9");
15769       caps = gst_caps_from_string ("video/x-vp9");
15770       break;
15771     case FOURCC_apcs:
15772       _codec ("Apple ProRes LT");
15773       caps =
15774           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
15775           NULL);
15776       break;
15777     case FOURCC_apch:
15778       _codec ("Apple ProRes HQ");
15779       caps =
15780           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
15781           NULL);
15782       break;
15783     case FOURCC_apcn:
15784       _codec ("Apple ProRes");
15785       caps =
15786           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15787           "standard", NULL);
15788       break;
15789     case FOURCC_apco:
15790       _codec ("Apple ProRes Proxy");
15791       caps =
15792           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15793           "proxy", NULL);
15794       break;
15795     case FOURCC_ap4h:
15796       _codec ("Apple ProRes 4444");
15797       caps =
15798           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15799           "4444", NULL);
15800
15801       /* 24 bits per sample = an alpha channel is coded but image is always opaque */
15802       if (entry->bits_per_sample > 0) {
15803         gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
15804             NULL);
15805       }
15806       break;
15807     case FOURCC_ap4x:
15808       _codec ("Apple ProRes 4444 XQ");
15809       caps =
15810           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15811           "4444xq", NULL);
15812
15813       /* 24 bits per sample = an alpha channel is coded but image is always opaque */
15814       if (entry->bits_per_sample > 0) {
15815         gst_caps_set_simple (caps, "depth", G_TYPE_INT, entry->bits_per_sample,
15816             NULL);
15817       }
15818       break;
15819     case FOURCC_cfhd:
15820       _codec ("GoPro CineForm");
15821       caps = gst_caps_from_string ("video/x-cineform");
15822       break;
15823     case FOURCC_vc_1:
15824     case FOURCC_ovc1:
15825       _codec ("VC-1");
15826       caps = gst_caps_new_simple ("video/x-wmv",
15827           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
15828       break;
15829     case FOURCC_av01:
15830       _codec ("AV1");
15831       caps = gst_caps_new_simple ("video/x-av1",
15832           "stream-format", G_TYPE_STRING, "obu-stream",
15833           "alignment", G_TYPE_STRING, "tu", NULL);
15834       break;
15835     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15836     default:
15837     {
15838       caps = _get_unknown_codec_name ("video", fourcc);
15839       break;
15840     }
15841   }
15842
15843   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15844     GstVideoInfo info;
15845
15846     gst_video_info_init (&info);
15847     gst_video_info_set_format (&info, format, entry->width, entry->height);
15848
15849     caps = gst_video_info_to_caps (&info);
15850     *codec_name = gst_pb_utils_get_codec_description (caps);
15851
15852     /* enable clipping for raw video streams */
15853     stream->need_clip = TRUE;
15854     stream->alignment = 32;
15855   }
15856
15857   return caps;
15858 }
15859
15860 static guint
15861 round_up_pow2 (guint n)
15862 {
15863   n = n - 1;
15864   n = n | (n >> 1);
15865   n = n | (n >> 2);
15866   n = n | (n >> 4);
15867   n = n | (n >> 8);
15868   n = n | (n >> 16);
15869   return n + 1;
15870 }
15871
15872 static GstCaps *
15873 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15874     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15875     int len, gchar ** codec_name)
15876 {
15877   GstCaps *caps;
15878   const GstStructure *s;
15879   const gchar *name;
15880   gint endian = 0;
15881   GstAudioFormat format = 0;
15882   gint depth;
15883
15884   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15885
15886   depth = entry->bytes_per_packet * 8;
15887
15888   switch (fourcc) {
15889     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15890     case FOURCC_raw_:
15891       /* 8-bit audio is unsigned */
15892       if (depth == 8)
15893         format = GST_AUDIO_FORMAT_U8;
15894       /* otherwise it's signed and big-endian just like 'twos' */
15895     case FOURCC_twos:
15896       endian = G_BIG_ENDIAN;
15897       /* fall-through */
15898     case FOURCC_sowt:
15899     {
15900       gchar *str;
15901
15902       if (!endian)
15903         endian = G_LITTLE_ENDIAN;
15904
15905       if (!format)
15906         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15907
15908       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15909       _codec (str);
15910       g_free (str);
15911
15912       caps = gst_caps_new_simple ("audio/x-raw",
15913           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15914           "layout", G_TYPE_STRING, "interleaved", NULL);
15915       stream->alignment = GST_ROUND_UP_8 (depth);
15916       stream->alignment = round_up_pow2 (stream->alignment);
15917       break;
15918     }
15919     case FOURCC_fl64:
15920       _codec ("Raw 64-bit floating-point audio");
15921       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15922        * endian later */
15923       caps = gst_caps_new_simple ("audio/x-raw",
15924           "format", G_TYPE_STRING, "F64BE",
15925           "layout", G_TYPE_STRING, "interleaved", NULL);
15926       stream->alignment = 8;
15927       break;
15928     case FOURCC_fl32:
15929       _codec ("Raw 32-bit floating-point audio");
15930       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15931        * endian later */
15932       caps = gst_caps_new_simple ("audio/x-raw",
15933           "format", G_TYPE_STRING, "F32BE",
15934           "layout", G_TYPE_STRING, "interleaved", NULL);
15935       stream->alignment = 4;
15936       break;
15937     case FOURCC_in24:
15938       _codec ("Raw 24-bit PCM audio");
15939       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15940        * endian later */
15941       caps = gst_caps_new_simple ("audio/x-raw",
15942           "format", G_TYPE_STRING, "S24BE",
15943           "layout", G_TYPE_STRING, "interleaved", NULL);
15944       stream->alignment = 4;
15945       break;
15946     case FOURCC_in32:
15947       _codec ("Raw 32-bit PCM audio");
15948       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15949        * endian later */
15950       caps = gst_caps_new_simple ("audio/x-raw",
15951           "format", G_TYPE_STRING, "S32BE",
15952           "layout", G_TYPE_STRING, "interleaved", NULL);
15953       stream->alignment = 4;
15954       break;
15955     case FOURCC_s16l:
15956       _codec ("Raw 16-bit PCM audio");
15957       caps = gst_caps_new_simple ("audio/x-raw",
15958           "format", G_TYPE_STRING, "S16LE",
15959           "layout", G_TYPE_STRING, "interleaved", NULL);
15960       stream->alignment = 2;
15961       break;
15962     case FOURCC_ulaw:
15963       _codec ("Mu-law audio");
15964       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15965       break;
15966     case FOURCC_alaw:
15967       _codec ("A-law audio");
15968       caps = gst_caps_new_empty_simple ("audio/x-alaw");
15969       break;
15970     case 0x0200736d:
15971     case 0x6d730002:
15972       _codec ("Microsoft ADPCM");
15973       /* Microsoft ADPCM-ACM code 2 */
15974       caps = gst_caps_new_simple ("audio/x-adpcm",
15975           "layout", G_TYPE_STRING, "microsoft", NULL);
15976       break;
15977     case 0x1100736d:
15978     case 0x6d730011:
15979       _codec ("DVI/IMA ADPCM");
15980       caps = gst_caps_new_simple ("audio/x-adpcm",
15981           "layout", G_TYPE_STRING, "dvi", NULL);
15982       break;
15983     case 0x1700736d:
15984     case 0x6d730017:
15985       _codec ("DVI/Intel IMA ADPCM");
15986       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15987       caps = gst_caps_new_simple ("audio/x-adpcm",
15988           "layout", G_TYPE_STRING, "quicktime", NULL);
15989       break;
15990     case 0x5500736d:
15991     case 0x6d730055:
15992       /* MPEG layer 3, CBR only (pre QT4.1) */
15993     case FOURCC__mp3:
15994     case FOURCC_mp3_:
15995       _codec ("MPEG-1 layer 3");
15996       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15997       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15998           "mpegversion", G_TYPE_INT, 1, NULL);
15999       break;
16000     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
16001       _codec ("MPEG-1 layer 2");
16002       /* MPEG layer 2 */
16003       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
16004           "mpegversion", G_TYPE_INT, 1, NULL);
16005       break;
16006     case 0x20736d:
16007     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
16008       _codec ("EAC-3 audio");
16009       caps = gst_caps_new_simple ("audio/x-eac3",
16010           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
16011       entry->sampled = TRUE;
16012       break;
16013     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
16014     case FOURCC_ac_3:
16015       _codec ("AC-3 audio");
16016       caps = gst_caps_new_simple ("audio/x-ac3",
16017           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
16018       entry->sampled = TRUE;
16019       break;
16020     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
16021     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
16022       _codec ("DTS audio");
16023       caps = gst_caps_new_simple ("audio/x-dts",
16024           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
16025       entry->sampled = TRUE;
16026       break;
16027     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
16028     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
16029       _codec ("DTS-HD audio");
16030       caps = gst_caps_new_simple ("audio/x-dts",
16031           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
16032       entry->sampled = TRUE;
16033       break;
16034     case FOURCC_MAC3:
16035       _codec ("MACE-3");
16036       caps = gst_caps_new_simple ("audio/x-mace",
16037           "maceversion", G_TYPE_INT, 3, NULL);
16038       break;
16039     case FOURCC_MAC6:
16040       _codec ("MACE-6");
16041       caps = gst_caps_new_simple ("audio/x-mace",
16042           "maceversion", G_TYPE_INT, 6, NULL);
16043       break;
16044     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
16045       /* ogg/vorbis */
16046       caps = gst_caps_new_empty_simple ("application/ogg");
16047       break;
16048     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
16049       _codec ("DV audio");
16050       caps = gst_caps_new_empty_simple ("audio/x-dv");
16051       break;
16052     case FOURCC_mp4a:
16053       _codec ("MPEG-4 AAC audio");
16054       caps = gst_caps_new_simple ("audio/mpeg",
16055           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
16056           "stream-format", G_TYPE_STRING, "raw", NULL);
16057       break;
16058     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
16059       _codec ("QDesign Music");
16060       caps = gst_caps_new_empty_simple ("audio/x-qdm");
16061       break;
16062     case FOURCC_QDM2:
16063       _codec ("QDesign Music v.2");
16064       /* FIXME: QDesign music version 2 (no constant) */
16065       if (FALSE && data) {
16066         caps = gst_caps_new_simple ("audio/x-qdm2",
16067             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
16068             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
16069             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
16070       } else {
16071         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
16072       }
16073       break;
16074     case FOURCC_agsm:
16075       _codec ("GSM audio");
16076       caps = gst_caps_new_empty_simple ("audio/x-gsm");
16077       break;
16078     case FOURCC_samr:
16079       _codec ("AMR audio");
16080       caps = gst_caps_new_empty_simple ("audio/AMR");
16081       break;
16082     case FOURCC_sawb:
16083       _codec ("AMR-WB audio");
16084       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
16085       break;
16086     case FOURCC_ima4:
16087       _codec ("Quicktime IMA ADPCM");
16088       caps = gst_caps_new_simple ("audio/x-adpcm",
16089           "layout", G_TYPE_STRING, "quicktime", NULL);
16090       break;
16091     case FOURCC_alac:
16092       _codec ("Apple lossless audio");
16093       caps = gst_caps_new_empty_simple ("audio/x-alac");
16094       break;
16095     case FOURCC_fLaC:
16096       _codec ("Free Lossless Audio Codec");
16097       caps = gst_caps_new_simple ("audio/x-flac",
16098           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
16099       break;
16100     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
16101       _codec ("QualComm PureVoice");
16102       caps = gst_caps_from_string ("audio/qcelp");
16103       break;
16104     case FOURCC_wma_:
16105     case FOURCC_owma:
16106       _codec ("WMA");
16107       caps = gst_caps_new_empty_simple ("audio/x-wma");
16108       break;
16109     case FOURCC_opus:
16110       _codec ("Opus");
16111       caps = gst_caps_new_empty_simple ("audio/x-opus");
16112       break;
16113     case FOURCC_lpcm:
16114     {
16115       guint32 flags = 0;
16116       guint32 depth = 0;
16117       guint32 width = 0;
16118       GstAudioFormat format;
16119       enum
16120       {
16121         FLAG_IS_FLOAT = 0x1,
16122         FLAG_IS_BIG_ENDIAN = 0x2,
16123         FLAG_IS_SIGNED = 0x4,
16124         FLAG_IS_PACKED = 0x8,
16125         FLAG_IS_ALIGNED_HIGH = 0x10,
16126         FLAG_IS_NON_INTERLEAVED = 0x20
16127       };
16128       _codec ("Raw LPCM audio");
16129
16130       if (data && len >= 36) {
16131         depth = QT_UINT32 (data + 24);
16132         flags = QT_UINT32 (data + 28);
16133         width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
16134       }
16135       if ((flags & FLAG_IS_FLOAT) == 0) {
16136         if (depth == 0)
16137           depth = 16;
16138         if (width == 0)
16139           width = 16;
16140         if ((flags & FLAG_IS_ALIGNED_HIGH))
16141           depth = width;
16142
16143         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
16144             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
16145             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
16146         caps = gst_caps_new_simple ("audio/x-raw",
16147             "format", G_TYPE_STRING,
16148             format !=
16149             GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
16150             "UNKNOWN", "layout", G_TYPE_STRING,
16151             (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
16152             "interleaved", NULL);
16153         stream->alignment = GST_ROUND_UP_8 (depth);
16154         stream->alignment = round_up_pow2 (stream->alignment);
16155       } else {
16156         if (width == 0)
16157           width = 32;
16158         if (width == 64) {
16159           if (flags & FLAG_IS_BIG_ENDIAN)
16160             format = GST_AUDIO_FORMAT_F64BE;
16161           else
16162             format = GST_AUDIO_FORMAT_F64LE;
16163         } else {
16164           if (flags & FLAG_IS_BIG_ENDIAN)
16165             format = GST_AUDIO_FORMAT_F32BE;
16166           else
16167             format = GST_AUDIO_FORMAT_F32LE;
16168         }
16169         caps = gst_caps_new_simple ("audio/x-raw",
16170             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
16171             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
16172             "non-interleaved" : "interleaved", NULL);
16173         stream->alignment = width / 8;
16174       }
16175       break;
16176     }
16177     case GST_MAKE_FOURCC ('a', 'c', '-', '4'):
16178     {
16179       _codec ("AC4");
16180       caps = gst_caps_new_empty_simple ("audio/x-ac4");
16181       break;
16182     }
16183     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
16184       /* ? */
16185     default:
16186     {
16187       caps = _get_unknown_codec_name ("audio", fourcc);
16188       break;
16189     }
16190   }
16191
16192   if (caps) {
16193     GstCaps *templ_caps =
16194         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
16195     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
16196     gst_caps_unref (caps);
16197     gst_caps_unref (templ_caps);
16198     caps = intersection;
16199   }
16200
16201   /* enable clipping for raw audio streams */
16202   s = gst_caps_get_structure (caps, 0);
16203   name = gst_structure_get_name (s);
16204   if (g_str_has_prefix (name, "audio/x-raw")) {
16205     stream->need_clip = TRUE;
16206     stream->min_buffer_size = 1024 * entry->bytes_per_frame;
16207     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
16208     GST_DEBUG ("setting min/max buffer sizes to %d/%d", stream->min_buffer_size,
16209         stream->max_buffer_size);
16210   }
16211   return caps;
16212 }
16213
16214 static GstCaps *
16215 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16216     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16217     const guint8 * stsd_entry_data, gchar ** codec_name)
16218 {
16219   GstCaps *caps;
16220
16221   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
16222
16223   switch (fourcc) {
16224     case FOURCC_mp4s:
16225       _codec ("DVD subtitle");
16226       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
16227       stream->process_func = gst_qtdemux_process_buffer_dvd;
16228       break;
16229     case FOURCC_text:
16230       _codec ("Quicktime timed text");
16231       goto text;
16232     case FOURCC_tx3g:
16233       _codec ("3GPP timed text");
16234     text:
16235       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
16236           "utf8", NULL);
16237       /* actual text piece needs to be extracted */
16238       stream->process_func = gst_qtdemux_process_buffer_text;
16239       break;
16240     case FOURCC_stpp:
16241       _codec ("XML subtitles");
16242       caps = gst_caps_new_empty_simple ("application/ttml+xml");
16243       break;
16244     case FOURCC_wvtt:
16245     {
16246       GstBuffer *buffer;
16247       const gchar *buf = "WEBVTT\n\n";
16248
16249       _codec ("WebVTT subtitles");
16250       caps = gst_caps_new_empty_simple ("application/x-subtitle-vtt");
16251       stream->process_func = gst_qtdemux_process_buffer_wvtt;
16252
16253       /* FIXME: Parse the vttC atom and get the entire WEBVTT header */
16254       buffer = gst_buffer_new_and_alloc (8);
16255       gst_buffer_fill (buffer, 0, buf, 8);
16256       stream->buffers = g_slist_append (stream->buffers, buffer);
16257
16258       break;
16259     }
16260     case FOURCC_c608:
16261       _codec ("CEA 608 Closed Caption");
16262       caps =
16263           gst_caps_new_simple ("closedcaption/x-cea-608", "format",
16264           G_TYPE_STRING, "s334-1a", NULL);
16265       stream->process_func = gst_qtdemux_process_buffer_clcp;
16266       stream->need_split = TRUE;
16267       break;
16268     case FOURCC_c708:
16269       _codec ("CEA 708 Closed Caption");
16270       caps =
16271           gst_caps_new_simple ("closedcaption/x-cea-708", "format",
16272           G_TYPE_STRING, "cdp", NULL);
16273       stream->process_func = gst_qtdemux_process_buffer_clcp;
16274       break;
16275
16276     default:
16277     {
16278       caps = _get_unknown_codec_name ("text", fourcc);
16279       break;
16280     }
16281   }
16282   return caps;
16283 }
16284
16285 static GstCaps *
16286 qtdemux_meta_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16287     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16288     const guint8 * stsd_entry_data, gchar ** codec_name)
16289 {
16290   GstCaps *caps = NULL;
16291
16292   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
16293
16294   switch (fourcc) {
16295     case FOURCC_metx:{
16296       gsize size = QT_UINT32 (stsd_entry_data);
16297       GstByteReader reader = GST_BYTE_READER_INIT (stsd_entry_data, size);
16298       const gchar *content_encoding;
16299       const gchar *namespaces;
16300       const gchar *schema_locations;
16301
16302       if (!gst_byte_reader_skip (&reader, 8 + 6 + 2)) {
16303         GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
16304         break;
16305       }
16306
16307       if (!gst_byte_reader_get_string (&reader, &content_encoding) ||
16308           !gst_byte_reader_get_string (&reader, &namespaces) ||
16309           !gst_byte_reader_get_string (&reader, &schema_locations)) {
16310         GST_WARNING_OBJECT (qtdemux, "Too short metx sample entry");
16311         break;
16312       }
16313
16314       if (strstr (namespaces, "http://www.onvif.org/ver10/schema") != 0) {
16315         if (content_encoding == NULL || *content_encoding == '\0'
16316             || g_ascii_strcasecmp (content_encoding, "xml") == 0) {
16317           _codec ("ONVIF Timed XML MetaData");
16318           caps =
16319               gst_caps_new_simple ("application/x-onvif-metadata", "parsed",
16320               G_TYPE_BOOLEAN, TRUE, NULL);
16321         } else {
16322           GST_DEBUG_OBJECT (qtdemux, "Unknown content encoding: %s",
16323               content_encoding);
16324         }
16325       } else {
16326         GST_DEBUG_OBJECT (qtdemux, "Unknown metadata namespaces: %s",
16327             namespaces);
16328       }
16329
16330       break;
16331     }
16332     default:
16333       break;
16334   }
16335
16336   if (!caps)
16337     caps = _get_unknown_codec_name ("meta", fourcc);
16338
16339   return caps;
16340 }
16341
16342 static GstCaps *
16343 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16344     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16345     const guint8 * stsd_entry_data, gchar ** codec_name)
16346 {
16347   GstCaps *caps;
16348
16349   switch (fourcc) {
16350     case FOURCC_m1v:
16351       _codec ("MPEG 1 video");
16352       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
16353           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
16354       break;
16355     default:
16356       caps = NULL;
16357       break;
16358   }
16359   return caps;
16360 }
16361
16362 static void
16363 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
16364     const gchar * system_id)
16365 {
16366   gint i;
16367
16368   if (!qtdemux->protection_system_ids)
16369     qtdemux->protection_system_ids =
16370         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
16371   /* Check whether we already have an entry for this system ID. */
16372   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
16373     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
16374     if (g_ascii_strcasecmp (system_id, id) == 0) {
16375       return;
16376     }
16377   }
16378   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
16379   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
16380           -1));
16381 }