qtdemux: Fix the problem that framerate don't include in caps
[platform/upstream/gst-plugins-good.git] / 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  *
33  * Demuxes a .mov file into raw or compressed audio and/or video streams.
34  *
35  * This element supports both push and pull-based scheduling, depending on the
36  * capabilities of the upstream elements.
37  *
38  * <refsect2>
39  * <title>Example launch line</title>
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  * </refsect2>
47  */
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif
52
53 #include "gst/gst-i18n-plugin.h"
54
55 #include <glib/gprintf.h>
56 #include <gst/tag/tag.h>
57 #include <gst/audio/audio.h>
58 #include <gst/video/video.h>
59 #include <gst/riff/riff.h>
60 #include <gst/pbutils/pbutils.h>
61
62 #include "qtatomparser.h"
63 #include "qtdemux_types.h"
64 #include "qtdemux_dump.h"
65 #include "fourcc.h"
66 #include "descriptors.h"
67 #include "qtdemux_lang.h"
68 #include "qtdemux.h"
69 #include "qtpalette.h"
70
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74
75 #include <math.h>
76 #include <gst/math-compat.h>
77
78 #ifdef HAVE_ZLIB
79 #include <zlib.h>
80 #endif
81
82 /* max. size considered 'sane' for non-mdat atoms */
83 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
84
85 /* if the sample index is larger than this, something is likely wrong */
86 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (200*1024*1024)
87
88 /* For converting qt creation times to unix epoch times */
89 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
90 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
91 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
92     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
93
94 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
95
96 #define STREAM_IS_EOS(s) ((s)->time_position == GST_CLOCK_TIME_NONE)
97
98 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
99
100 #define QTDEMUX_STREAM(s) ((QtDemuxStream *)(s))
101 #define QTDEMUX_N_STREAMS(demux) ((demux)->active_streams->len)
102 #define QTDEMUX_NTH_STREAM(demux,idx) \
103    QTDEMUX_STREAM(g_ptr_array_index((demux)->active_streams,idx))
104 #define QTDEMUX_NTH_OLD_STREAM(demux,idx) \
105    QTDEMUX_STREAM(g_ptr_array_index((demux)->old_streams,idx))
106
107 GST_DEBUG_CATEGORY (qtdemux_debug);
108 #define GST_CAT_DEFAULT qtdemux_debug
109
110 typedef struct _QtDemuxSegment QtDemuxSegment;
111 typedef struct _QtDemuxSample QtDemuxSample;
112
113 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
114
115 struct _QtDemuxSample
116 {
117   guint32 size;
118   gint32 pts_offset;            /* Add this value to timestamp to get the pts */
119   guint64 offset;
120   guint64 timestamp;            /* DTS In mov time */
121   guint32 duration;             /* In mov time */
122   gboolean keyframe;            /* TRUE when this packet is a keyframe */
123 };
124
125 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
126 typedef struct _QtDemuxSphericalMetadata QtDemuxSphericalMetadata;
127
128 struct _QtDemuxSphericalMetadata
129 {
130   gboolean is_spherical;
131   gboolean is_stitched;
132   char *stitching_software;
133   char *projection_type;
134   char *stereo_mode;
135   int source_count;
136   int init_view_heading;
137   int init_view_pitch;
138   int init_view_roll;
139   int timestamp;
140   int full_pano_width_pixels;
141   int full_pano_height_pixels;
142   int cropped_area_image_width;
143   int cropped_area_image_height;
144   int cropped_area_left;
145   int cropped_area_top;
146   QTDEMUX_AMBISONIC_TYPE ambisonic_type;
147   QTDEMUX_AMBISONIC_FORMAT ambisonic_format;
148   QTDEMUX_AMBISONIC_ORDER ambisonic_order;
149 };
150
151 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
152
153 /* Macros for converting to/from timescale */
154 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
155 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
156
157 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
158 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
159
160 /* timestamp is the DTS */
161 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
162 /* timestamp + offset + cslg_shift is the outgoing PTS */
163 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
164 /* timestamp + offset is the PTS used for internal seek calcuations */
165 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
166 /* timestamp + duration - dts is the duration */
167 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
168
169 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
170
171 #define QTDEMUX_EXPOSE_GET_LOCK(demux) (&((demux)->expose_lock))
172 #define QTDEMUX_EXPOSE_LOCK(demux) G_STMT_START { \
173     GST_TRACE("Locking from thread %p", g_thread_self()); \
174     g_mutex_lock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
175     GST_TRACE("Locked from thread %p", g_thread_self()); \
176  } G_STMT_END
177
178 #define QTDEMUX_EXPOSE_UNLOCK(demux) G_STMT_START { \
179     GST_TRACE("Unlocking from thread %p", g_thread_self()); \
180     g_mutex_unlock (QTDEMUX_EXPOSE_GET_LOCK (demux)); \
181  } G_STMT_END
182
183 /*
184  * Quicktime has tracks and segments. A track is a continuous piece of
185  * multimedia content. The track is not always played from start to finish but
186  * instead, pieces of the track are 'cut out' and played in sequence. This is
187  * what the segments do.
188  *
189  * Inside the track we have keyframes (K) and delta frames. The track has its
190  * own timing, which starts from 0 and extends to end. The position in the track
191  * is called the media_time.
192  *
193  * The segments now describe the pieces that should be played from this track
194  * and are basically tuples of media_time/duration/rate entries. We can have
195  * multiple segments and they are all played after one another. An example:
196  *
197  * segment 1: media_time: 1 second, duration: 1 second, rate 1
198  * segment 2: media_time: 3 second, duration: 2 second, rate 2
199  *
200  * To correctly play back this track, one must play: 1 second of media starting
201  * from media_time 1 followed by 2 seconds of media starting from media_time 3
202  * at a rate of 2.
203  *
204  * Each of the segments will be played at a specific time, the first segment at
205  * time 0, the second one after the duration of the first one, etc.. Note that
206  * the time in resulting playback is not identical to the media_time of the
207  * track anymore.
208  *
209  * Visually, assuming the track has 4 second of media_time:
210  *
211  *                (a)                   (b)          (c)              (d)
212  *         .-----------------------------------------------------------.
213  * track:  | K.....K.........K........K.......K.......K...........K... |
214  *         '-----------------------------------------------------------'
215  *         0              1              2              3              4
216  *           .------------^              ^   .----------^              ^
217  *          /              .-------------'  /       .------------------'
218  *         /              /          .-----'       /
219  *         .--------------.         .--------------.
220  *         | segment 1    |         | segment 2    |
221  *         '--------------'         '--------------'
222  *
223  * The challenge here is to cut out the right pieces of the track for each of
224  * the playback segments. This fortunately can easily be done with the SEGMENT
225  * events of GStreamer.
226  *
227  * For playback of segment 1, we need to provide the decoder with the keyframe
228  * (a), in the above figure, but we must instruct it only to output the decoded
229  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
230  * position set to the time of the segment: 0.
231  *
232  * We then proceed to push data from keyframe (a) to frame (b). The decoder
233  * decodes but clips all before media_time 1.
234  *
235  * After finishing a segment, we push out a new SEGMENT event with the clipping
236  * boundaries of the new data.
237  *
238  * This is a good usecase for the GStreamer accumulated SEGMENT events.
239  */
240
241 struct _QtDemuxSegment
242 {
243   /* global time and duration, all gst time */
244   GstClockTime time;
245   GstClockTime stop_time;
246   GstClockTime duration;
247   /* media time of trak, all gst time */
248   GstClockTime media_start;
249   GstClockTime media_stop;
250   gdouble rate;
251   /* Media start time in trak timescale units */
252   guint32 trak_media_start;
253 };
254
255 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
256
257 /* Used with fragmented MP4 files (mfra atom) */
258 typedef struct
259 {
260   GstClockTime ts;
261   guint64 moof_offset;
262 } QtDemuxRandomAccessEntry;
263
264 typedef struct _QtDemuxStreamStsdEntry
265 {
266   GstCaps *caps;
267   guint32 fourcc;
268   gboolean sparse;
269
270   /* video info */
271   gint width;
272   gint height;
273   gint par_w;
274   gint par_h;
275   /* Numerator/denominator framerate */
276   gint fps_n;
277   gint fps_d;
278   GstVideoColorimetry colorimetry;
279   guint16 bits_per_sample;
280   guint16 color_table_id;
281   GstMemory *rgb8_palette;
282   guint interlace_mode;
283   guint field_order;
284
285   /* audio info */
286   gdouble rate;
287   gint n_channels;
288   guint samples_per_packet;
289   guint samples_per_frame;
290   guint bytes_per_packet;
291   guint bytes_per_sample;
292   guint bytes_per_frame;
293   guint compression;
294
295   /* if we use chunks or samples */
296   gboolean sampled;
297   guint padding;
298
299 } QtDemuxStreamStsdEntry;
300
301 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
302
303 struct _QtDemuxStream
304 {
305   GstPad *pad;
306
307   GstQTDemux *demux;
308   gchar *stream_id;
309
310   QtDemuxStreamStsdEntry *stsd_entries;
311   guint stsd_entries_length;
312   guint cur_stsd_entry_index;
313
314   /* stream type */
315   guint32 subtype;
316
317   gboolean new_caps;            /* If TRUE, caps need to be generated (by
318                                  * calling _configure_stream()) This happens
319                                  * for MSS and fragmented streams */
320
321   gboolean new_stream;          /* signals that a stream_start is required */
322   gboolean on_keyframe;         /* if this stream last pushed buffer was a
323                                  * keyframe. This is important to identify
324                                  * where to stop pushing buffers after a
325                                  * segment stop time */
326
327   /* if the stream has a redirect URI in its headers, we store it here */
328   gchar *redirect_uri;
329
330   /* track id */
331   guint track_id;
332
333   /* duration/scale */
334   guint64 duration;             /* in timescale units */
335   guint32 timescale;
336
337   /* language */
338   gchar lang_id[4];             /* ISO 639-2T language code */
339
340   /* our samples */
341   guint32 n_samples;
342   QtDemuxSample *samples;
343   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
344   guint32 n_samples_moof;       /* sample count in a moof */
345   guint64 duration_moof;        /* duration in timescale of a moof, used for figure out
346                                  * the framerate of fragmented format stream */
347   guint64 duration_last_moof;
348
349   guint32 offset_in_sample;     /* Offset in the current sample, used for
350                                  * streams which have got exceedingly big
351                                  * sample size (such as 24s of raw audio).
352                                  * Only used when max_buffer_size is non-NULL */
353   guint32 max_buffer_size;      /* Maximum allowed size for output buffers.
354                                  * Currently only set for raw audio streams*/
355
356   /* video info */
357   /* aspect ratio */
358   gint display_width;
359   gint display_height;
360
361   /* allocation */
362   gboolean use_allocator;
363   GstAllocator *allocator;
364   GstAllocationParams params;
365
366   gsize alignment;
367
368   /* when a discontinuity is pending */
369   gboolean discont;
370
371   /* list of buffers to push first */
372   GSList *buffers;
373
374   /* if we need to clip this buffer. This is only needed for uncompressed
375    * data */
376   gboolean need_clip;
377
378   /* buffer needs some custom processing, e.g. subtitles */
379   gboolean need_process;
380   /* buffer needs potentially be split, e.g. CEA608 subtitles */
381   gboolean need_split;
382
383   /* current position */
384   guint32 segment_index;
385   guint32 sample_index;
386   GstClockTime time_position;   /* in gst time */
387   guint64 accumulated_base;
388
389   /* the Gst segment we are processing out, used for clipping */
390   GstSegment segment;
391
392   /* quicktime segments */
393   guint32 n_segments;
394   QtDemuxSegment *segments;
395   gboolean dummy_segment;
396   guint32 from_sample;
397   guint32 to_sample;
398
399   gboolean sent_eos;
400   GstTagList *stream_tags;
401   gboolean send_global_tags;
402
403   GstEvent *pending_event;
404
405   GstByteReader stco;
406   GstByteReader stsz;
407   GstByteReader stsc;
408   GstByteReader stts;
409   GstByteReader stss;
410   GstByteReader stps;
411   GstByteReader ctts;
412
413   gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
414   gint64 stbl_index;
415   /* stco */
416   guint co_size;
417   GstByteReader co_chunk;
418   guint32 first_chunk;
419   guint32 current_chunk;
420   guint32 last_chunk;
421   guint32 samples_per_chunk;
422   guint32 stsd_sample_description_id;
423   guint32 stco_sample_index;
424   /* stsz */
425   guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
426   /* stsc */
427   guint32 stsc_index;
428   guint32 n_samples_per_chunk;
429   guint32 stsc_chunk_index;
430   guint32 stsc_sample_index;
431   guint64 chunk_offset;
432   /* stts */
433   guint32 stts_index;
434   guint32 stts_samples;
435   guint32 n_sample_times;
436   guint32 stts_sample_index;
437   guint64 stts_time;
438   guint32 stts_duration;
439   /* stss */
440   gboolean stss_present;
441   guint32 n_sample_syncs;
442   guint32 stss_index;
443   /* stps */
444   gboolean stps_present;
445   guint32 n_sample_partial_syncs;
446   guint32 stps_index;
447   QtDemuxRandomAccessEntry *ra_entries;
448   guint n_ra_entries;
449
450   const QtDemuxRandomAccessEntry *pending_seek;
451
452   /* ctts */
453   gboolean ctts_present;
454   guint32 n_composition_times;
455   guint32 ctts_index;
456   guint32 ctts_sample_index;
457   guint32 ctts_count;
458   gint32 ctts_soffset;
459
460   /* cslg */
461   guint32 cslg_shift;
462
463   /* fragmented */
464   gboolean parsed_trex;
465   guint32 def_sample_description_index; /* index is 1-based */
466   guint32 def_sample_duration;
467   guint32 def_sample_size;
468   guint32 def_sample_flags;
469
470   gboolean disabled;
471
472   /* stereoscopic video streams */
473   GstVideoMultiviewMode multiview_mode;
474   GstVideoMultiviewFlags multiview_flags;
475
476   /* protected streams */
477   gboolean protected;
478   guint32 protection_scheme_type;
479   guint32 protection_scheme_version;
480   gpointer protection_scheme_info;      /* specific to the protection scheme */
481   GQueue protection_scheme_event_queue;
482
483   gint ref_count;               /* atomic */
484 };
485
486 /* Contains properties and cryptographic info for a set of samples from a
487  * track protected using Common Encryption (cenc) */
488 struct _QtDemuxCencSampleSetInfo
489 {
490   GstStructure *default_properties;
491
492   /* @crypto_info holds one GstStructure per sample */
493   GPtrArray *crypto_info;
494 };
495
496 static const gchar *
497 qt_demux_state_string (enum QtDemuxState state)
498 {
499   switch (state) {
500     case QTDEMUX_STATE_INITIAL:
501       return "<INITIAL>";
502     case QTDEMUX_STATE_HEADER:
503       return "<HEADER>";
504     case QTDEMUX_STATE_MOVIE:
505       return "<MOVIE>";
506     case QTDEMUX_STATE_BUFFER_MDAT:
507       return "<BUFFER_MDAT>";
508     default:
509       return "<UNKNOWN>";
510   }
511 }
512
513 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
514 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
515     guint32 fourcc, GstByteReader * parser);
516 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
517 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
518     guint32 fourcc, GstByteReader * parser);
519
520 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
521
522 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
523
524 static GstStaticPadTemplate gst_qtdemux_sink_template =
525     GST_STATIC_PAD_TEMPLATE ("sink",
526     GST_PAD_SINK,
527     GST_PAD_ALWAYS,
528     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
529         "application/x-3gp")
530     );
531
532 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
533 GST_STATIC_PAD_TEMPLATE ("video_%u",
534     GST_PAD_SRC,
535     GST_PAD_SOMETIMES,
536     GST_STATIC_CAPS_ANY);
537
538 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
539 GST_STATIC_PAD_TEMPLATE ("audio_%u",
540     GST_PAD_SRC,
541     GST_PAD_SOMETIMES,
542     GST_STATIC_CAPS_ANY);
543
544 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
545 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
546     GST_PAD_SRC,
547     GST_PAD_SOMETIMES,
548     GST_STATIC_CAPS_ANY);
549
550 #define gst_qtdemux_parent_class parent_class
551 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
552
553 static void gst_qtdemux_dispose (GObject * object);
554
555 static guint32
556 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
557     GstClockTime media_time);
558 static guint32
559 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
560     QtDemuxStream * str, gint64 media_offset);
561
562 #if 0
563 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
564 static GstIndex *gst_qtdemux_get_index (GstElement * element);
565 #endif
566 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
567     GstStateChange transition);
568 static void gst_qtdemux_set_context (GstElement * element,
569     GstContext * context);
570 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
571 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
572     GstObject * parent, GstPadMode mode, gboolean active);
573
574 static void gst_qtdemux_loop (GstPad * pad);
575 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
576     GstBuffer * inbuf);
577 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
578     GstEvent * event);
579 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
580     GstQuery * query);
581 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
582 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
583     QtDemuxStream * stream);
584 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
585     QtDemuxStream * stream);
586 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
587     gboolean force);
588
589 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
590
591 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
592     const guint8 * buffer, guint length);
593 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
594     const guint8 * buffer, guint length);
595 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
596 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
597     GNode * udta);
598
599 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
600     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
601     GstTagList * list);
602 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
603     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
604     const guint8 * stsd_entry_data, gchar ** codec_name);
605 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
606     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
607     const guint8 * data, int len, gchar ** codec_name);
608 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
609     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
610     gchar ** codec_name);
611 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
612     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
613     const guint8 * stsd_entry_data, gchar ** codec_name);
614
615 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
616     QtDemuxStream * stream, guint32 n);
617 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
618 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
619 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
620 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
621 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
622 static void qtdemux_do_allocation (QtDemuxStream * stream,
623     GstQTDemux * qtdemux);
624 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
625     QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
626 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
627     QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
628     GstClockTime * _start, GstClockTime * _stop);
629 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
630     QtDemuxStream * stream, gint segment_index, GstClockTime pos);
631
632 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
633 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
634
635 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
636
637 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
638     QtDemuxStream * stream, guint sample_index);
639 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
640     const gchar * id);
641 static void qtdemux_gst_structure_free (GstStructure * gststructure);
642 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
643
644 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
645 static void gst_tag_register_spherical_tags (void);
646 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
647
648 static void
649 gst_qtdemux_class_init (GstQTDemuxClass * klass)
650 {
651   GObjectClass *gobject_class;
652   GstElementClass *gstelement_class;
653
654   gobject_class = (GObjectClass *) klass;
655   gstelement_class = (GstElementClass *) klass;
656
657   parent_class = g_type_class_peek_parent (klass);
658
659   gobject_class->dispose = gst_qtdemux_dispose;
660
661   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
662 #if 0
663   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
664   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
665 #endif
666   gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
667
668   gst_tag_register_musicbrainz_tags ();
669
670 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
671   gst_tag_register_spherical_tags ();
672 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
673
674   gst_element_class_add_static_pad_template (gstelement_class,
675       &gst_qtdemux_sink_template);
676   gst_element_class_add_static_pad_template (gstelement_class,
677       &gst_qtdemux_videosrc_template);
678   gst_element_class_add_static_pad_template (gstelement_class,
679       &gst_qtdemux_audiosrc_template);
680   gst_element_class_add_static_pad_template (gstelement_class,
681       &gst_qtdemux_subsrc_template);
682   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
683       "Codec/Demuxer",
684       "Demultiplex a QuickTime file into audio and video streams",
685       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
686
687   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
688   gst_riff_init ();
689 }
690
691 static void
692 gst_qtdemux_init (GstQTDemux * qtdemux)
693 {
694   qtdemux->sinkpad =
695       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
696   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
697   gst_pad_set_activatemode_function (qtdemux->sinkpad,
698       qtdemux_sink_activate_mode);
699   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
700   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
701   gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
702   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
703
704   qtdemux->adapter = gst_adapter_new ();
705   g_queue_init (&qtdemux->protection_event_queue);
706   qtdemux->flowcombiner = gst_flow_combiner_new ();
707   g_mutex_init (&qtdemux->expose_lock);
708
709   qtdemux->active_streams = g_ptr_array_new_with_free_func
710       ((GDestroyNotify) gst_qtdemux_stream_unref);
711   qtdemux->old_streams = g_ptr_array_new_with_free_func
712       ((GDestroyNotify) gst_qtdemux_stream_unref);
713
714 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
715   qtdemux->spherical_metadata = (QtDemuxSphericalMetadata *)
716       malloc (sizeof (QtDemuxSphericalMetadata));
717
718   if (qtdemux->spherical_metadata) {
719     qtdemux->spherical_metadata->is_spherical = FALSE;
720     qtdemux->spherical_metadata->is_stitched = FALSE;
721     qtdemux->spherical_metadata->stitching_software = NULL;
722     qtdemux->spherical_metadata->projection_type = NULL;
723     qtdemux->spherical_metadata->stereo_mode = NULL;
724     qtdemux->spherical_metadata->source_count = 0;
725     qtdemux->spherical_metadata->init_view_heading = 0;
726     qtdemux->spherical_metadata->init_view_pitch = 0;
727     qtdemux->spherical_metadata->init_view_roll = 0;
728     qtdemux->spherical_metadata->timestamp = 0;
729     qtdemux->spherical_metadata->full_pano_width_pixels = 0;
730     qtdemux->spherical_metadata->full_pano_height_pixels = 0;
731     qtdemux->spherical_metadata->cropped_area_image_width = 0;
732     qtdemux->spherical_metadata->cropped_area_image_height = 0;
733     qtdemux->spherical_metadata->cropped_area_left = 0;
734     qtdemux->spherical_metadata->cropped_area_top = 0;
735     qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
736     qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_UNKNOWN;
737     qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_UNKNOWN;
738   }
739 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
740
741   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
742
743   gst_qtdemux_reset (qtdemux, TRUE);
744 }
745
746 static void
747 gst_qtdemux_dispose (GObject * object)
748 {
749   GstQTDemux *qtdemux = GST_QTDEMUX (object);
750
751 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
752   if (qtdemux->spherical_metadata) {
753     if (qtdemux->spherical_metadata->stitching_software)
754       free(qtdemux->spherical_metadata->stitching_software);
755     if (qtdemux->spherical_metadata->projection_type)
756       free(qtdemux->spherical_metadata->projection_type);
757     if (qtdemux->spherical_metadata->stereo_mode)
758       free(qtdemux->spherical_metadata->stereo_mode);
759
760     free(qtdemux->spherical_metadata);
761     qtdemux->spherical_metadata = NULL;
762   }
763 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
764
765   if (qtdemux->adapter) {
766     g_object_unref (G_OBJECT (qtdemux->adapter));
767     qtdemux->adapter = NULL;
768   }
769   gst_tag_list_unref (qtdemux->tag_list);
770   gst_flow_combiner_free (qtdemux->flowcombiner);
771   g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
772       NULL);
773   g_queue_clear (&qtdemux->protection_event_queue);
774
775   g_free (qtdemux->cenc_aux_info_sizes);
776   qtdemux->cenc_aux_info_sizes = NULL;
777   g_mutex_clear (&qtdemux->expose_lock);
778
779   g_ptr_array_free (qtdemux->active_streams, TRUE);
780   g_ptr_array_free (qtdemux->old_streams, TRUE);
781
782   G_OBJECT_CLASS (parent_class)->dispose (object);
783 }
784
785 static void
786 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
787 {
788   if (qtdemux->posted_redirect) {
789     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
790         (_("This file contains no playable streams.")),
791         ("no known streams found, a redirect message has been posted"));
792   } else {
793     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
794         (_("This file contains no playable streams.")),
795         ("no known streams found"));
796   }
797 }
798
799 static GstBuffer *
800 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
801 {
802   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
803       mem, size, 0, size, mem, free_func);
804 }
805
806 static GstFlowReturn
807 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
808     GstBuffer ** buf)
809 {
810   GstFlowReturn flow;
811   GstMapInfo map;
812   gsize bsize;
813
814   if (G_UNLIKELY (size == 0)) {
815     GstFlowReturn ret;
816     GstBuffer *tmp = NULL;
817
818     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
819     if (ret != GST_FLOW_OK)
820       return ret;
821
822     gst_buffer_map (tmp, &map, GST_MAP_READ);
823     size = QT_UINT32 (map.data);
824     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
825
826     gst_buffer_unmap (tmp, &map);
827     gst_buffer_unref (tmp);
828   }
829
830   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
831   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
832     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
833       /* we're pulling header but already got most interesting bits,
834        * so never mind the rest (e.g. tags) (that much) */
835       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
836           size);
837       return GST_FLOW_EOS;
838     } else {
839       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
840           (_("This file is invalid and cannot be played.")),
841           ("atom has bogus size %" G_GUINT64_FORMAT, size));
842       return GST_FLOW_ERROR;
843     }
844   }
845
846   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
847
848   if (G_UNLIKELY (flow != GST_FLOW_OK))
849     return flow;
850
851   bsize = gst_buffer_get_size (*buf);
852   /* Catch short reads - we don't want any partial atoms */
853   if (G_UNLIKELY (bsize < size)) {
854     GST_WARNING_OBJECT (qtdemux,
855         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
856     gst_buffer_unref (*buf);
857     *buf = NULL;
858     return GST_FLOW_EOS;
859   }
860
861   return flow;
862 }
863
864 #if 1
865 static gboolean
866 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
867     GstFormat src_format, gint64 src_value, GstFormat dest_format,
868     gint64 * dest_value)
869 {
870   gboolean res = TRUE;
871   QtDemuxStream *stream = gst_pad_get_element_private (pad);
872   gint32 index;
873
874   if (stream->subtype != FOURCC_vide) {
875     res = FALSE;
876     goto done;
877   }
878
879   switch (src_format) {
880     case GST_FORMAT_TIME:
881       switch (dest_format) {
882         case GST_FORMAT_BYTES:{
883           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
884           if (-1 == index) {
885             res = FALSE;
886             goto done;
887           }
888
889           *dest_value = stream->samples[index].offset;
890
891           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
892               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
893               GST_TIME_ARGS (src_value), *dest_value);
894           break;
895         }
896         default:
897           res = FALSE;
898           break;
899       }
900       break;
901     case GST_FORMAT_BYTES:
902       switch (dest_format) {
903         case GST_FORMAT_TIME:{
904           index =
905               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
906               stream, src_value);
907
908           if (-1 == index) {
909             res = FALSE;
910             goto done;
911           }
912
913           *dest_value =
914               QTSTREAMTIME_TO_GSTTIME (stream,
915               stream->samples[index].timestamp);
916           GST_DEBUG_OBJECT (qtdemux,
917               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
918               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
919           break;
920         }
921         default:
922           res = FALSE;
923           break;
924       }
925       break;
926     default:
927       res = FALSE;
928       break;
929   }
930
931 done:
932   return res;
933 }
934 #endif
935
936 static gboolean
937 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
938 {
939   gboolean res = FALSE;
940
941   *duration = GST_CLOCK_TIME_NONE;
942
943   if (qtdemux->duration != 0 &&
944       qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
945     *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
946     res = TRUE;
947   } else {
948     *duration = GST_CLOCK_TIME_NONE;
949   }
950
951   return res;
952 }
953
954 static gboolean
955 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
956     GstQuery * query)
957 {
958   gboolean res = FALSE;
959   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
960
961   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
962
963   switch (GST_QUERY_TYPE (query)) {
964     case GST_QUERY_POSITION:{
965       GstFormat fmt;
966
967       gst_query_parse_position (query, &fmt, NULL);
968       if (fmt == GST_FORMAT_TIME
969           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
970         gst_query_set_position (query, GST_FORMAT_TIME,
971             qtdemux->segment.position);
972         res = TRUE;
973       }
974     }
975       break;
976     case GST_QUERY_DURATION:{
977       GstFormat fmt;
978
979       gst_query_parse_duration (query, &fmt, NULL);
980       if (fmt == GST_FORMAT_TIME) {
981         /* First try to query upstream */
982         res = gst_pad_query_default (pad, parent, query);
983         if (!res) {
984           GstClockTime duration;
985           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
986             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
987             res = TRUE;
988           }
989         }
990       }
991       break;
992     }
993     case GST_QUERY_CONVERT:{
994       GstFormat src_fmt, dest_fmt;
995       gint64 src_value, dest_value = 0;
996
997       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
998
999       res = gst_qtdemux_src_convert (qtdemux, pad,
1000           src_fmt, src_value, dest_fmt, &dest_value);
1001       if (res)
1002         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
1003
1004       break;
1005     }
1006     case GST_QUERY_FORMATS:
1007       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
1008       res = TRUE;
1009       break;
1010     case GST_QUERY_SEEKING:{
1011       GstFormat fmt;
1012       gboolean seekable;
1013
1014       /* try upstream first */
1015       res = gst_pad_query_default (pad, parent, query);
1016
1017       if (!res) {
1018         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1019         if (fmt == GST_FORMAT_TIME) {
1020           GstClockTime duration;
1021
1022           gst_qtdemux_get_duration (qtdemux, &duration);
1023           seekable = TRUE;
1024           if (!qtdemux->pullbased) {
1025             GstQuery *q;
1026
1027             /* we might be able with help from upstream */
1028             seekable = FALSE;
1029             q = gst_query_new_seeking (GST_FORMAT_BYTES);
1030             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
1031               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
1032               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
1033             }
1034             gst_query_unref (q);
1035           }
1036           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
1037           res = TRUE;
1038         }
1039       }
1040       break;
1041     }
1042     case GST_QUERY_SEGMENT:
1043     {
1044       GstFormat format;
1045       gint64 start, stop;
1046
1047       format = qtdemux->segment.format;
1048
1049       start =
1050           gst_segment_to_stream_time (&qtdemux->segment, format,
1051           qtdemux->segment.start);
1052       if ((stop = qtdemux->segment.stop) == -1)
1053         stop = qtdemux->segment.duration;
1054       else
1055         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
1056
1057       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
1058       res = TRUE;
1059       break;
1060     }
1061     default:
1062       res = gst_pad_query_default (pad, parent, query);
1063       break;
1064   }
1065
1066   return res;
1067 }
1068
1069 static void
1070 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
1071 {
1072   if (G_LIKELY (stream->pad)) {
1073     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
1074         GST_DEBUG_PAD_NAME (stream->pad));
1075
1076     if (!gst_tag_list_is_empty (stream->stream_tags)) {
1077       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
1078           stream->stream_tags);
1079       gst_pad_push_event (stream->pad,
1080           gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
1081 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
1082       /* post message qtdemux tag (for early recive application) */
1083       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1084             gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
1085                   gst_tag_list_copy (stream->stream_tags)));
1086 #endif
1087     }
1088
1089     if (G_UNLIKELY (stream->send_global_tags)) {
1090       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1091           qtdemux->tag_list);
1092       gst_pad_push_event (stream->pad,
1093           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1094       stream->send_global_tags = FALSE;
1095     }
1096   }
1097 }
1098
1099 /* push event on all source pads; takes ownership of the event */
1100 static void
1101 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1102 {
1103   gboolean has_valid_stream = FALSE;
1104   GstEventType etype = GST_EVENT_TYPE (event);
1105   guint i;
1106
1107   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1108       GST_EVENT_TYPE_NAME (event));
1109
1110   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1111     GstPad *pad;
1112     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1113     GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1114
1115     if ((pad = stream->pad)) {
1116       has_valid_stream = TRUE;
1117
1118       if (etype == GST_EVENT_EOS) {
1119         /* let's not send twice */
1120         if (stream->sent_eos)
1121           continue;
1122         stream->sent_eos = TRUE;
1123       }
1124
1125       gst_pad_push_event (pad, gst_event_ref (event));
1126     }
1127   }
1128
1129   gst_event_unref (event);
1130
1131   /* if it is EOS and there are no pads, post an error */
1132   if (!has_valid_stream && etype == GST_EVENT_EOS) {
1133     gst_qtdemux_post_no_playable_stream_error (qtdemux);
1134   }
1135 }
1136
1137 typedef struct
1138 {
1139   guint64 media_time;
1140 } FindData;
1141
1142 static gint
1143 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1144 {
1145   if ((gint64) s1->timestamp > *media_time)
1146     return 1;
1147   if ((gint64) s1->timestamp == *media_time)
1148     return 0;
1149
1150   return -1;
1151 }
1152
1153 /* find the index of the sample that includes the data for @media_time using a
1154  * binary search.  Only to be called in optimized cases of linear search below.
1155  *
1156  * Returns the index of the sample with the corresponding *DTS*.
1157  */
1158 static guint32
1159 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1160     guint64 media_time)
1161 {
1162   QtDemuxSample *result;
1163   guint32 index;
1164
1165   /* convert media_time to mov format */
1166   media_time =
1167       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1168
1169   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1170       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1171       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1172
1173   if (G_LIKELY (result))
1174     index = result - str->samples;
1175   else
1176     index = 0;
1177
1178   return index;
1179 }
1180
1181
1182
1183 /* find the index of the sample that includes the data for @media_offset using a
1184  * linear search
1185  *
1186  * Returns the index of the sample.
1187  */
1188 static guint32
1189 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1190     QtDemuxStream * str, gint64 media_offset)
1191 {
1192   QtDemuxSample *result = str->samples;
1193   guint32 index = 0;
1194
1195   if (result == NULL || str->n_samples == 0)
1196     return -1;
1197
1198   if (media_offset == result->offset)
1199     return index;
1200
1201   result++;
1202   while (index < str->n_samples - 1) {
1203     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1204       goto parse_failed;
1205
1206     if (media_offset < result->offset)
1207       break;
1208
1209     index++;
1210     result++;
1211   }
1212   return index;
1213
1214   /* ERRORS */
1215 parse_failed:
1216   {
1217     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1218     return -1;
1219   }
1220 }
1221
1222 /* find the index of the sample that includes the data for @media_time using a
1223  * linear search, and keeping in mind that not all samples may have been parsed
1224  * yet.  If possible, it will delegate to binary search.
1225  *
1226  * Returns the index of the sample.
1227  */
1228 static guint32
1229 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1230     GstClockTime media_time)
1231 {
1232   guint32 index = 0;
1233   guint64 mov_time;
1234   QtDemuxSample *sample;
1235
1236   /* convert media_time to mov format */
1237   mov_time =
1238       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1239
1240   sample = str->samples;
1241   if (mov_time == sample->timestamp + sample->pts_offset)
1242     return index;
1243
1244   /* use faster search if requested time in already parsed range */
1245   sample = str->samples + str->stbl_index;
1246   if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1247     index = gst_qtdemux_find_index (qtdemux, str, media_time);
1248     sample = str->samples + index;
1249   } else {
1250     while (index < str->n_samples - 1) {
1251       if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1252         goto parse_failed;
1253
1254       sample = str->samples + index + 1;
1255       if (mov_time < sample->timestamp) {
1256         sample = str->samples + index;
1257         break;
1258       }
1259
1260       index++;
1261     }
1262   }
1263
1264   /* sample->timestamp is now <= media_time, need to find the corresponding
1265    * PTS now by looking backwards */
1266   while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1267     index--;
1268     sample = str->samples + index;
1269   }
1270
1271   return index;
1272
1273   /* ERRORS */
1274 parse_failed:
1275   {
1276     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1277     return -1;
1278   }
1279 }
1280
1281 /* find the index of the keyframe needed to decode the sample at @index
1282  * of stream @str, or of a subsequent keyframe (depending on @next)
1283  *
1284  * Returns the index of the keyframe.
1285  */
1286 static guint32
1287 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1288     guint32 index, gboolean next)
1289 {
1290   guint32 new_index = index;
1291
1292   if (index >= str->n_samples) {
1293     new_index = str->n_samples;
1294     goto beach;
1295   }
1296
1297   /* all keyframes, return index */
1298   if (str->all_keyframe) {
1299     new_index = index;
1300     goto beach;
1301   }
1302
1303   /* else search until we have a keyframe */
1304   while (new_index < str->n_samples) {
1305     if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1306       goto parse_failed;
1307
1308     if (str->samples[new_index].keyframe)
1309       break;
1310
1311     if (new_index == 0)
1312       break;
1313
1314     if (next)
1315       new_index++;
1316     else
1317       new_index--;
1318   }
1319
1320   if (new_index == str->n_samples) {
1321     GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1322     new_index = -1;
1323   }
1324
1325 beach:
1326   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1327       "gave %u", next ? "after" : "before", index, new_index);
1328
1329   return new_index;
1330
1331   /* ERRORS */
1332 parse_failed:
1333   {
1334     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1335     return -1;
1336   }
1337 }
1338
1339 /* find the segment for @time_position for @stream
1340  *
1341  * Returns the index of the segment containing @time_position.
1342  * Returns the last segment and sets the @eos variable to TRUE
1343  * if the time is beyond the end. @eos may be NULL
1344  */
1345 static guint32
1346 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1347     GstClockTime time_position)
1348 {
1349   gint i;
1350   guint32 seg_idx;
1351
1352   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1353       GST_TIME_ARGS (time_position));
1354
1355   seg_idx = -1;
1356   for (i = 0; i < stream->n_segments; i++) {
1357     QtDemuxSegment *segment = &stream->segments[i];
1358
1359     GST_LOG_OBJECT (stream->pad,
1360         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1361         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1362
1363     /* For the last segment we include stop_time in the last segment */
1364     if (i < stream->n_segments - 1) {
1365       if (segment->time <= time_position && time_position < segment->stop_time) {
1366         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1367         seg_idx = i;
1368         break;
1369       }
1370     } else {
1371       /* Last segment always matches */
1372       seg_idx = i;
1373       break;
1374     }
1375   }
1376   return seg_idx;
1377 }
1378
1379 /* move the stream @str to the sample position @index.
1380  *
1381  * Updates @str->sample_index and marks discontinuity if needed.
1382  */
1383 static void
1384 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1385     guint32 index)
1386 {
1387   /* no change needed */
1388   if (index == str->sample_index)
1389     return;
1390
1391   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1392       str->n_samples);
1393
1394   /* position changed, we have a discont */
1395   str->sample_index = index;
1396   str->offset_in_sample = 0;
1397   /* Each time we move in the stream we store the position where we are
1398    * starting from */
1399   str->from_sample = index;
1400   str->discont = TRUE;
1401 }
1402
1403 static void
1404 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1405     gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1406 {
1407   guint64 min_offset;
1408   gint64 min_byte_offset = -1;
1409   guint i;
1410
1411   min_offset = desired_time;
1412
1413   /* for each stream, find the index of the sample in the segment
1414    * and move back to the previous keyframe. */
1415   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1416     QtDemuxStream *str;
1417     guint32 index, kindex;
1418     guint32 seg_idx;
1419     GstClockTime media_start;
1420     GstClockTime media_time;
1421     GstClockTime seg_time;
1422     QtDemuxSegment *seg;
1423     gboolean empty_segment = FALSE;
1424
1425     str = QTDEMUX_NTH_STREAM (qtdemux, i);
1426
1427     if (CUR_STREAM (str)->sparse && !use_sparse)
1428       continue;
1429
1430     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1431     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1432
1433     /* get segment and time in the segment */
1434     seg = &str->segments[seg_idx];
1435     seg_time = (desired_time - seg->time) * seg->rate;
1436
1437     while (QTSEGMENT_IS_EMPTY (seg)) {
1438       seg_time = 0;
1439       empty_segment = TRUE;
1440       GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1441           seg_idx);
1442       seg_idx++;
1443       if (seg_idx == str->n_segments)
1444         break;
1445       seg = &str->segments[seg_idx];
1446     }
1447
1448     if (seg_idx == str->n_segments) {
1449       /* FIXME track shouldn't have the last segment as empty, but if it
1450        * happens we better handle it */
1451       continue;
1452     }
1453
1454     /* get the media time in the segment */
1455     media_start = seg->media_start + seg_time;
1456
1457     /* get the index of the sample with media time */
1458     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1459     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1460         " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1461         GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1462         empty_segment);
1463
1464     /* shift to next frame if we are looking for next keyframe */
1465     if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1466         && index < str->stbl_index)
1467       index++;
1468
1469     if (!empty_segment) {
1470       /* find previous keyframe */
1471       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1472
1473       /* we will settle for one before if none found after */
1474       if (next && kindex == -1)
1475         kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1476
1477       /* if the keyframe is at a different position, we need to update the
1478        * requested seek time */
1479       if (index != kindex) {
1480         index = kindex;
1481
1482         /* get timestamp of keyframe */
1483         media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1484         GST_DEBUG_OBJECT (qtdemux,
1485             "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1486             G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1487             str->samples[kindex].offset);
1488
1489         /* keyframes in the segment get a chance to change the
1490          * desired_offset. keyframes out of the segment are
1491          * ignored. */
1492         if (media_time >= seg->media_start) {
1493           GstClockTime seg_time;
1494
1495           /* this keyframe is inside the segment, convert back to
1496            * segment time */
1497           seg_time = (media_time - seg->media_start) + seg->time;
1498           if ((!next && (seg_time < min_offset)) ||
1499               (next && (seg_time > min_offset)))
1500             min_offset = seg_time;
1501         }
1502       }
1503     }
1504
1505     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1506       min_byte_offset = str->samples[index].offset;
1507   }
1508
1509   if (key_time)
1510     *key_time = min_offset;
1511   if (key_offset)
1512     *key_offset = min_byte_offset;
1513 }
1514
1515 static gboolean
1516 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1517     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1518 {
1519   gboolean res;
1520
1521   g_return_val_if_fail (format != NULL, FALSE);
1522   g_return_val_if_fail (cur != NULL, FALSE);
1523   g_return_val_if_fail (stop != NULL, FALSE);
1524
1525   if (*format == GST_FORMAT_TIME)
1526     return TRUE;
1527
1528   res = TRUE;
1529   if (cur_type != GST_SEEK_TYPE_NONE)
1530     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1531   if (res && stop_type != GST_SEEK_TYPE_NONE)
1532     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1533
1534   if (res)
1535     *format = GST_FORMAT_TIME;
1536
1537   return res;
1538 }
1539
1540 /* perform seek in push based mode:
1541    find BYTE position to move to based on time and delegate to upstream
1542 */
1543 static gboolean
1544 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1545 {
1546   gdouble rate;
1547   GstFormat format;
1548   GstSeekFlags flags;
1549   GstSeekType cur_type, stop_type;
1550   gint64 cur, stop, key_cur;
1551   gboolean res;
1552   gint64 byte_cur;
1553   gint64 original_stop;
1554   guint32 seqnum;
1555
1556   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1557
1558   gst_event_parse_seek (event, &rate, &format, &flags,
1559       &cur_type, &cur, &stop_type, &stop);
1560   seqnum = gst_event_get_seqnum (event);
1561
1562   /* only forward streaming and seeking is possible */
1563   if (rate <= 0)
1564     goto unsupported_seek;
1565
1566   /* convert to TIME if needed and possible */
1567   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1568           stop_type, &stop))
1569     goto no_format;
1570
1571   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1572    * the original stop position to use when upstream pushes the new segment
1573    * for this seek */
1574   original_stop = stop;
1575   stop = -1;
1576
1577   /* find reasonable corresponding BYTE position,
1578    * also try to mind about keyframes, since we can not go back a bit for them
1579    * later on */
1580   /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1581    * mostly just work, but let's not yet boldly go there  ... */
1582   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1583
1584   if (byte_cur == -1)
1585     goto abort_seek;
1586
1587   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1588       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1589       stop);
1590
1591   GST_OBJECT_LOCK (qtdemux);
1592   qtdemux->seek_offset = byte_cur;
1593   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1594     qtdemux->push_seek_start = cur;
1595   } else {
1596     qtdemux->push_seek_start = key_cur;
1597   }
1598
1599   if (stop_type == GST_SEEK_TYPE_NONE) {
1600     qtdemux->push_seek_stop = qtdemux->segment.stop;
1601   } else {
1602     qtdemux->push_seek_stop = original_stop;
1603   }
1604   GST_OBJECT_UNLOCK (qtdemux);
1605
1606   qtdemux->segment_seqnum = seqnum;
1607   /* BYTE seek event */
1608   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1609       stop_type, stop);
1610   gst_event_set_seqnum (event, seqnum);
1611   res = gst_pad_push_event (qtdemux->sinkpad, event);
1612
1613   return res;
1614
1615   /* ERRORS */
1616 abort_seek:
1617   {
1618     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1619         "seek aborted.");
1620     return FALSE;
1621   }
1622 unsupported_seek:
1623   {
1624     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1625     return FALSE;
1626   }
1627 no_format:
1628   {
1629     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1630     return FALSE;
1631   }
1632 }
1633
1634 /* perform the seek.
1635  *
1636  * We set all segment_indexes in the streams to unknown and
1637  * adjust the time_position to the desired position. this is enough
1638  * to trigger a segment switch in the streaming thread to start
1639  * streaming from the desired position.
1640  *
1641  * Keyframe seeking is a little more complicated when dealing with
1642  * segments. Ideally we want to move to the previous keyframe in
1643  * the segment but there might not be a keyframe in the segment. In
1644  * fact, none of the segments could contain a keyframe. We take a
1645  * practical approach: seek to the previous keyframe in the segment,
1646  * if there is none, seek to the beginning of the segment.
1647  *
1648  * Called with STREAM_LOCK
1649  */
1650 static gboolean
1651 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1652     guint32 seqnum, GstSeekFlags flags)
1653 {
1654   gint64 desired_offset;
1655   guint i;
1656
1657   desired_offset = segment->position;
1658
1659   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1660       GST_TIME_ARGS (desired_offset));
1661
1662   /* may not have enough fragmented info to do this adjustment,
1663    * and we can't scan (and probably should not) at this time with
1664    * possibly flushing upstream */
1665   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1666     gint64 min_offset;
1667     gboolean next, before, after;
1668
1669     before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1670     after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1671     next = after && !before;
1672     if (segment->rate < 0)
1673       next = !next;
1674
1675     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1676         NULL);
1677     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1678         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1679     desired_offset = min_offset;
1680   }
1681
1682   /* and set all streams to the final position */
1683   gst_flow_combiner_reset (qtdemux->flowcombiner);
1684   qtdemux->segment_seqnum = seqnum;
1685   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1686     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1687
1688     stream->time_position = desired_offset;
1689     stream->accumulated_base = 0;
1690     stream->sample_index = -1;
1691     stream->offset_in_sample = 0;
1692     stream->segment_index = -1;
1693     stream->sent_eos = FALSE;
1694
1695     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1696       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1697   }
1698   segment->position = desired_offset;
1699   segment->time = desired_offset;
1700   if (segment->rate >= 0) {
1701     segment->start = desired_offset;
1702
1703     /* we stop at the end */
1704     if (segment->stop == -1)
1705       segment->stop = segment->duration;
1706   } else {
1707     segment->stop = desired_offset;
1708   }
1709
1710   if (qtdemux->fragmented)
1711     qtdemux->fragmented_seek_pending = TRUE;
1712
1713   return TRUE;
1714 }
1715
1716 /* do a seek in pull based mode */
1717 static gboolean
1718 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1719 {
1720   gdouble rate;
1721   GstFormat format;
1722   GstSeekFlags flags;
1723   GstSeekType cur_type, stop_type;
1724   gint64 cur, stop;
1725   gboolean flush;
1726   gboolean update;
1727   GstSegment seeksegment;
1728   guint32 seqnum = GST_SEQNUM_INVALID;
1729   GstEvent *flush_event;
1730   gboolean ret;
1731
1732   if (event) {
1733     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1734
1735     gst_event_parse_seek (event, &rate, &format, &flags,
1736         &cur_type, &cur, &stop_type, &stop);
1737     seqnum = gst_event_get_seqnum (event);
1738
1739     /* we have to have a format as the segment format. Try to convert
1740      * if not. */
1741     if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1742             stop_type, &stop))
1743       goto no_format;
1744
1745     GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1746   } else {
1747     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1748     flags = 0;
1749   }
1750
1751   flush = flags & GST_SEEK_FLAG_FLUSH;
1752
1753   /* stop streaming, either by flushing or by pausing the task */
1754   if (flush) {
1755     flush_event = gst_event_new_flush_start ();
1756     if (seqnum != GST_SEQNUM_INVALID)
1757       gst_event_set_seqnum (flush_event, seqnum);
1758     /* unlock upstream pull_range */
1759     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1760     /* make sure out loop function exits */
1761     gst_qtdemux_push_event (qtdemux, flush_event);
1762   } else {
1763     /* non flushing seek, pause the task */
1764     gst_pad_pause_task (qtdemux->sinkpad);
1765   }
1766
1767   /* wait for streaming to finish */
1768   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1769
1770   /* copy segment, we need this because we still need the old
1771    * segment when we close the current segment. */
1772   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1773
1774   if (event) {
1775     /* configure the segment with the seek variables */
1776     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1777     if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1778             cur_type, cur, stop_type, stop, &update)) {
1779       ret = FALSE;
1780       GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1781     } else {
1782       /* now do the seek */
1783       ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1784     }
1785   } else {
1786     /* now do the seek */
1787     ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1788   }
1789
1790   /* prepare for streaming again */
1791   if (flush) {
1792     flush_event = gst_event_new_flush_stop (TRUE);
1793     if (seqnum != GST_SEQNUM_INVALID)
1794       gst_event_set_seqnum (flush_event, seqnum);
1795
1796     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1797     gst_qtdemux_push_event (qtdemux, flush_event);
1798   }
1799
1800   /* commit the new segment */
1801   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1802
1803   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1804     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1805         qtdemux->segment.format, qtdemux->segment.position);
1806     if (seqnum != GST_SEQNUM_INVALID)
1807       gst_message_set_seqnum (msg, seqnum);
1808     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1809   }
1810
1811   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1812   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1813       qtdemux->sinkpad, NULL);
1814
1815   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1816
1817   return ret;
1818
1819   /* ERRORS */
1820 no_format:
1821   {
1822     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1823     return FALSE;
1824   }
1825 }
1826
1827 static gboolean
1828 qtdemux_ensure_index (GstQTDemux * qtdemux)
1829 {
1830   guint i;
1831
1832   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1833
1834   /* Build complete index */
1835   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1836     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1837
1838     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1839       GST_LOG_OBJECT (qtdemux,
1840           "Building complete index of track-id %u for seeking failed!",
1841           stream->track_id);
1842       return FALSE;
1843     }
1844   }
1845
1846   return TRUE;
1847 }
1848
1849 static gboolean
1850 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1851     GstEvent * event)
1852 {
1853   gboolean res = TRUE;
1854   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1855
1856   switch (GST_EVENT_TYPE (event)) {
1857     case GST_EVENT_SEEK:
1858     {
1859 #ifndef GST_DISABLE_GST_DEBUG
1860       GstClockTime ts = gst_util_get_timestamp ();
1861 #endif
1862       guint32 seqnum = gst_event_get_seqnum (event);
1863
1864       qtdemux->received_seek = TRUE;
1865
1866       if (seqnum == qtdemux->segment_seqnum) {
1867         GST_LOG_OBJECT (pad,
1868             "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1869         gst_event_unref (event);
1870         return TRUE;
1871       }
1872
1873       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1874         /* seek should be handled by upstream, we might need to re-download fragments */
1875         GST_DEBUG_OBJECT (qtdemux,
1876             "let upstream handle seek for fragmented playback");
1877         goto upstream;
1878       }
1879
1880       /* Build complete index for seeking;
1881        * if not a fragmented file at least */
1882       if (!qtdemux->fragmented)
1883         if (!qtdemux_ensure_index (qtdemux))
1884           goto index_failed;
1885 #ifndef GST_DISABLE_GST_DEBUG
1886       ts = gst_util_get_timestamp () - ts;
1887       GST_INFO_OBJECT (qtdemux,
1888           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1889 #endif
1890     }
1891       if (qtdemux->pullbased) {
1892         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1893       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1894         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1895         res = TRUE;
1896       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1897           && QTDEMUX_N_STREAMS (qtdemux)
1898           && !qtdemux->fragmented) {
1899         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1900       } else {
1901         GST_DEBUG_OBJECT (qtdemux,
1902             "ignoring seek in push mode in current state");
1903         res = FALSE;
1904       }
1905       gst_event_unref (event);
1906       break;
1907     default:
1908     upstream:
1909       res = gst_pad_event_default (pad, parent, event);
1910       break;
1911   }
1912
1913 done:
1914   return res;
1915
1916   /* ERRORS */
1917 index_failed:
1918   {
1919     GST_ERROR_OBJECT (qtdemux, "Index failed");
1920     gst_event_unref (event);
1921     res = FALSE;
1922     goto done;
1923   }
1924 }
1925
1926 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1927  *
1928  * If @fw is false, the coding order is explored backwards.
1929  *
1930  * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1931  * sample is found for that track.
1932  *
1933  * The stream and sample index of the sample with the minimum offset in the direction explored
1934  * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1935  *
1936  * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1937  * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1938  * @_stream and @_index. */
1939 static void
1940 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1941     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1942 {
1943   gint i, index;
1944   gint64 time, min_time;
1945   QtDemuxStream *stream;
1946   gint iter;
1947
1948   min_time = -1;
1949   stream = NULL;
1950   index = -1;
1951
1952   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1953     QtDemuxStream *str;
1954     gint inc;
1955     gboolean set_sample;
1956
1957     str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1958     set_sample = !set;
1959
1960     if (fw) {
1961       i = 0;
1962       inc = 1;
1963     } else {
1964       i = str->n_samples - 1;
1965       inc = -1;
1966     }
1967
1968     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1969       if (str->samples[i].size == 0)
1970         continue;
1971
1972       if (fw && (str->samples[i].offset < byte_pos))
1973         continue;
1974
1975       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1976         continue;
1977
1978       /* move stream to first available sample */
1979       if (set) {
1980         gst_qtdemux_move_stream (qtdemux, str, i);
1981         set_sample = TRUE;
1982       }
1983
1984       /* avoid index from sparse streams since they might be far away */
1985       if (!CUR_STREAM (str)->sparse) {
1986         /* determine min/max time */
1987         time = QTSAMPLE_PTS (str, &str->samples[i]);
1988         if (min_time == -1 || (!fw && time > min_time) ||
1989             (fw && time < min_time)) {
1990           min_time = time;
1991         }
1992
1993         /* determine stream with leading sample, to get its position */
1994         if (!stream ||
1995             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1996             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1997           stream = str;
1998           index = i;
1999         }
2000       }
2001       break;
2002     }
2003
2004     /* no sample for this stream, mark eos */
2005     if (!set_sample)
2006       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
2007   }
2008
2009   if (_time)
2010     *_time = min_time;
2011   if (_stream)
2012     *_stream = stream;
2013   if (_index)
2014     *_index = index;
2015 }
2016
2017 /* Copied from mpegtsbase code */
2018 /* FIXME: replace this function when we add new util function for stream-id creation */
2019 static gchar *
2020 _get_upstream_id (GstQTDemux * demux)
2021 {
2022   gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
2023
2024   if (!upstream_id) {
2025     /* Try to create one from the upstream URI, else use a randome number */
2026     GstQuery *query;
2027     gchar *uri = NULL;
2028
2029     /* Try to generate one from the URI query and
2030      * if it fails take a random number instead */
2031     query = gst_query_new_uri ();
2032     if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
2033       gst_query_parse_uri (query, &uri);
2034     }
2035
2036     if (uri) {
2037       GChecksum *cs;
2038
2039       /* And then generate an SHA256 sum of the URI */
2040       cs = g_checksum_new (G_CHECKSUM_SHA256);
2041       g_checksum_update (cs, (const guchar *) uri, strlen (uri));
2042       g_free (uri);
2043       upstream_id = g_strdup (g_checksum_get_string (cs));
2044       g_checksum_free (cs);
2045     } else {
2046       /* Just get some random number if the URI query fails */
2047       GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
2048           "implementing a deterministic way of creating a stream-id");
2049       upstream_id =
2050           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
2051           g_random_int (), g_random_int ());
2052     }
2053
2054     gst_query_unref (query);
2055   }
2056   return upstream_id;
2057 }
2058
2059 static QtDemuxStream *
2060 _create_stream (GstQTDemux * demux, guint32 track_id)
2061 {
2062   QtDemuxStream *stream;
2063   gchar *upstream_id;
2064
2065   stream = g_new0 (QtDemuxStream, 1);
2066   stream->demux = demux;
2067   stream->track_id = track_id;
2068   upstream_id = _get_upstream_id (demux);
2069   stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
2070   g_free (upstream_id);
2071   /* new streams always need a discont */
2072   stream->discont = TRUE;
2073   /* we enable clipping for raw audio/video streams */
2074   stream->need_clip = FALSE;
2075   stream->need_process = FALSE;
2076   stream->segment_index = -1;
2077   stream->time_position = 0;
2078   stream->sample_index = -1;
2079   stream->offset_in_sample = 0;
2080   stream->new_stream = TRUE;
2081   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2082   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2083   stream->protected = FALSE;
2084   stream->protection_scheme_type = 0;
2085   stream->protection_scheme_version = 0;
2086   stream->protection_scheme_info = NULL;
2087   stream->n_samples_moof = 0;
2088   stream->duration_moof = 0;
2089   stream->duration_last_moof = 0;
2090   stream->alignment = 1;
2091   stream->stream_tags = gst_tag_list_new_empty ();
2092   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2093   g_queue_init (&stream->protection_scheme_event_queue);
2094   stream->ref_count = 1;
2095   /* consistent default for push based mode */
2096   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
2097   return stream;
2098 }
2099
2100 static gboolean
2101 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2102 {
2103   GstStructure *structure;
2104   const gchar *variant;
2105   const GstCaps *mediacaps = NULL;
2106
2107   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2108
2109   structure = gst_caps_get_structure (caps, 0);
2110   variant = gst_structure_get_string (structure, "variant");
2111
2112   if (variant && strcmp (variant, "mss-fragmented") == 0) {
2113     QtDemuxStream *stream;
2114     const GValue *value;
2115
2116     demux->fragmented = TRUE;
2117     demux->mss_mode = TRUE;
2118
2119     if (QTDEMUX_N_STREAMS (demux) > 1) {
2120       /* can't do this, we can only renegotiate for another mss format */
2121       return FALSE;
2122     }
2123
2124     value = gst_structure_get_value (structure, "media-caps");
2125     /* create stream */
2126     if (value) {
2127       const GValue *timescale_v;
2128
2129       /* TODO update when stream changes during playback */
2130
2131       if (QTDEMUX_N_STREAMS (demux) == 0) {
2132         stream = _create_stream (demux, 1);
2133         g_ptr_array_add (demux->active_streams, stream);
2134         /* mss has no stsd/stsd entry, use id 0 as default */
2135         stream->stsd_entries_length = 1;
2136         stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2137         stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2138       } else {
2139         stream = QTDEMUX_NTH_STREAM (demux, 0);
2140       }
2141
2142       timescale_v = gst_structure_get_value (structure, "timescale");
2143       if (timescale_v) {
2144         stream->timescale = g_value_get_uint64 (timescale_v);
2145       } else {
2146         /* default mss timescale */
2147         stream->timescale = 10000000;
2148       }
2149       demux->timescale = stream->timescale;
2150
2151       mediacaps = gst_value_get_caps (value);
2152       if (!CUR_STREAM (stream)->caps
2153           || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2154         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2155             mediacaps);
2156         stream->new_caps = TRUE;
2157       }
2158       gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2159       structure = gst_caps_get_structure (mediacaps, 0);
2160       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2161         stream->subtype = FOURCC_vide;
2162
2163         gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2164         gst_structure_get_int (structure, "height",
2165             &CUR_STREAM (stream)->height);
2166         gst_structure_get_fraction (structure, "framerate",
2167             &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2168       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2169         gint rate = 0;
2170         stream->subtype = FOURCC_soun;
2171         gst_structure_get_int (structure, "channels",
2172             &CUR_STREAM (stream)->n_channels);
2173         gst_structure_get_int (structure, "rate", &rate);
2174         CUR_STREAM (stream)->rate = rate;
2175       }
2176     }
2177     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2178   } else {
2179     demux->mss_mode = FALSE;
2180   }
2181
2182   return TRUE;
2183 }
2184
2185 static void
2186 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2187 {
2188   gint i;
2189
2190   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2191   gst_pad_stop_task (qtdemux->sinkpad);
2192
2193   if (hard || qtdemux->upstream_format_is_time) {
2194     qtdemux->state = QTDEMUX_STATE_INITIAL;
2195     qtdemux->neededbytes = 16;
2196     qtdemux->todrop = 0;
2197     qtdemux->pullbased = FALSE;
2198     qtdemux->posted_redirect = FALSE;
2199     qtdemux->first_mdat = -1;
2200     qtdemux->header_size = 0;
2201     qtdemux->mdatoffset = -1;
2202     qtdemux->restoredata_offset = -1;
2203     if (qtdemux->mdatbuffer)
2204       gst_buffer_unref (qtdemux->mdatbuffer);
2205     if (qtdemux->restoredata_buffer)
2206       gst_buffer_unref (qtdemux->restoredata_buffer);
2207     qtdemux->mdatbuffer = NULL;
2208     qtdemux->restoredata_buffer = NULL;
2209     qtdemux->mdatleft = 0;
2210     qtdemux->mdatsize = 0;
2211     if (qtdemux->comp_brands)
2212       gst_buffer_unref (qtdemux->comp_brands);
2213     qtdemux->comp_brands = NULL;
2214     qtdemux->last_moov_offset = -1;
2215     if (qtdemux->moov_node_compressed) {
2216       g_node_destroy (qtdemux->moov_node_compressed);
2217       if (qtdemux->moov_node)
2218         g_free (qtdemux->moov_node->data);
2219     }
2220     qtdemux->moov_node_compressed = NULL;
2221     if (qtdemux->moov_node)
2222       g_node_destroy (qtdemux->moov_node);
2223     qtdemux->moov_node = NULL;
2224     if (qtdemux->tag_list)
2225       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2226     qtdemux->tag_list = gst_tag_list_new_empty ();
2227     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2228 #if 0
2229     if (qtdemux->element_index)
2230       gst_object_unref (qtdemux->element_index);
2231     qtdemux->element_index = NULL;
2232 #endif
2233     qtdemux->major_brand = 0;
2234     qtdemux->upstream_format_is_time = FALSE;
2235     qtdemux->upstream_seekable = FALSE;
2236     qtdemux->upstream_size = 0;
2237
2238     qtdemux->fragment_start = -1;
2239     qtdemux->fragment_start_offset = -1;
2240     qtdemux->duration = 0;
2241     qtdemux->moof_offset = 0;
2242     qtdemux->chapters_track_id = 0;
2243     qtdemux->have_group_id = FALSE;
2244     qtdemux->group_id = G_MAXUINT;
2245
2246     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2247         NULL);
2248     g_queue_clear (&qtdemux->protection_event_queue);
2249
2250     qtdemux->received_seek = FALSE;
2251     qtdemux->first_moof_already_parsed = FALSE;
2252   }
2253   qtdemux->offset = 0;
2254   gst_adapter_clear (qtdemux->adapter);
2255   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2256   qtdemux->need_segment = TRUE;
2257
2258   if (hard) {
2259     qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2260     g_ptr_array_set_size (qtdemux->active_streams, 0);
2261     g_ptr_array_set_size (qtdemux->old_streams, 0);
2262     qtdemux->n_video_streams = 0;
2263     qtdemux->n_audio_streams = 0;
2264     qtdemux->n_sub_streams = 0;
2265     qtdemux->exposed = FALSE;
2266     qtdemux->fragmented = FALSE;
2267     qtdemux->mss_mode = FALSE;
2268     gst_caps_replace (&qtdemux->media_caps, NULL);
2269     qtdemux->timescale = 0;
2270     qtdemux->got_moov = FALSE;
2271     qtdemux->cenc_aux_info_offset = 0;
2272     qtdemux->cenc_aux_info_sizes = NULL;
2273     qtdemux->cenc_aux_sample_count = 0;
2274     if (qtdemux->protection_system_ids) {
2275       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2276       qtdemux->protection_system_ids = NULL;
2277     }
2278     qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2279         && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2280         GST_BIN_FLAG_STREAMS_AWARE);
2281
2282     if (qtdemux->preferred_protection_system_id) {
2283       g_free (qtdemux->preferred_protection_system_id);
2284       qtdemux->preferred_protection_system_id = NULL;
2285     }
2286   } else if (qtdemux->mss_mode) {
2287     gst_flow_combiner_reset (qtdemux->flowcombiner);
2288     g_ptr_array_foreach (qtdemux->active_streams,
2289         (GFunc) gst_qtdemux_stream_clear, NULL);
2290   } else {
2291     gst_flow_combiner_reset (qtdemux->flowcombiner);
2292     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2293       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2294       stream->sent_eos = FALSE;
2295       stream->time_position = 0;
2296       stream->accumulated_base = 0;
2297     }
2298   }
2299 }
2300
2301
2302 /* Maps the @segment to the qt edts internal segments and pushes
2303  * the correspnding segment event.
2304  *
2305  * If it ends up being at a empty segment, a gap will be pushed and the next
2306  * edts segment will be activated in sequence.
2307  *
2308  * To be used in push-mode only */
2309 static void
2310 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2311 {
2312   gint i, iter;
2313
2314   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2315     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2316
2317     stream->time_position = segment->start;
2318
2319     /* in push mode we should be guaranteed that we will have empty segments
2320      * at the beginning and then one segment after, other scenarios are not
2321      * supported and are discarded when parsing the edts */
2322     for (i = 0; i < stream->n_segments; i++) {
2323       if (stream->segments[i].stop_time > segment->start) {
2324         /* push the empty segment and move to the next one */
2325         gst_qtdemux_activate_segment (qtdemux, stream, i,
2326             stream->time_position);
2327         if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2328           gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2329               stream->time_position);
2330
2331           /* accumulate previous segments */
2332           if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2333             stream->accumulated_base +=
2334                 (stream->segment.stop -
2335                 stream->segment.start) / ABS (stream->segment.rate);
2336           continue;
2337         }
2338
2339         g_assert (i == stream->n_segments - 1);
2340       }
2341     }
2342   }
2343 }
2344
2345 static void
2346 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2347     GPtrArray * src)
2348 {
2349   guint i;
2350   guint len;
2351
2352   len = src->len;
2353
2354   if (len == 0)
2355     return;
2356
2357   for (i = 0; i < len; i++) {
2358     QtDemuxStream *stream = g_ptr_array_index (src, i);
2359
2360 #ifndef GST_DISABLE_GST_DEBUG
2361     GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2362         stream, GST_STR_NULL (stream->stream_id), dest);
2363 #endif
2364     g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2365   }
2366
2367   g_ptr_array_set_size (src, 0);
2368 }
2369
2370 static gboolean
2371 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2372     GstEvent * event)
2373 {
2374   GstQTDemux *demux = GST_QTDEMUX (parent);
2375   gboolean res = TRUE;
2376
2377   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2378
2379   switch (GST_EVENT_TYPE (event)) {
2380     case GST_EVENT_SEGMENT:
2381     {
2382       gint64 offset = 0;
2383       QtDemuxStream *stream;
2384       gint idx;
2385       GstSegment segment;
2386
2387       /* some debug output */
2388       gst_event_copy_segment (event, &segment);
2389       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2390           &segment);
2391
2392       if (segment.format == GST_FORMAT_TIME) {
2393         demux->upstream_format_is_time = TRUE;
2394         demux->segment_seqnum = gst_event_get_seqnum (event);
2395       } else {
2396         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2397             "not in time format");
2398
2399         /* chain will send initial newsegment after pads have been added */
2400         if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2401           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2402           goto exit;
2403         }
2404       }
2405
2406       /* check if this matches a time seek we received previously
2407        * FIXME for backwards compatibility reasons we use the
2408        * seek_offset here to compare. In the future we might want to
2409        * change this to use the seqnum as it uniquely should identify
2410        * the segment that corresponds to the seek. */
2411       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2412           ", received segment offset %" G_GINT64_FORMAT,
2413           demux->seek_offset, segment.start);
2414       if (segment.format == GST_FORMAT_BYTES
2415           && demux->seek_offset == segment.start) {
2416         GST_OBJECT_LOCK (demux);
2417         offset = segment.start;
2418
2419         segment.format = GST_FORMAT_TIME;
2420         segment.start = demux->push_seek_start;
2421         segment.stop = demux->push_seek_stop;
2422         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2423             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2424             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2425         GST_OBJECT_UNLOCK (demux);
2426       }
2427
2428       /* we only expect a BYTE segment, e.g. following a seek */
2429       if (segment.format == GST_FORMAT_BYTES) {
2430         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2431           offset = segment.start;
2432
2433           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2434               NULL, (gint64 *) & segment.start);
2435           if ((gint64) segment.start < 0)
2436             segment.start = 0;
2437         }
2438         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2439           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2440               NULL, (gint64 *) & segment.stop);
2441           /* keyframe seeking should already arrange for start >= stop,
2442            * but make sure in other rare cases */
2443           segment.stop = MAX (segment.stop, segment.start);
2444         }
2445       } else if (segment.format == GST_FORMAT_TIME) {
2446         /* push all data on the adapter before starting this
2447          * new segment */
2448         gst_qtdemux_process_adapter (demux, TRUE);
2449       } else {
2450         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2451         goto exit;
2452       }
2453
2454       /* We shouldn't modify upstream driven TIME FORMAT segment */
2455       if (!demux->upstream_format_is_time) {
2456         /* accept upstream's notion of segment and distribute along */
2457         segment.format = GST_FORMAT_TIME;
2458         segment.position = segment.time = segment.start;
2459         segment.duration = demux->segment.duration;
2460         segment.base = gst_segment_to_running_time (&demux->segment,
2461             GST_FORMAT_TIME, demux->segment.position);
2462       }
2463
2464       gst_segment_copy_into (&segment, &demux->segment);
2465       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2466
2467       /* map segment to internal qt segments and push on each stream */
2468       if (QTDEMUX_N_STREAMS (demux)) {
2469         demux->need_segment = TRUE;
2470         gst_qtdemux_check_send_pending_segment (demux);
2471       }
2472
2473       /* clear leftover in current segment, if any */
2474       gst_adapter_clear (demux->adapter);
2475
2476       /* set up streaming thread */
2477       demux->offset = offset;
2478       if (demux->upstream_format_is_time) {
2479         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2480             "set values to restart reading from a new atom");
2481         demux->neededbytes = 16;
2482         demux->todrop = 0;
2483       } else {
2484         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2485             NULL);
2486         if (stream) {
2487           demux->todrop = stream->samples[idx].offset - offset;
2488           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2489         } else {
2490           /* set up for EOS */
2491           demux->neededbytes = -1;
2492           demux->todrop = 0;
2493         }
2494       }
2495     exit:
2496       gst_event_unref (event);
2497       res = TRUE;
2498       goto drop;
2499     }
2500     case GST_EVENT_FLUSH_START:
2501     {
2502       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2503         gst_event_unref (event);
2504         goto drop;
2505       }
2506       QTDEMUX_EXPOSE_LOCK (demux);
2507       res = gst_pad_event_default (demux->sinkpad, parent, event);
2508       QTDEMUX_EXPOSE_UNLOCK (demux);
2509       goto drop;
2510     }
2511     case GST_EVENT_FLUSH_STOP:
2512     {
2513       guint64 dur;
2514
2515       dur = demux->segment.duration;
2516       gst_qtdemux_reset (demux, FALSE);
2517       demux->segment.duration = dur;
2518
2519       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2520         gst_event_unref (event);
2521         goto drop;
2522       }
2523       break;
2524     }
2525     case GST_EVENT_EOS:
2526       /* If we are in push mode, and get an EOS before we've seen any streams,
2527        * then error out - we have nowhere to send the EOS */
2528       if (!demux->pullbased) {
2529         gint i;
2530         gboolean has_valid_stream = FALSE;
2531         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2532           if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2533             has_valid_stream = TRUE;
2534             break;
2535           }
2536         }
2537         if (!has_valid_stream)
2538           gst_qtdemux_post_no_playable_stream_error (demux);
2539         else {
2540           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2541               (guint) gst_adapter_available (demux->adapter));
2542           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2543             res = FALSE;
2544           }
2545         }
2546       }
2547       break;
2548     case GST_EVENT_CAPS:{
2549       GstCaps *caps = NULL;
2550
2551       gst_event_parse_caps (event, &caps);
2552       gst_qtdemux_setcaps (demux, caps);
2553       res = TRUE;
2554       gst_event_unref (event);
2555       goto drop;
2556     }
2557     case GST_EVENT_PROTECTION:
2558     {
2559       const gchar *system_id = NULL;
2560
2561       gst_event_parse_protection (event, &system_id, NULL, NULL);
2562       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2563           system_id);
2564       gst_qtdemux_append_protection_system_id (demux, system_id);
2565       /* save the event for later, for source pads that have not been created */
2566       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2567       /* send it to all pads that already exist */
2568       gst_qtdemux_push_event (demux, event);
2569       res = TRUE;
2570       goto drop;
2571     }
2572     case GST_EVENT_STREAM_START:
2573     {
2574       res = TRUE;
2575       gst_event_unref (event);
2576
2577       /* Drain all the buffers */
2578       gst_qtdemux_process_adapter (demux, TRUE);
2579       gst_qtdemux_reset (demux, FALSE);
2580       /* We expect new moov box after new stream-start event */
2581       if (demux->exposed) {
2582         gst_qtdemux_stream_concat (demux,
2583             demux->old_streams, demux->active_streams);
2584       }
2585
2586       goto drop;
2587     }
2588     default:
2589       break;
2590   }
2591
2592   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2593
2594 drop:
2595   return res;
2596 }
2597
2598 static gboolean
2599 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2600     GstQuery * query)
2601 {
2602   GstQTDemux *demux = GST_QTDEMUX (parent);
2603   gboolean res = FALSE;
2604
2605   switch (GST_QUERY_TYPE (query)) {
2606     case GST_QUERY_BITRATE:
2607     {
2608       GstClockTime duration;
2609
2610       /* populate demux->upstream_size if not done yet */
2611       gst_qtdemux_check_seekability (demux);
2612
2613       if (demux->upstream_size != -1
2614           && gst_qtdemux_get_duration (demux, &duration)) {
2615         guint bitrate =
2616             gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2617             duration);
2618
2619         GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2620             " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2621             demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2622
2623         /* TODO: better results based on ranges/index tables */
2624         gst_query_set_bitrate (query, bitrate);
2625         res = TRUE;
2626       }
2627       break;
2628     }
2629     default:
2630       res = gst_pad_query_default (pad, (GstObject *) demux, query);
2631       break;
2632   }
2633
2634   return res;
2635 }
2636
2637
2638 #if 0
2639 static void
2640 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2641 {
2642   GstQTDemux *demux = GST_QTDEMUX (element);
2643
2644   GST_OBJECT_LOCK (demux);
2645   if (demux->element_index)
2646     gst_object_unref (demux->element_index);
2647   if (index) {
2648     demux->element_index = gst_object_ref (index);
2649   } else {
2650     demux->element_index = NULL;
2651   }
2652   GST_OBJECT_UNLOCK (demux);
2653   /* object lock might be taken again */
2654   if (index)
2655     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2656   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2657       demux->element_index, demux->index_id);
2658 }
2659
2660 static GstIndex *
2661 gst_qtdemux_get_index (GstElement * element)
2662 {
2663   GstIndex *result = NULL;
2664   GstQTDemux *demux = GST_QTDEMUX (element);
2665
2666   GST_OBJECT_LOCK (demux);
2667   if (demux->element_index)
2668     result = gst_object_ref (demux->element_index);
2669   GST_OBJECT_UNLOCK (demux);
2670
2671   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2672
2673   return result;
2674 }
2675 #endif
2676
2677 static void
2678 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2679 {
2680   g_free ((gpointer) stream->stco.data);
2681   stream->stco.data = NULL;
2682   g_free ((gpointer) stream->stsz.data);
2683   stream->stsz.data = NULL;
2684   g_free ((gpointer) stream->stsc.data);
2685   stream->stsc.data = NULL;
2686   g_free ((gpointer) stream->stts.data);
2687   stream->stts.data = NULL;
2688   g_free ((gpointer) stream->stss.data);
2689   stream->stss.data = NULL;
2690   g_free ((gpointer) stream->stps.data);
2691   stream->stps.data = NULL;
2692   g_free ((gpointer) stream->ctts.data);
2693   stream->ctts.data = NULL;
2694 }
2695
2696 static void
2697 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2698 {
2699   g_free (stream->segments);
2700   stream->segments = NULL;
2701   stream->segment_index = -1;
2702   stream->accumulated_base = 0;
2703 }
2704
2705 static void
2706 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2707 {
2708   g_free (stream->samples);
2709   stream->samples = NULL;
2710   gst_qtdemux_stbl_free (stream);
2711
2712   /* fragments */
2713   g_free (stream->ra_entries);
2714   stream->ra_entries = NULL;
2715   stream->n_ra_entries = 0;
2716
2717   stream->sample_index = -1;
2718   stream->stbl_index = -1;
2719   stream->n_samples = 0;
2720   stream->time_position = 0;
2721
2722   stream->n_samples_moof = 0;
2723   stream->duration_moof = 0;
2724   stream->duration_last_moof = 0;
2725 }
2726
2727 static void
2728 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2729 {
2730   gint i;
2731   if (stream->allocator)
2732     gst_object_unref (stream->allocator);
2733   while (stream->buffers) {
2734     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2735     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2736   }
2737   for (i = 0; i < stream->stsd_entries_length; i++) {
2738     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2739     if (entry->rgb8_palette) {
2740       gst_memory_unref (entry->rgb8_palette);
2741       entry->rgb8_palette = NULL;
2742     }
2743     entry->sparse = FALSE;
2744   }
2745
2746   if (stream->stream_tags)
2747     gst_tag_list_unref (stream->stream_tags);
2748
2749   stream->stream_tags = gst_tag_list_new_empty ();
2750   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2751   g_free (stream->redirect_uri);
2752   stream->redirect_uri = NULL;
2753   stream->sent_eos = FALSE;
2754   stream->protected = FALSE;
2755   if (stream->protection_scheme_info) {
2756     if (stream->protection_scheme_type == FOURCC_cenc) {
2757       QtDemuxCencSampleSetInfo *info =
2758           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2759       if (info->default_properties)
2760         gst_structure_free (info->default_properties);
2761       if (info->crypto_info)
2762         g_ptr_array_free (info->crypto_info, TRUE);
2763     }
2764     g_free (stream->protection_scheme_info);
2765     stream->protection_scheme_info = NULL;
2766   }
2767   stream->protection_scheme_type = 0;
2768   stream->protection_scheme_version = 0;
2769   g_queue_foreach (&stream->protection_scheme_event_queue,
2770       (GFunc) gst_event_unref, NULL);
2771   g_queue_clear (&stream->protection_scheme_event_queue);
2772   gst_qtdemux_stream_flush_segments_data (stream);
2773   gst_qtdemux_stream_flush_samples_data (stream);
2774 }
2775
2776 static void
2777 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2778 {
2779   gint i;
2780   gst_qtdemux_stream_clear (stream);
2781   for (i = 0; i < stream->stsd_entries_length; i++) {
2782     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2783     if (entry->caps) {
2784       gst_caps_unref (entry->caps);
2785       entry->caps = NULL;
2786     }
2787   }
2788   g_free (stream->stsd_entries);
2789   stream->stsd_entries = NULL;
2790   stream->stsd_entries_length = 0;
2791 }
2792
2793 static QtDemuxStream *
2794 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2795 {
2796   g_atomic_int_add (&stream->ref_count, 1);
2797
2798   return stream;
2799 }
2800
2801 static void
2802 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2803 {
2804   if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2805     gst_qtdemux_stream_reset (stream);
2806     gst_tag_list_unref (stream->stream_tags);
2807     if (stream->pad) {
2808       GstQTDemux *demux = stream->demux;
2809       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2810       gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2811     }
2812     g_free (stream->stream_id);
2813     g_free (stream);
2814   }
2815 }
2816
2817 static GstStateChangeReturn
2818 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2819 {
2820   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2821   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2822
2823   switch (transition) {
2824     case GST_STATE_CHANGE_READY_TO_PAUSED:
2825       gst_qtdemux_reset (qtdemux, TRUE);
2826       break;
2827     default:
2828       break;
2829   }
2830
2831   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2832
2833   switch (transition) {
2834     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2835       gst_qtdemux_reset (qtdemux, TRUE);
2836       break;
2837     }
2838     default:
2839       break;
2840   }
2841
2842   return result;
2843 }
2844
2845 static void
2846 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2847 {
2848   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2849
2850   g_return_if_fail (GST_IS_CONTEXT (context));
2851
2852   if (gst_context_has_context_type (context,
2853           "drm-preferred-decryption-system-id")) {
2854     const GstStructure *s;
2855
2856     s = gst_context_get_structure (context);
2857     g_free (qtdemux->preferred_protection_system_id);
2858     qtdemux->preferred_protection_system_id =
2859         g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2860     GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2861         qtdemux->preferred_protection_system_id);
2862   }
2863
2864   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2865 }
2866
2867 static void
2868 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2869 {
2870   /* counts as header data */
2871   qtdemux->header_size += length;
2872
2873   /* only consider at least a sufficiently complete ftyp atom */
2874   if (length >= 20) {
2875     GstBuffer *buf;
2876
2877     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2878     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2879         GST_FOURCC_ARGS (qtdemux->major_brand));
2880     if (qtdemux->comp_brands)
2881       gst_buffer_unref (qtdemux->comp_brands);
2882     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2883     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2884   }
2885 }
2886
2887 static void
2888 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2889     GstTagList * xmptaglist)
2890 {
2891   /* Strip out bogus fields */
2892   if (xmptaglist) {
2893     if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2894       gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2895       gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2896     } else {
2897       gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2898     }
2899
2900     GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2901
2902     /* prioritize native tags using _KEEP mode */
2903     gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2904     gst_tag_list_unref (xmptaglist);
2905   }
2906 }
2907
2908 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
2909 static void
2910 _get_int_value_from_xml_string (GstQTDemux * qtdemux,
2911     const char *xml_str, const char *param_name, int *value)
2912 {
2913   char *value_start, *value_end, *endptr;
2914   const short value_length_max = 12;
2915   char init_view_ret[12];
2916   int value_length = 0;
2917   int i = 0;
2918
2919   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2920
2921   if (!value_start) {
2922     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2923         param_name);
2924     return;
2925   }
2926
2927   value_start += strlen (param_name);
2928   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2929     value_start++;
2930
2931   value_end = strchr (value_start, '<');
2932   if (!value_end) {
2933     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2934     return;
2935   }
2936
2937   value_length = value_end - value_start;
2938   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2939           || (value_start[value_length - 1] == '\t')))
2940     value_length--;
2941
2942   if (value_start[i] == '+' || value_start[i] == '-')
2943     i++;
2944   while (i < value_length) {
2945     if (value_start[i] < '0' || value_start[i] > '9') {
2946       GST_ERROR_OBJECT (qtdemux,
2947           "error: incorrect value, integer was expected\n");
2948       return;
2949     }
2950     i++;
2951   }
2952
2953   if (value_length >= value_length_max || value_length < 1) {
2954     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2955     return;
2956   }
2957
2958   strncpy (init_view_ret, value_start, value_length_max);
2959   init_view_ret[value_length] = '\0';
2960
2961   *value = strtol (init_view_ret, &endptr, 10);
2962   if (endptr == init_view_ret) {
2963     GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n");
2964     return;
2965   }
2966
2967   return;
2968 }
2969
2970 static void
2971 _get_string_value_from_xml_string (GstQTDemux * qtdemux,
2972     const char *xml_str, const char *param_name, char **value)
2973 {
2974   char *value_start, *value_end;
2975   const short value_length_max = 256;
2976   int value_length = 0;
2977
2978   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2979
2980   if (!value_start) {
2981     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2982         param_name);
2983     return;
2984   }
2985
2986   value_start += strlen (param_name);
2987   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2988     value_start++;
2989
2990   value_end = strchr (value_start, '<');
2991   if (!value_end) {
2992     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2993     return;
2994   }
2995
2996   value_length = value_end - value_start;
2997   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2998           || (value_start[value_length - 1] == '\t')))
2999     value_length--;
3000
3001   if (value_length >= value_length_max || value_length < 1) {
3002     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
3003     return;
3004   }
3005
3006   *value = strndup(value_start, value_length);
3007
3008   return;
3009 }
3010
3011 static void
3012 _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
3013     const char *xml_str, const char *param_name, gboolean * value)
3014 {
3015   char *value_start, *value_end;
3016   int value_length = 0;
3017
3018   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
3019
3020   if (!value_start) {
3021     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
3022         param_name);
3023     return;
3024   }
3025
3026   value_start += strlen (param_name);
3027   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
3028     value_start++;
3029
3030   value_end = strchr (value_start, '<');
3031   if (!value_end) {
3032     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
3033     return;
3034   }
3035
3036   value_length = value_end - value_start;
3037   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
3038           || (value_start[value_length - 1] == '\t')))
3039     value_length--;
3040
3041   if (value_length < 1) {
3042     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
3043     return;
3044   }
3045
3046   *value = g_strstr_len(value_start, value_length, "true") ? TRUE : FALSE;
3047
3048   return;
3049 }
3050
3051 static void
3052 _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux, const char *xmlStr)
3053 {
3054   const char is_spherical_str[] = "<GSpherical:Spherical>";
3055   const char is_stitched_str[] = "<GSpherical:Stitched>";
3056   const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
3057   const char projection_type_str[] = "<GSpherical:ProjectionType>";
3058   const char stereo_mode_str[] = "<GSpherical:StereoMode>";
3059   const char source_count_str[] = "<GSpherical:SourceCount>";
3060   const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
3061   const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
3062   const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
3063   const char timestamp_str[] = "<GSpherical:Timestamp>";
3064   const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
3065   const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
3066   const char cropped_area_image_width_str[] =
3067       "<GSpherical:CroppedAreaImageWidthPixels>";
3068   const char cropped_area_image_height_str[] =
3069       "<GSpherical:CroppedAreaImageHeightPixels>";
3070   const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
3071   const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
3072
3073   QtDemuxSphericalMetadata * spherical_metadata = qtdemux->spherical_metadata;
3074
3075   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
3076       (gboolean *) & spherical_metadata->is_spherical);
3077   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
3078       (gboolean *) & spherical_metadata->is_stitched);
3079
3080   if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
3081     _get_string_value_from_xml_string (qtdemux, xmlStr,
3082         stitching_software_str, &spherical_metadata->stitching_software);
3083     _get_string_value_from_xml_string (qtdemux, xmlStr,
3084         projection_type_str, &spherical_metadata->projection_type);
3085     _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
3086         &spherical_metadata->stereo_mode);
3087     _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
3088         &spherical_metadata->source_count);
3089     _get_int_value_from_xml_string (qtdemux, xmlStr,
3090         init_view_heading_str, &spherical_metadata->init_view_heading);
3091     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
3092         &spherical_metadata->init_view_pitch);
3093     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
3094         &spherical_metadata->init_view_roll);
3095     _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
3096         &spherical_metadata->timestamp);
3097     _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
3098         &spherical_metadata->full_pano_width_pixels);
3099     _get_int_value_from_xml_string (qtdemux, xmlStr,
3100         full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
3101     _get_int_value_from_xml_string (qtdemux, xmlStr,
3102         cropped_area_image_width_str,
3103         &spherical_metadata->cropped_area_image_width);
3104     _get_int_value_from_xml_string (qtdemux, xmlStr,
3105         cropped_area_image_height_str,
3106         &spherical_metadata->cropped_area_image_height);
3107     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
3108         &spherical_metadata->cropped_area_left);
3109     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
3110         &spherical_metadata->cropped_area_top);
3111   }
3112
3113   return;
3114 }
3115
3116 static void
3117 gst_tag_register_spherical_tags (void) {
3118   gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
3119       G_TYPE_INT,
3120       _("tag-spherical"),
3121       _("Flag indicating if the video is a spherical video"),
3122       NULL);
3123   gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
3124       G_TYPE_INT,
3125       _("tag-stitched"),
3126       _("Flag indicating if the video is stitched"),
3127       NULL);
3128   gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
3129       G_TYPE_STRING,
3130       _("tag-stitching-software"),
3131       _("Software used to stitch the spherical video"),
3132       NULL);
3133   gst_tag_register ("projection_type", GST_TAG_FLAG_META,
3134       G_TYPE_STRING,
3135       _("tag-projection-type"),
3136       _("Projection type used in the video frames"),
3137       NULL);
3138   gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
3139       G_TYPE_STRING,
3140       _("tag-stereo-mode"),
3141       _("Description of stereoscopic 3D layout"),
3142       NULL);
3143   gst_tag_register ("source_count", GST_TAG_FLAG_META,
3144       G_TYPE_INT,
3145       _("tag-source-count"),
3146       _("Number of cameras used to create the spherical video"),
3147       NULL);
3148   gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
3149       G_TYPE_INT,
3150       _("tag-init-view-heading"),
3151       _("The heading angle of the initial view in degrees"),
3152       NULL);
3153   gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
3154       G_TYPE_INT,
3155       _("tag-init-view-pitch"),
3156       _("The pitch angle of the initial view in degrees"),
3157       NULL);
3158   gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
3159       G_TYPE_INT,
3160       _("tag-init-view-roll"),
3161       _("The roll angle of the initial view in degrees"),
3162       NULL);
3163   gst_tag_register ("timestamp", GST_TAG_FLAG_META,
3164       G_TYPE_INT,
3165       _("tag-timestamp"),
3166       _("Epoch timestamp of when the first frame in the video was recorded"),
3167       NULL);
3168   gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
3169       G_TYPE_INT,
3170       _("tag-full-pano-width"),
3171       _("Width of the encoded video frame in pixels"),
3172       NULL);
3173   gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
3174       G_TYPE_INT,
3175       _("tag-full-pano-height"),
3176       _("Height of the encoded video frame in pixels"),
3177       NULL);
3178   gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
3179       G_TYPE_INT,
3180       _("tag-cropped-area-image-width"),
3181       _("Width of the video frame to display (e.g. cropping)"),
3182       NULL);
3183   gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
3184       G_TYPE_INT,
3185       _("tag-cropped-area-image-height"),
3186       _("Height of the video frame to display (e.g. cropping)"),
3187       NULL);
3188   gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
3189       G_TYPE_INT,
3190       _("tag-cropped-area-left"),
3191       _("Column where the left edge of the image was cropped from the"
3192           " full sized panorama"),
3193       NULL);
3194   gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
3195       G_TYPE_INT,
3196       _("tag-cropped-area-top"),
3197       _("Row where the top edge of the image was cropped from the"
3198           " full sized panorama"),
3199       NULL);
3200   gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
3201       G_TYPE_INT,
3202       _("tag-ambisonic-type"),
3203       _("Specifies the type of ambisonic audio represented"),
3204       NULL);
3205   gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
3206       G_TYPE_INT,
3207       _("tag-ambisonic-format"),
3208       _("Specifies the ambisonic audio format"),
3209       NULL);
3210   gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
3211       G_TYPE_INT,
3212       _("tag-ambisonic-order"),
3213       _("Specifies the ambisonic audio channel order"),
3214       NULL);
3215
3216   return;
3217 }
3218
3219 static void
3220 _send_spherical_metadata_msg_to_bus (GstQTDemux * qtdemux)
3221 {
3222   GstTagList *taglist;
3223   QtDemuxSphericalMetadata *spherical_metadata = qtdemux->spherical_metadata;
3224
3225   GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
3226       spherical_metadata->is_spherical);
3227   GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
3228       spherical_metadata->is_stitched);
3229   GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
3230       spherical_metadata->stitching_software);
3231   GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
3232       spherical_metadata->projection_type);
3233   GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
3234       spherical_metadata->stereo_mode);
3235   GST_DEBUG_OBJECT (qtdemux, "source_count %d",
3236       spherical_metadata->source_count);
3237   GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
3238       spherical_metadata->init_view_heading);
3239   GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
3240       spherical_metadata->init_view_pitch);
3241   GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
3242       spherical_metadata->init_view_roll);
3243   GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
3244   GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
3245       spherical_metadata->full_pano_width_pixels);
3246   GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
3247       spherical_metadata->full_pano_height_pixels);
3248   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
3249       spherical_metadata->cropped_area_image_width);
3250   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
3251       spherical_metadata->cropped_area_image_height);
3252   GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
3253       spherical_metadata->cropped_area_left);
3254   GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
3255       spherical_metadata->cropped_area_top);
3256   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
3257       spherical_metadata->ambisonic_type);
3258   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
3259       spherical_metadata->ambisonic_order);
3260   GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
3261       spherical_metadata->ambisonic_format);
3262
3263   taglist = gst_tag_list_new_empty ();
3264   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3265       "is_spherical", spherical_metadata->is_spherical,
3266       "is_stitched", spherical_metadata->is_stitched,
3267       "source_count", spherical_metadata->source_count,
3268       "init_view_heading", spherical_metadata->init_view_heading,
3269       "init_view_pitch", spherical_metadata->init_view_pitch,
3270       "init_view_roll", spherical_metadata->init_view_roll,
3271       "timestamp", spherical_metadata->timestamp,
3272       "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
3273       "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
3274       "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
3275       "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
3276       "cropped_area_left", spherical_metadata->cropped_area_left,
3277       "cropped_area_top", spherical_metadata->cropped_area_top,
3278       "ambisonic_type", spherical_metadata->ambisonic_type,
3279       "ambisonic_format", spherical_metadata->ambisonic_format,
3280       "ambisonic_order", spherical_metadata->ambisonic_order,
3281       NULL);
3282
3283   if (spherical_metadata->stitching_software)
3284     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3285         "stitching_software", spherical_metadata->stitching_software,
3286         NULL);
3287   if (spherical_metadata->projection_type)
3288     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3289         "projection_type", spherical_metadata->projection_type,
3290         NULL);
3291   if (spherical_metadata->stereo_mode)
3292     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3293         "stereo_mode", spherical_metadata->stereo_mode,
3294         NULL);
3295
3296   gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3297           gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
3298                   gst_tag_list_copy (taglist)));
3299
3300   gst_tag_list_unref(taglist);
3301
3302   return;
3303 }
3304
3305 static void
3306 qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3307 {
3308   guint offset = 0;
3309
3310   guint8 version = 0;
3311   guint8 ambisonic_type  = 0;
3312   guint32 ambisonic_order = 0;
3313   guint8 ambisonic_channel_ordering = 0;
3314   guint8 ambisonic_normalization = 0;
3315   guint32 num_channels = 0;
3316   guint32 channel_map[49] = { 0 };      /* Up to 6th order */
3317
3318   int i;
3319
3320   GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
3321
3322   qtdemux->header_size += length;
3323   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3324
3325   if (length <= offset + 16) {
3326     GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
3327     return;
3328   }
3329
3330   version = QT_UINT8 (buffer + offset);
3331   ambisonic_type = QT_UINT8 (buffer + offset + 1);
3332   ambisonic_order = QT_UINT32 (buffer + offset + 2);
3333   ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
3334   ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
3335   num_channels = QT_UINT32 (buffer + offset + 8);
3336   for (i = 0; i < num_channels; ++i)
3337     channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
3338
3339   GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
3340   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
3341   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
3342   GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
3343       ambisonic_channel_ordering);
3344   GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
3345       ambisonic_normalization);
3346   GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
3347   for (i = 0; i < num_channels; ++i)
3348     GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
3349
3350   if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
3351     if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
3352       qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
3353
3354     if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
3355       if (num_channels == 4) {
3356         qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
3357
3358         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
3359             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
3360             && (channel_map[0] == 0) && (channel_map[1] == 1)
3361             && (channel_map[2] == 2) && (channel_map[3] == 3))
3362           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
3363
3364         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
3365             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
3366             && (channel_map[0] == 0) && (channel_map[1] == 3)
3367             && (channel_map[2] == 1) && (channel_map[3] == 2))
3368           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
3369       }
3370     }
3371   }
3372
3373   return;
3374 }
3375 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3376
3377 static void
3378 qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
3379     QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
3380     const guint8 * kid)
3381 {
3382   GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
3383   gst_buffer_fill (kid_buf, 0, kid, 16);
3384   if (info->default_properties)
3385     gst_structure_free (info->default_properties);
3386   info->default_properties =
3387       gst_structure_new ("application/x-cenc",
3388       "iv_size", G_TYPE_UINT, iv_size,
3389       "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
3390       "kid", GST_TYPE_BUFFER, kid_buf, NULL);
3391   GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
3392       "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
3393   gst_buffer_unref (kid_buf);
3394 }
3395
3396 static gboolean
3397 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
3398     QtDemuxCencSampleSetInfo * info, GstByteReader * br)
3399 {
3400   guint32 algorithm_id = 0;
3401   const guint8 *kid;
3402   gboolean is_encrypted = TRUE;
3403   guint8 iv_size = 8;
3404
3405   if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
3406     GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
3407     return FALSE;
3408   }
3409
3410   algorithm_id >>= 8;
3411   if (algorithm_id == 0) {
3412     is_encrypted = FALSE;
3413   } else if (algorithm_id == 1) {
3414     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
3415   } else if (algorithm_id == 2) {
3416     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
3417   }
3418
3419   if (!gst_byte_reader_get_uint8 (br, &iv_size))
3420     return FALSE;
3421
3422   if (!gst_byte_reader_get_data (br, 16, &kid))
3423     return FALSE;
3424
3425   qtdemux_update_default_sample_encryption_settings (qtdemux, info,
3426       is_encrypted, iv_size, kid);
3427   gst_structure_set (info->default_properties, "piff_algorithm_id",
3428       G_TYPE_UINT, algorithm_id, NULL);
3429   return TRUE;
3430 }
3431
3432
3433 static void
3434 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
3435     guint offset)
3436 {
3437   GstByteReader br;
3438   guint8 version;
3439   guint32 flags = 0;
3440   guint i;
3441   guint iv_size = 8;
3442   QtDemuxStream *stream;
3443   GstStructure *structure;
3444   QtDemuxCencSampleSetInfo *ss_info = NULL;
3445   const gchar *system_id;
3446   gboolean uses_sub_sample_encryption = FALSE;
3447   guint32 sample_count;
3448
3449   if (QTDEMUX_N_STREAMS (qtdemux) == 0)
3450     return;
3451
3452   stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
3453
3454   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
3455   if (!gst_structure_has_name (structure, "application/x-cenc")) {
3456     GST_WARNING_OBJECT (qtdemux,
3457         "Attempting PIFF box parsing on an unencrypted stream.");
3458     return;
3459   }
3460
3461   gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
3462       G_TYPE_STRING, &system_id, NULL);
3463   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
3464
3465   stream->protected = TRUE;
3466   stream->protection_scheme_type = FOURCC_cenc;
3467
3468   if (!stream->protection_scheme_info)
3469     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
3470
3471   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3472   if (!ss_info->default_properties) {
3473     ss_info->default_properties =
3474         gst_structure_new ("application/x-cenc",
3475         "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
3476         NULL);
3477
3478   }
3479
3480   if (ss_info->crypto_info) {
3481     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3482     g_ptr_array_free (ss_info->crypto_info, TRUE);
3483     ss_info->crypto_info = NULL;
3484   }
3485
3486   /* skip UUID */
3487   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
3488
3489   if (!gst_byte_reader_get_uint8 (&br, &version)) {
3490     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
3491     return;
3492   }
3493
3494   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
3495     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
3496     return;
3497   }
3498
3499   if ((flags & 0x000001)) {
3500     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
3501             &br))
3502       return;
3503   } else if ((flags & 0x000002)) {
3504     uses_sub_sample_encryption = TRUE;
3505   }
3506
3507   if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
3508           &iv_size)) {
3509     GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
3510     return;
3511   }
3512
3513   if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
3514     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
3515     return;
3516   }
3517
3518   ss_info->crypto_info =
3519       g_ptr_array_new_full (sample_count,
3520       (GDestroyNotify) qtdemux_gst_structure_free);
3521
3522   for (i = 0; i < sample_count; ++i) {
3523     GstStructure *properties;
3524     guint8 *data;
3525     GstBuffer *buf;
3526
3527     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3528     if (properties == NULL) {
3529       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3530       qtdemux->cenc_aux_sample_count = i;
3531       return;
3532     }
3533
3534     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
3535       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
3536       gst_structure_free (properties);
3537       qtdemux->cenc_aux_sample_count = i;
3538       return;
3539     }
3540     buf = gst_buffer_new_wrapped (data, iv_size);
3541     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3542     gst_buffer_unref (buf);
3543
3544     if (uses_sub_sample_encryption) {
3545       guint16 n_subsamples;
3546       const GValue *kid_buf_value;
3547
3548       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
3549           || n_subsamples == 0) {
3550         GST_ERROR_OBJECT (qtdemux,
3551             "failed to get subsample count for sample %u", i);
3552         gst_structure_free (properties);
3553         qtdemux->cenc_aux_sample_count = i;
3554         return;
3555       }
3556       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3557       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
3558         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3559             i);
3560         gst_structure_free (properties);
3561         qtdemux->cenc_aux_sample_count = i;
3562         return;
3563       }
3564       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3565
3566       kid_buf_value =
3567           gst_structure_get_value (ss_info->default_properties, "kid");
3568
3569       gst_structure_set (properties,
3570           "subsample_count", G_TYPE_UINT, n_subsamples,
3571           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3572       gst_structure_set_value (properties, "kid", kid_buf_value);
3573       gst_buffer_unref (buf);
3574     } else {
3575       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3576     }
3577
3578     g_ptr_array_add (ss_info->crypto_info, properties);
3579   }
3580
3581   qtdemux->cenc_aux_sample_count = sample_count;
3582 }
3583
3584 static void
3585 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3586 {
3587   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
3588     0x97, 0xA9, 0x42, 0xE8,
3589     0x9C, 0x71, 0x99, 0x94,
3590     0x91, 0xE3, 0xAF, 0xAC
3591   };
3592   static const guint8 playready_uuid[] = {
3593     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
3594     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
3595   };
3596
3597   static const guint8 piff_sample_encryption_uuid[] = {
3598     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3599     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3600   };
3601
3602 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3603   static const guint8 spherical_uuid[] = {
3604     0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
3605     0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd
3606   };
3607 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3608
3609   guint offset;
3610
3611   /* counts as header data */
3612   qtdemux->header_size += length;
3613
3614   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3615
3616   if (length <= offset + 16) {
3617     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3618     return;
3619   }
3620
3621 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3622   if (memcmp (buffer + offset, spherical_uuid, 16) == 0) {
3623     const char *contents;
3624
3625     GST_DEBUG_OBJECT (qtdemux, "spherical uuid was found");
3626     contents = (char *) (buffer + offset + 16);
3627     GST_DEBUG_OBJECT (qtdemux, "contents: %s\n", contents);
3628
3629     if (qtdemux->spherical_metadata)
3630       _parse_spatial_video_metadata_from_xml_string (qtdemux, contents);
3631
3632     return;
3633   }
3634 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3635
3636   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3637     GstBuffer *buf;
3638     GstTagList *taglist;
3639
3640     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3641         length - offset - 16, NULL);
3642     taglist = gst_tag_list_from_xmp_buffer (buf);
3643     gst_buffer_unref (buf);
3644
3645     /* make sure we have a usable taglist */
3646     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3647
3648     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3649
3650   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3651     int len;
3652     const gunichar2 *s_utf16;
3653     char *contents;
3654
3655     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3656     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3657     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3658     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3659
3660     g_free (contents);
3661
3662     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3663         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3664         (NULL));
3665   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3666     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3667   } else {
3668     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3669         GST_READ_UINT32_LE (buffer + offset),
3670         GST_READ_UINT32_LE (buffer + offset + 4),
3671         GST_READ_UINT32_LE (buffer + offset + 8),
3672         GST_READ_UINT32_LE (buffer + offset + 12));
3673   }
3674 }
3675
3676 static void
3677 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3678 {
3679   GstSidxParser sidx_parser;
3680   GstIsoffParserResult res;
3681   guint consumed;
3682
3683   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3684
3685   res =
3686       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3687       &consumed);
3688   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3689   if (res == GST_ISOFF_QT_PARSER_DONE) {
3690     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3691   }
3692   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3693 }
3694
3695 /* caller verifies at least 8 bytes in buf */
3696 static void
3697 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3698     guint64 * plength, guint32 * pfourcc)
3699 {
3700   guint64 length;
3701   guint32 fourcc;
3702
3703   length = QT_UINT32 (data);
3704   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3705   fourcc = QT_FOURCC (data + 4);
3706   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3707
3708   if (length == 0) {
3709     length = G_MAXUINT64;
3710   } else if (length == 1 && size >= 16) {
3711     /* this means we have an extended size, which is the 64 bit value of
3712      * the next 8 bytes */
3713     length = QT_UINT64 (data + 8);
3714     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3715   }
3716
3717   if (plength)
3718     *plength = length;
3719   if (pfourcc)
3720     *pfourcc = fourcc;
3721 }
3722
3723 static gboolean
3724 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3725 {
3726   guint32 version = 0;
3727   GstClockTime duration = 0;
3728
3729   if (!gst_byte_reader_get_uint32_be (br, &version))
3730     goto failed;
3731
3732   version >>= 24;
3733   if (version == 1) {
3734     if (!gst_byte_reader_get_uint64_be (br, &duration))
3735       goto failed;
3736   } else {
3737     guint32 dur = 0;
3738
3739     if (!gst_byte_reader_get_uint32_be (br, &dur))
3740       goto failed;
3741     duration = dur;
3742   }
3743
3744   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3745   qtdemux->duration = duration;
3746
3747   return TRUE;
3748
3749 failed:
3750   {
3751     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3752     return FALSE;
3753   }
3754 }
3755
3756 static gboolean
3757 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3758     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3759 {
3760   if (!stream->parsed_trex && qtdemux->moov_node) {
3761     GNode *mvex, *trex;
3762     GstByteReader trex_data;
3763
3764     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3765     if (mvex) {
3766       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3767           &trex_data);
3768       while (trex) {
3769         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3770
3771         /* skip version/flags */
3772         if (!gst_byte_reader_skip (&trex_data, 4))
3773           goto next;
3774         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3775           goto next;
3776         if (id != stream->track_id)
3777           goto next;
3778         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3779           goto next;
3780         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3781           goto next;
3782         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3783           goto next;
3784         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3785           goto next;
3786
3787         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3788             "duration %d,  size %d, flags 0x%x", stream->track_id,
3789             dur, size, flags);
3790
3791         stream->parsed_trex = TRUE;
3792         stream->def_sample_description_index = sdi;
3793         stream->def_sample_duration = dur;
3794         stream->def_sample_size = size;
3795         stream->def_sample_flags = flags;
3796
3797       next:
3798         /* iterate all siblings */
3799         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3800             &trex_data);
3801       }
3802     }
3803   }
3804
3805   *ds_duration = stream->def_sample_duration;
3806   *ds_size = stream->def_sample_size;
3807   *ds_flags = stream->def_sample_flags;
3808
3809   /* even then, above values are better than random ... */
3810   if (G_UNLIKELY (!stream->parsed_trex)) {
3811     GST_WARNING_OBJECT (qtdemux,
3812         "failed to find fragment defaults for stream %d", stream->track_id);
3813     return FALSE;
3814   }
3815
3816   return TRUE;
3817 }
3818
3819 /* This method should be called whenever a more accurate duration might
3820  * have been found. It will update all relevant variables if/where needed
3821  */
3822 static void
3823 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3824 {
3825   guint i;
3826   guint64 movdur;
3827   GstClockTime prevdur;
3828
3829   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3830
3831   if (movdur > qtdemux->duration) {
3832     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3833     GST_DEBUG_OBJECT (qtdemux,
3834         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3835         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3836     qtdemux->duration = movdur;
3837     GST_DEBUG_OBJECT (qtdemux,
3838         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3839         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3840         GST_TIME_ARGS (qtdemux->segment.stop));
3841     if (qtdemux->segment.duration == prevdur) {
3842       /* If the current segment has duration/stop identical to previous duration
3843        * update them also (because they were set at that point in time with
3844        * the wrong duration */
3845       /* We convert the value *from* the timescale version to avoid rounding errors */
3846       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3847       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3848       qtdemux->segment.duration = fixeddur;
3849       qtdemux->segment.stop = fixeddur;
3850     }
3851   }
3852
3853   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3854     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3855
3856     movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3857     if (movdur > stream->duration) {
3858       GST_DEBUG_OBJECT (qtdemux,
3859           "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3860           GST_TIME_ARGS (duration));
3861       stream->duration = movdur;
3862       /* internal duration tracking state has been updated above, so */
3863       /* preserve an open-ended dummy segment rather than repeatedly updating
3864        * it and spamming downstream accordingly with segment events */
3865       if (stream->dummy_segment &&
3866           GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3867         /* Update all dummy values to new duration */
3868         stream->segments[0].stop_time = duration;
3869         stream->segments[0].duration = duration;
3870         stream->segments[0].media_stop = duration;
3871
3872         /* let downstream know we possibly have a new stop time */
3873         if (stream->segment_index != -1) {
3874           GstClockTime pos;
3875
3876           if (qtdemux->segment.rate >= 0) {
3877             pos = stream->segment.start;
3878           } else {
3879             pos = stream->segment.stop;
3880           }
3881
3882           gst_qtdemux_stream_update_segment (qtdemux, stream,
3883               stream->segment_index, pos, NULL, NULL);
3884         }
3885       }
3886     }
3887   }
3888 }
3889
3890 static gboolean
3891 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3892     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3893     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3894     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3895     gboolean has_tfdt)
3896 {
3897   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3898   guint64 timestamp;
3899   gint32 data_offset = 0;
3900   guint32 flags = 0, first_flags = 0, samples_count = 0;
3901   gint i;
3902   guint8 *data;
3903   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3904   QtDemuxSample *sample;
3905   gboolean ismv = FALSE;
3906   gint64 initial_offset;
3907
3908   GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3909       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3910       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3911       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3912
3913   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3914     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3915     return TRUE;
3916   }
3917
3918   /* presence of stss or not can't really tell us much,
3919    * and flags and so on tend to be marginally reliable in these files */
3920   if (stream->subtype == FOURCC_soun) {
3921     GST_DEBUG_OBJECT (qtdemux,
3922         "sound track in fragmented file; marking all keyframes");
3923     stream->all_keyframe = TRUE;
3924   }
3925
3926   if (!gst_byte_reader_skip (trun, 1) ||
3927       !gst_byte_reader_get_uint24_be (trun, &flags))
3928     goto fail;
3929
3930   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3931     goto fail;
3932
3933   if (flags & TR_DATA_OFFSET) {
3934     /* note this is really signed */
3935     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3936       goto fail;
3937     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3938     /* default base offset = first byte of moof */
3939     if (*base_offset == -1) {
3940       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3941       *base_offset = moof_offset;
3942     }
3943     *running_offset = *base_offset + data_offset;
3944   } else {
3945     /* if no offset at all, that would mean data starts at moof start,
3946      * which is a bit wrong and is ismv crappy way, so compensate
3947      * assuming data is in mdat following moof */
3948     if (*base_offset == -1) {
3949       *base_offset = moof_offset + moof_length + 8;
3950       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3951       ismv = TRUE;
3952     }
3953     if (*running_offset == -1)
3954       *running_offset = *base_offset;
3955   }
3956
3957   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3958       *running_offset);
3959   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3960       data_offset, flags, samples_count);
3961
3962   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3963     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3964       GST_DEBUG_OBJECT (qtdemux,
3965           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3966       flags ^= TR_FIRST_SAMPLE_FLAGS;
3967     } else {
3968       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3969         goto fail;
3970       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3971     }
3972   }
3973
3974   /* FIXME ? spec says other bits should also be checked to determine
3975    * entry size (and prefix size for that matter) */
3976   entry_size = 0;
3977   dur_offset = size_offset = 0;
3978   if (flags & TR_SAMPLE_DURATION) {
3979     GST_LOG_OBJECT (qtdemux, "entry duration present");
3980     dur_offset = entry_size;
3981     entry_size += 4;
3982   }
3983   if (flags & TR_SAMPLE_SIZE) {
3984     GST_LOG_OBJECT (qtdemux, "entry size present");
3985     size_offset = entry_size;
3986     entry_size += 4;
3987   }
3988   if (flags & TR_SAMPLE_FLAGS) {
3989     GST_LOG_OBJECT (qtdemux, "entry flags present");
3990     flags_offset = entry_size;
3991     entry_size += 4;
3992   }
3993   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3994     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3995     ct_offset = entry_size;
3996     entry_size += 4;
3997   }
3998
3999   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
4000     goto fail;
4001   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
4002
4003   if (stream->n_samples + samples_count >=
4004       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
4005     goto index_too_big;
4006
4007   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
4008       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
4009       (stream->n_samples + samples_count) *
4010       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
4011
4012   /* create a new array of samples if it's the first sample parsed */
4013   if (stream->n_samples == 0) {
4014     g_assert (stream->samples == NULL);
4015     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
4016     /* or try to reallocate it with space enough to insert the new samples */
4017   } else
4018     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
4019         stream->n_samples + samples_count);
4020   if (stream->samples == NULL)
4021     goto out_of_memory;
4022
4023   if (qtdemux->fragment_start != -1) {
4024     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
4025     qtdemux->fragment_start = -1;
4026   } else {
4027     if (stream->n_samples == 0) {
4028       if (decode_ts > 0) {
4029         timestamp = decode_ts;
4030       } else if (stream->pending_seek != NULL) {
4031         /* if we don't have a timestamp from a tfdt box, we'll use the one
4032          * from the mfra seek table */
4033         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
4034             GST_TIME_ARGS (stream->pending_seek->ts));
4035
4036         /* FIXME: this is not fully correct, the timestamp refers to the random
4037          * access sample refered to in the tfra entry, which may not necessarily
4038          * be the first sample in the tfrag/trun (but hopefully/usually is) */
4039         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
4040       } else {
4041         timestamp = 0;
4042       }
4043
4044       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
4045       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
4046           GST_TIME_ARGS (gst_ts));
4047     } else {
4048       /* subsequent fragments extend stream */
4049       timestamp =
4050           stream->samples[stream->n_samples - 1].timestamp +
4051           stream->samples[stream->n_samples - 1].duration;
4052
4053       /* If this is a GST_FORMAT_BYTES stream and there's a significant
4054        * difference (1 sec.) between decode_ts and timestamp, prefer the
4055        * former */
4056       if (has_tfdt && !qtdemux->upstream_format_is_time
4057           && ABSDIFF (decode_ts, timestamp) >
4058           MAX (stream->duration_last_moof / 2,
4059               GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
4060         GST_INFO_OBJECT (qtdemux,
4061             "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
4062             ") are significantly different (more than %" GST_TIME_FORMAT
4063             "), using decode_ts",
4064             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
4065             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
4066             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
4067                     MAX (stream->duration_last_moof / 2,
4068                         GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
4069         timestamp = decode_ts;
4070       }
4071
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   initial_offset = *running_offset;
4079
4080   sample = stream->samples + stream->n_samples;
4081   for (i = 0; i < samples_count; i++) {
4082     guint32 dur, size, sflags, ct;
4083
4084     /* first read sample data */
4085     if (flags & TR_SAMPLE_DURATION) {
4086       dur = QT_UINT32 (data + dur_offset);
4087     } else {
4088       dur = d_sample_duration;
4089     }
4090     if (flags & TR_SAMPLE_SIZE) {
4091       size = QT_UINT32 (data + size_offset);
4092     } else {
4093       size = d_sample_size;
4094     }
4095     if (flags & TR_FIRST_SAMPLE_FLAGS) {
4096       if (i == 0) {
4097         sflags = first_flags;
4098       } else {
4099         sflags = d_sample_flags;
4100       }
4101     } else if (flags & TR_SAMPLE_FLAGS) {
4102       sflags = QT_UINT32 (data + flags_offset);
4103     } else {
4104       sflags = d_sample_flags;
4105     }
4106     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
4107       ct = QT_UINT32 (data + ct_offset);
4108     } else {
4109       ct = 0;
4110     }
4111     data += entry_size;
4112
4113     /* fill the sample information */
4114     sample->offset = *running_offset;
4115     sample->pts_offset = ct;
4116     sample->size = size;
4117     sample->timestamp = timestamp;
4118     sample->duration = dur;
4119     /* sample-is-difference-sample */
4120     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
4121      * now idea how it relates to bitfield other than massive LE/BE confusion */
4122     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
4123     *running_offset += size;
4124     timestamp += dur;
4125     stream->duration_moof += dur;
4126     sample++;
4127   }
4128
4129   /* Update total duration if needed */
4130   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
4131
4132   /* Pre-emptively figure out size of mdat based on trun information.
4133    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
4134    * size, else we will still be able to use this when dealing with gap'ed
4135    * input */
4136   qtdemux->mdatleft = *running_offset - initial_offset;
4137   qtdemux->mdatoffset = initial_offset;
4138   qtdemux->mdatsize = qtdemux->mdatleft;
4139
4140   stream->n_samples += samples_count;
4141   stream->n_samples_moof += samples_count;
4142
4143   if (stream->pending_seek != NULL)
4144     stream->pending_seek = NULL;
4145
4146   return TRUE;
4147
4148 fail:
4149   {
4150     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
4151     return FALSE;
4152   }
4153 out_of_memory:
4154   {
4155     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
4156         stream->n_samples);
4157     return FALSE;
4158   }
4159 index_too_big:
4160   {
4161     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
4162         "be larger than %uMB (broken file?)", stream->n_samples,
4163         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
4164     return FALSE;
4165   }
4166 }
4167
4168 /* find stream with @id */
4169 static inline QtDemuxStream *
4170 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
4171 {
4172   QtDemuxStream *stream;
4173   gint i;
4174
4175   /* check */
4176   if (G_UNLIKELY (!id)) {
4177     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
4178     return NULL;
4179   }
4180
4181   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4182     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4183     if (stream->track_id == id)
4184       return stream;
4185   }
4186   if (qtdemux->mss_mode) {
4187     /* mss should have only 1 stream anyway */
4188     return QTDEMUX_NTH_STREAM (qtdemux, 0);
4189   }
4190
4191   return NULL;
4192 }
4193
4194 static gboolean
4195 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
4196     guint32 * fragment_number)
4197 {
4198   if (!gst_byte_reader_skip (mfhd, 4))
4199     goto fail;
4200   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
4201     goto fail;
4202   return TRUE;
4203 fail:
4204   {
4205     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
4206     return FALSE;
4207   }
4208 }
4209
4210 static gboolean
4211 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
4212     QtDemuxStream ** stream, guint32 * default_sample_duration,
4213     guint32 * default_sample_size, guint32 * default_sample_flags,
4214     gint64 * base_offset)
4215 {
4216   guint32 flags = 0;
4217   guint32 track_id = 0;
4218
4219   if (!gst_byte_reader_skip (tfhd, 1) ||
4220       !gst_byte_reader_get_uint24_be (tfhd, &flags))
4221     goto invalid_track;
4222
4223   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
4224     goto invalid_track;
4225
4226   *stream = qtdemux_find_stream (qtdemux, track_id);
4227   if (G_UNLIKELY (!*stream))
4228     goto unknown_stream;
4229
4230   if (flags & TF_DEFAULT_BASE_IS_MOOF)
4231     *base_offset = qtdemux->moof_offset;
4232
4233   if (flags & TF_BASE_DATA_OFFSET)
4234     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
4235       goto invalid_track;
4236
4237   /* obtain stream defaults */
4238   qtdemux_parse_trex (qtdemux, *stream,
4239       default_sample_duration, default_sample_size, default_sample_flags);
4240
4241   (*stream)->stsd_sample_description_id =
4242       (*stream)->def_sample_description_index - 1;
4243
4244   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
4245     guint32 sample_description_index;
4246     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
4247       goto invalid_track;
4248     (*stream)->stsd_sample_description_id = sample_description_index - 1;
4249   }
4250
4251   if (qtdemux->mss_mode) {
4252     /* mss has no stsd entry */
4253     (*stream)->stsd_sample_description_id = 0;
4254   }
4255
4256   if (flags & TF_DEFAULT_SAMPLE_DURATION)
4257     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
4258       goto invalid_track;
4259
4260   if (flags & TF_DEFAULT_SAMPLE_SIZE)
4261     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
4262       goto invalid_track;
4263
4264   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
4265     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
4266       goto invalid_track;
4267
4268   return TRUE;
4269
4270 invalid_track:
4271   {
4272     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
4273     return FALSE;
4274   }
4275 unknown_stream:
4276   {
4277     GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
4278     return TRUE;
4279   }
4280 }
4281
4282 static gboolean
4283 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
4284     guint64 * decode_time)
4285 {
4286   guint32 version = 0;
4287
4288   if (!gst_byte_reader_get_uint32_be (br, &version))
4289     return FALSE;
4290
4291   version >>= 24;
4292   if (version == 1) {
4293     if (!gst_byte_reader_get_uint64_be (br, decode_time))
4294       goto failed;
4295   } else {
4296     guint32 dec_time = 0;
4297     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
4298       goto failed;
4299     *decode_time = dec_time;
4300   }
4301
4302   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
4303       *decode_time);
4304
4305   return TRUE;
4306
4307 failed:
4308   {
4309     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
4310     return FALSE;
4311   }
4312 }
4313
4314 /* Returns a pointer to a GstStructure containing the properties of
4315  * the stream sample identified by @sample_index. The caller must unref
4316  * the returned object after use. Returns NULL if unsuccessful. */
4317 static GstStructure *
4318 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
4319     QtDemuxStream * stream, guint sample_index)
4320 {
4321   QtDemuxCencSampleSetInfo *info = NULL;
4322
4323   g_return_val_if_fail (stream != NULL, NULL);
4324   g_return_val_if_fail (stream->protected, NULL);
4325   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
4326
4327   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4328
4329   /* Currently, cenc properties for groups of samples are not supported, so
4330    * simply return a copy of the default sample properties */
4331   return gst_structure_copy (info->default_properties);
4332 }
4333
4334 /* Parses the sizes of sample auxiliary information contained within a stream,
4335  * as given in a saiz box. Returns array of sample_count guint8 size values,
4336  * or NULL on failure */
4337 static guint8 *
4338 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
4339     GstByteReader * br, guint32 * sample_count)
4340 {
4341   guint32 flags = 0;
4342   guint8 *info_sizes;
4343   guint8 default_info_size;
4344
4345   g_return_val_if_fail (qtdemux != NULL, NULL);
4346   g_return_val_if_fail (stream != NULL, NULL);
4347   g_return_val_if_fail (br != NULL, NULL);
4348   g_return_val_if_fail (sample_count != NULL, NULL);
4349
4350   if (!gst_byte_reader_get_uint32_be (br, &flags))
4351     return NULL;
4352
4353   if (flags & 0x1) {
4354     /* aux_info_type and aux_info_type_parameter are ignored */
4355     if (!gst_byte_reader_skip (br, 8))
4356       return NULL;
4357   }
4358
4359   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
4360     return NULL;
4361   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
4362
4363   if (!gst_byte_reader_get_uint32_be (br, sample_count))
4364     return NULL;
4365   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
4366
4367
4368   if (default_info_size == 0) {
4369     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
4370       return NULL;
4371     }
4372   } else {
4373     info_sizes = g_new (guint8, *sample_count);
4374     memset (info_sizes, default_info_size, *sample_count);
4375   }
4376
4377   return info_sizes;
4378 }
4379
4380 /* Parses the offset of sample auxiliary information contained within a stream,
4381  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
4382 static gboolean
4383 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
4384     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
4385     guint64 * offset)
4386 {
4387   guint8 version = 0;
4388   guint32 flags = 0;
4389   guint32 aux_info_type = 0;
4390   guint32 aux_info_type_parameter = 0;
4391   guint32 entry_count;
4392   guint32 off_32;
4393   guint64 off_64;
4394   const guint8 *aux_info_type_data = NULL;
4395
4396   g_return_val_if_fail (qtdemux != NULL, FALSE);
4397   g_return_val_if_fail (stream != NULL, FALSE);
4398   g_return_val_if_fail (br != NULL, FALSE);
4399   g_return_val_if_fail (offset != NULL, FALSE);
4400
4401   if (!gst_byte_reader_get_uint8 (br, &version))
4402     return FALSE;
4403
4404   if (!gst_byte_reader_get_uint24_be (br, &flags))
4405     return FALSE;
4406
4407   if (flags & 0x1) {
4408
4409     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
4410       return FALSE;
4411     aux_info_type = QT_FOURCC (aux_info_type_data);
4412
4413     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
4414       return FALSE;
4415   } else if (stream->protected) {
4416     aux_info_type = stream->protection_scheme_type;
4417   } else {
4418     aux_info_type = CUR_STREAM (stream)->fourcc;
4419   }
4420
4421   if (info_type)
4422     *info_type = aux_info_type;
4423   if (info_type_parameter)
4424     *info_type_parameter = aux_info_type_parameter;
4425
4426   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
4427       "aux_info_type_parameter:  %#06x",
4428       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
4429
4430   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
4431     return FALSE;
4432
4433   if (entry_count != 1) {
4434     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
4435     return FALSE;
4436   }
4437
4438   if (version == 0) {
4439     if (!gst_byte_reader_get_uint32_be (br, &off_32))
4440       return FALSE;
4441     *offset = (guint64) off_32;
4442   } else {
4443     if (!gst_byte_reader_get_uint64_be (br, &off_64))
4444       return FALSE;
4445     *offset = off_64;
4446   }
4447
4448   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
4449   return TRUE;
4450 }
4451
4452 static void
4453 qtdemux_gst_structure_free (GstStructure * gststructure)
4454 {
4455   if (gststructure) {
4456     gst_structure_free (gststructure);
4457   }
4458 }
4459
4460 /* Parses auxiliary information relating to samples protected using Common
4461  * Encryption (cenc); the format of this information is defined in
4462  * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
4463 static gboolean
4464 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
4465     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
4466 {
4467   QtDemuxCencSampleSetInfo *ss_info = NULL;
4468   guint8 size;
4469   gint i;
4470   GPtrArray *old_crypto_info = NULL;
4471   guint old_entries = 0;
4472
4473   g_return_val_if_fail (qtdemux != NULL, FALSE);
4474   g_return_val_if_fail (stream != NULL, FALSE);
4475   g_return_val_if_fail (br != NULL, FALSE);
4476   g_return_val_if_fail (stream->protected, FALSE);
4477   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
4478
4479   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4480
4481   if (ss_info->crypto_info) {
4482     old_crypto_info = ss_info->crypto_info;
4483     /* Count number of non-null entries remaining at the tail end */
4484     for (i = old_crypto_info->len - 1; i >= 0; i--) {
4485       if (g_ptr_array_index (old_crypto_info, i) == NULL)
4486         break;
4487       old_entries++;
4488     }
4489   }
4490
4491   ss_info->crypto_info =
4492       g_ptr_array_new_full (sample_count + old_entries,
4493       (GDestroyNotify) qtdemux_gst_structure_free);
4494
4495   /* We preserve old entries because we parse the next moof in advance
4496    * of consuming all samples from the previous moof, and otherwise
4497    * we'd discard the corresponding crypto info for the samples
4498    * from the previous fragment. */
4499   if (old_entries) {
4500     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
4501         old_entries);
4502     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
4503       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
4504               i));
4505       g_ptr_array_index (old_crypto_info, i) = NULL;
4506     }
4507   }
4508
4509   if (old_crypto_info) {
4510     /* Everything now belongs to the new array */
4511     g_ptr_array_free (old_crypto_info, TRUE);
4512   }
4513
4514   for (i = 0; i < sample_count; ++i) {
4515     GstStructure *properties;
4516     guint16 n_subsamples = 0;
4517     guint8 *data;
4518     guint iv_size;
4519     GstBuffer *buf;
4520
4521     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
4522     if (properties == NULL) {
4523       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
4524       return FALSE;
4525     }
4526     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
4527       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
4528       gst_structure_free (properties);
4529       return FALSE;
4530     }
4531     if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
4532       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4533       gst_structure_free (properties);
4534       return FALSE;
4535     }
4536     buf = gst_buffer_new_wrapped (data, iv_size);
4537     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
4538     gst_buffer_unref (buf);
4539     size = info_sizes[i];
4540     if (size > iv_size) {
4541       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4542           || !(n_subsamples > 0)) {
4543         gst_structure_free (properties);
4544         GST_ERROR_OBJECT (qtdemux,
4545             "failed to get subsample count for sample %u", i);
4546         return FALSE;
4547       }
4548       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4549       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4550         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4551             i);
4552         gst_structure_free (properties);
4553         return FALSE;
4554       }
4555       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4556       if (!buf) {
4557         gst_structure_free (properties);
4558         return FALSE;
4559       }
4560       gst_structure_set (properties,
4561           "subsample_count", G_TYPE_UINT, n_subsamples,
4562           "subsamples", GST_TYPE_BUFFER, buf, NULL);
4563       gst_buffer_unref (buf);
4564     } else {
4565       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4566     }
4567     g_ptr_array_add (ss_info->crypto_info, properties);
4568   }
4569   return TRUE;
4570 }
4571
4572 /* Converts a UUID in raw byte form to a string representation, as defined in
4573  * RFC 4122. The caller takes ownership of the returned string and is
4574  * responsible for freeing it after use. */
4575 static gchar *
4576 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4577 {
4578   const guint8 *uuid = (const guint8 *) uuid_bytes;
4579
4580   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4581       "%02x%02x-%02x%02x%02x%02x%02x%02x",
4582       uuid[0], uuid[1], uuid[2], uuid[3],
4583       uuid[4], uuid[5], uuid[6], uuid[7],
4584       uuid[8], uuid[9], uuid[10], uuid[11],
4585       uuid[12], uuid[13], uuid[14], uuid[15]);
4586 }
4587
4588 /* Parses a Protection System Specific Header box (pssh), as defined in the
4589  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4590  * information needed by a specific content protection system in order to
4591  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4592  * otherwise. */
4593 static gboolean
4594 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4595 {
4596   gchar *sysid_string;
4597   guint32 pssh_size = QT_UINT32 (node->data);
4598   GstBuffer *pssh = NULL;
4599   GstEvent *event = NULL;
4600   guint32 parent_box_type;
4601   gint i;
4602
4603   if (G_UNLIKELY (pssh_size < 32U)) {
4604     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4605     return FALSE;
4606   }
4607
4608   sysid_string =
4609       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4610
4611   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4612
4613   pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
4614   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4615       gst_buffer_get_size (pssh));
4616
4617   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4618
4619   /* Push an event containing the pssh box onto the queues of all streams. */
4620   event = gst_event_new_protection (sysid_string, pssh,
4621       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4622   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4623     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4624     GST_TRACE_OBJECT (qtdemux,
4625         "adding protection event for stream %s and system %s",
4626         stream->stream_id, sysid_string);
4627     g_queue_push_tail (&stream->protection_scheme_event_queue,
4628         gst_event_ref (event));
4629   }
4630   g_free (sysid_string);
4631   gst_event_unref (event);
4632   gst_buffer_unref (pssh);
4633   return TRUE;
4634 }
4635
4636 static gboolean
4637 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4638     guint64 moof_offset, QtDemuxStream * stream)
4639 {
4640   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4641   GNode *uuid_node;
4642   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4643   GNode *saiz_node, *saio_node, *pssh_node;
4644   GstByteReader saiz_data, saio_data;
4645   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4646   gint64 base_offset, running_offset;
4647   guint32 frag_num;
4648   GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4649
4650   /* NOTE @stream ignored */
4651
4652   moof_node = g_node_new ((guint8 *) buffer);
4653   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4654   qtdemux_node_dump (qtdemux, moof_node);
4655
4656   /* Get fragment number from mfhd and check it's valid */
4657   mfhd_node =
4658       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4659   if (mfhd_node == NULL)
4660     goto missing_mfhd;
4661   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4662     goto fail;
4663   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4664
4665   /* unknown base_offset to start with */
4666   base_offset = running_offset = -1;
4667   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4668   while (traf_node) {
4669     guint64 decode_time = 0;
4670
4671     /* Fragment Header node */
4672     tfhd_node =
4673         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4674         &tfhd_data);
4675     if (!tfhd_node)
4676       goto missing_tfhd;
4677     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4678             &ds_size, &ds_flags, &base_offset))
4679       goto missing_tfhd;
4680
4681     /* The following code assumes at most a single set of sample auxiliary
4682      * data in the fragment (consisting of a saiz box and a corresponding saio
4683      * box); in theory, however, there could be multiple sets of sample
4684      * auxiliary data in a fragment. */
4685     saiz_node =
4686         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4687         &saiz_data);
4688     if (saiz_node) {
4689       guint32 info_type = 0;
4690       guint64 offset = 0;
4691       guint32 info_type_parameter = 0;
4692
4693       g_free (qtdemux->cenc_aux_info_sizes);
4694
4695       qtdemux->cenc_aux_info_sizes =
4696           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4697           &qtdemux->cenc_aux_sample_count);
4698       if (qtdemux->cenc_aux_info_sizes == NULL) {
4699         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4700         goto fail;
4701       }
4702       saio_node =
4703           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4704           &saio_data);
4705       if (!saio_node) {
4706         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4707         g_free (qtdemux->cenc_aux_info_sizes);
4708         qtdemux->cenc_aux_info_sizes = NULL;
4709         goto fail;
4710       }
4711
4712       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4713                   &info_type, &info_type_parameter, &offset))) {
4714         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4715         g_free (qtdemux->cenc_aux_info_sizes);
4716         qtdemux->cenc_aux_info_sizes = NULL;
4717         goto fail;
4718       }
4719       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4720         offset += (guint64) (base_offset - qtdemux->moof_offset);
4721       if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4722         GstByteReader br;
4723         if (offset > length) {
4724           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4725           qtdemux->cenc_aux_info_offset = offset;
4726         } else {
4727           gst_byte_reader_init (&br, buffer + offset, length - offset);
4728           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4729                   qtdemux->cenc_aux_info_sizes,
4730                   qtdemux->cenc_aux_sample_count)) {
4731             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4732             g_free (qtdemux->cenc_aux_info_sizes);
4733             qtdemux->cenc_aux_info_sizes = NULL;
4734             goto fail;
4735           }
4736         }
4737       }
4738     }
4739
4740     tfdt_node =
4741         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4742         &tfdt_data);
4743     if (tfdt_node) {
4744       /* We'll use decode_time to interpolate timestamps
4745        * in case the input timestamps are missing */
4746       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4747
4748       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4749           " (%" GST_TIME_FORMAT ")", decode_time,
4750           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4751                   decode_time) : GST_CLOCK_TIME_NONE));
4752
4753       /* Discard the fragment buffer timestamp info to avoid using it.
4754        * Rely on tfdt instead as it is more accurate than the timestamp
4755        * that is fetched from a manifest/playlist and is usually
4756        * less accurate. */
4757       qtdemux->fragment_start = -1;
4758     }
4759
4760     if (G_UNLIKELY (!stream)) {
4761       /* we lost track of offset, we'll need to regain it,
4762        * but can delay complaining until later or avoid doing so altogether */
4763       base_offset = -2;
4764       goto next;
4765     }
4766     if (G_UNLIKELY (base_offset < -1))
4767       goto lost_offset;
4768
4769     min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4770
4771     if (!qtdemux->pullbased) {
4772       /* Sample tables can grow enough to be problematic if the system memory
4773        * is very low (e.g. embedded devices) and the videos very long
4774        * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4775        * Fortunately, we can easily discard them for each new fragment when
4776        * we know qtdemux will not receive seeks outside of the current fragment.
4777        * adaptivedemux honors this assumption.
4778        * This optimization is also useful for applications that use qtdemux as
4779        * a push-based simple demuxer, like Media Source Extensions. */
4780       gst_qtdemux_stream_flush_samples_data (stream);
4781     }
4782
4783     /* initialise moof sample data */
4784     stream->n_samples_moof = 0;
4785     stream->duration_last_moof = stream->duration_moof;
4786     stream->duration_moof = 0;
4787
4788     /* Track Run node */
4789     trun_node =
4790         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4791         &trun_data);
4792     while (trun_node) {
4793       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4794           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4795           &running_offset, decode_time, (tfdt_node != NULL));
4796       /* iterate all siblings */
4797       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4798           &trun_data);
4799     }
4800
4801     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4802     if (uuid_node) {
4803       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4804       guint32 box_length = QT_UINT32 (uuid_buffer);
4805
4806       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4807     }
4808
4809     /* if no new base_offset provided for next traf,
4810      * base is end of current traf */
4811     base_offset = running_offset;
4812     running_offset = -1;
4813
4814     if (stream->n_samples_moof && stream->duration_moof)
4815       stream->new_caps = TRUE;
4816
4817   next:
4818     /* iterate all siblings */
4819     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4820   }
4821
4822   /* parse any protection system info */
4823   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4824   while (pssh_node) {
4825     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4826     qtdemux_parse_pssh (qtdemux, pssh_node);
4827     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4828   }
4829
4830   if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4831       && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4832       && min_dts != 0) {
4833     /* Unless the user has explictly requested another seek, perform an
4834      * internal seek to the time specified in the tfdt.
4835      *
4836      * This way if the user opens a file where the first tfdt is 1 hour
4837      * into the presentation, they will not have to wait 1 hour for run
4838      * time to catch up and actual playback to start. */
4839     gint i;
4840
4841     GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4842         "performing an internal seek to %" GST_TIME_FORMAT,
4843         GST_TIME_ARGS (min_dts));
4844
4845     qtdemux->segment.start = min_dts;
4846     qtdemux->segment.time = qtdemux->segment.position = min_dts;
4847
4848     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4849       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4850       stream->time_position = min_dts;
4851     }
4852
4853     /* Before this code was run a segment was already sent when the moov was
4854      * parsed... which is OK -- some apps (mostly tests) expect a segment to
4855      * be emitted after a moov, and we can emit a second segment anyway for
4856      * special cases like this. */
4857     qtdemux->need_segment = TRUE;
4858   }
4859
4860   qtdemux->first_moof_already_parsed = TRUE;
4861
4862   g_node_destroy (moof_node);
4863   return TRUE;
4864
4865 missing_tfhd:
4866   {
4867     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4868     goto fail;
4869   }
4870 missing_mfhd:
4871   {
4872     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4873     goto fail;
4874   }
4875 lost_offset:
4876   {
4877     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4878     goto fail;
4879   }
4880 fail:
4881   {
4882     g_node_destroy (moof_node);
4883     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4884         (_("This file is corrupt and cannot be played.")), (NULL));
4885     return FALSE;
4886   }
4887 }
4888
4889 #if 0
4890 /* might be used if some day we actually use mfra & co
4891  * for random access to fragments,
4892  * but that will require quite some modifications and much less relying
4893  * on a sample array */
4894 #endif
4895
4896 static gboolean
4897 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4898 {
4899   QtDemuxStream *stream;
4900   guint32 ver_flags, track_id, len, num_entries, i;
4901   guint value_size, traf_size, trun_size, sample_size;
4902   guint64 time = 0, moof_offset = 0;
4903 #if 0
4904   GstBuffer *buf = NULL;
4905   GstFlowReturn ret;
4906 #endif
4907   GstByteReader tfra;
4908
4909   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4910
4911   if (!gst_byte_reader_skip (&tfra, 8))
4912     return FALSE;
4913
4914   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4915     return FALSE;
4916
4917   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4918       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4919       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4920     return FALSE;
4921
4922   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4923
4924   stream = qtdemux_find_stream (qtdemux, track_id);
4925   if (stream == NULL)
4926     goto unknown_trackid;
4927
4928   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4929   sample_size = (len & 3) + 1;
4930   trun_size = ((len & 12) >> 2) + 1;
4931   traf_size = ((len & 48) >> 4) + 1;
4932
4933   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4934       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4935
4936   if (num_entries == 0)
4937     goto no_samples;
4938
4939   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4940           value_size + value_size + traf_size + trun_size + sample_size))
4941     goto corrupt_file;
4942
4943   g_free (stream->ra_entries);
4944   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4945   stream->n_ra_entries = num_entries;
4946
4947   for (i = 0; i < num_entries; i++) {
4948     qt_atom_parser_get_offset (&tfra, value_size, &time);
4949     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4950     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4951     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4952     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4953
4954     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4955
4956     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4957         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4958
4959     stream->ra_entries[i].ts = time;
4960     stream->ra_entries[i].moof_offset = moof_offset;
4961
4962     /* don't want to go through the entire file and read all moofs at startup */
4963 #if 0
4964     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4965     if (ret != GST_FLOW_OK)
4966       goto corrupt_file;
4967     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4968         moof_offset, stream);
4969     gst_buffer_unref (buf);
4970 #endif
4971   }
4972
4973   check_update_duration (qtdemux, time);
4974
4975   return TRUE;
4976
4977 /* ERRORS */
4978 unknown_trackid:
4979   {
4980     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4981     return FALSE;
4982   }
4983 corrupt_file:
4984   {
4985     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4986     return FALSE;
4987   }
4988 no_samples:
4989   {
4990     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4991     return FALSE;
4992   }
4993 }
4994
4995 static gboolean
4996 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4997 {
4998   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4999   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
5000   GstBuffer *mfro = NULL, *mfra = NULL;
5001   GstFlowReturn flow;
5002   gboolean ret = FALSE;
5003   GNode *mfra_node, *tfra_node;
5004   guint64 mfra_offset = 0;
5005   guint32 fourcc, mfra_size;
5006   gint64 len;
5007
5008   /* query upstream size in bytes */
5009   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
5010     goto size_query_failed;
5011
5012   /* mfro box should be at the very end of the file */
5013   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
5014   if (flow != GST_FLOW_OK)
5015     goto exit;
5016
5017   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
5018
5019   fourcc = QT_FOURCC (mfro_map.data + 4);
5020   if (fourcc != FOURCC_mfro)
5021     goto exit;
5022
5023   GST_INFO_OBJECT (qtdemux, "Found mfro box");
5024   if (mfro_map.size < 16)
5025     goto invalid_mfro_size;
5026
5027   mfra_size = QT_UINT32 (mfro_map.data + 12);
5028   if (mfra_size >= len)
5029     goto invalid_mfra_size;
5030
5031   mfra_offset = len - mfra_size;
5032
5033   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
5034       mfra_offset, mfra_size);
5035
5036   /* now get and parse mfra box */
5037   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
5038   if (flow != GST_FLOW_OK)
5039     goto broken_file;
5040
5041   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
5042
5043   mfra_node = g_node_new ((guint8 *) mfra_map.data);
5044   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
5045
5046   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
5047
5048   while (tfra_node) {
5049     qtdemux_parse_tfra (qtdemux, tfra_node);
5050     /* iterate all siblings */
5051     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
5052   }
5053   g_node_destroy (mfra_node);
5054
5055   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
5056   ret = TRUE;
5057
5058 exit:
5059
5060   if (mfro) {
5061     if (mfro_map.memory != NULL)
5062       gst_buffer_unmap (mfro, &mfro_map);
5063     gst_buffer_unref (mfro);
5064   }
5065   if (mfra) {
5066     if (mfra_map.memory != NULL)
5067       gst_buffer_unmap (mfra, &mfra_map);
5068     gst_buffer_unref (mfra);
5069   }
5070   return ret;
5071
5072 /* ERRORS */
5073 size_query_failed:
5074   {
5075     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
5076     goto exit;
5077   }
5078 invalid_mfro_size:
5079   {
5080     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
5081     goto exit;
5082   }
5083 invalid_mfra_size:
5084   {
5085     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
5086     goto exit;
5087   }
5088 broken_file:
5089   {
5090     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
5091     goto exit;
5092   }
5093 }
5094
5095 static guint64
5096 add_offset (guint64 offset, guint64 advance)
5097 {
5098   /* Avoid 64-bit overflow by clamping */
5099   if (offset > G_MAXUINT64 - advance)
5100     return G_MAXUINT64;
5101   return offset + advance;
5102 }
5103
5104 static GstFlowReturn
5105 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
5106 {
5107   guint64 length = 0;
5108   guint32 fourcc = 0;
5109   GstBuffer *buf = NULL;
5110   GstFlowReturn ret = GST_FLOW_OK;
5111   guint64 cur_offset = qtdemux->offset;
5112   GstMapInfo map;
5113
5114   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
5115   if (G_UNLIKELY (ret != GST_FLOW_OK))
5116     goto beach;
5117   gst_buffer_map (buf, &map, GST_MAP_READ);
5118   if (G_LIKELY (map.size >= 8))
5119     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
5120   gst_buffer_unmap (buf, &map);
5121   gst_buffer_unref (buf);
5122
5123   /* maybe we already got most we needed, so only consider this eof */
5124   if (G_UNLIKELY (length == 0)) {
5125     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5126         (_("Invalid atom size.")),
5127         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
5128             GST_FOURCC_ARGS (fourcc)));
5129     ret = GST_FLOW_EOS;
5130     goto beach;
5131   }
5132
5133   switch (fourcc) {
5134     case FOURCC_moof:
5135       /* record for later parsing when needed */
5136       if (!qtdemux->moof_offset) {
5137         qtdemux->moof_offset = qtdemux->offset;
5138       }
5139       if (qtdemux_pull_mfro_mfra (qtdemux)) {
5140         /* FIXME */
5141       } else {
5142         qtdemux->offset += length;      /* skip moof and keep going */
5143       }
5144       if (qtdemux->got_moov) {
5145         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
5146         ret = GST_FLOW_EOS;
5147         goto beach;
5148       }
5149       break;
5150     case FOURCC_mdat:
5151     case FOURCC_free:
5152     case FOURCC_skip:
5153     case FOURCC_wide:
5154     case FOURCC_PICT:
5155     case FOURCC_pnot:
5156     {
5157       GST_LOG_OBJECT (qtdemux,
5158           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5159           GST_FOURCC_ARGS (fourcc), cur_offset);
5160       qtdemux->offset = add_offset (qtdemux->offset, length);
5161       break;
5162     }
5163     case FOURCC_moov:
5164     {
5165       GstBuffer *moov = NULL;
5166
5167       if (qtdemux->got_moov) {
5168         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
5169         qtdemux->offset = add_offset (qtdemux->offset, length);
5170         goto beach;
5171       }
5172
5173       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
5174       if (ret != GST_FLOW_OK)
5175         goto beach;
5176       gst_buffer_map (moov, &map, GST_MAP_READ);
5177
5178       if (length != map.size) {
5179         /* Some files have a 'moov' atom at the end of the file which contains
5180          * a terminal 'free' atom where the body of the atom is missing.
5181          * Check for, and permit, this special case.
5182          */
5183         if (map.size >= 8) {
5184           guint8 *final_data = map.data + (map.size - 8);
5185           guint32 final_length = QT_UINT32 (final_data);
5186           guint32 final_fourcc = QT_FOURCC (final_data + 4);
5187
5188           if (final_fourcc == FOURCC_free
5189               && map.size + final_length - 8 == length) {
5190             /* Ok, we've found that special case. Allocate a new buffer with
5191              * that free atom actually present. */
5192             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
5193             gst_buffer_fill (newmoov, 0, map.data, map.size);
5194             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
5195             gst_buffer_unmap (moov, &map);
5196             gst_buffer_unref (moov);
5197             moov = newmoov;
5198             gst_buffer_map (moov, &map, GST_MAP_READ);
5199           }
5200         }
5201       }
5202
5203       if (length != map.size) {
5204         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5205             (_("This file is incomplete and cannot be played.")),
5206             ("We got less than expected (received %" G_GSIZE_FORMAT
5207                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
5208                 (guint) length, cur_offset));
5209         gst_buffer_unmap (moov, &map);
5210         gst_buffer_unref (moov);
5211         ret = GST_FLOW_ERROR;
5212         goto beach;
5213       }
5214       qtdemux->offset += length;
5215
5216       qtdemux_parse_moov (qtdemux, map.data, length);
5217       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
5218
5219       qtdemux_parse_tree (qtdemux);
5220       if (qtdemux->moov_node_compressed) {
5221         g_node_destroy (qtdemux->moov_node_compressed);
5222         g_free (qtdemux->moov_node->data);
5223       }
5224       qtdemux->moov_node_compressed = NULL;
5225       g_node_destroy (qtdemux->moov_node);
5226       qtdemux->moov_node = NULL;
5227       gst_buffer_unmap (moov, &map);
5228       gst_buffer_unref (moov);
5229       qtdemux->got_moov = TRUE;
5230
5231       break;
5232     }
5233     case FOURCC_ftyp:
5234     {
5235       GstBuffer *ftyp = NULL;
5236
5237       /* extract major brand; might come in handy for ISO vs QT issues */
5238       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
5239       if (ret != GST_FLOW_OK)
5240         goto beach;
5241       qtdemux->offset += length;
5242       gst_buffer_map (ftyp, &map, GST_MAP_READ);
5243       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
5244       gst_buffer_unmap (ftyp, &map);
5245       gst_buffer_unref (ftyp);
5246       break;
5247     }
5248     case FOURCC_uuid:
5249     {
5250       GstBuffer *uuid = NULL;
5251
5252       /* uuid are extension atoms */
5253       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
5254       if (ret != GST_FLOW_OK)
5255         goto beach;
5256       qtdemux->offset += length;
5257       gst_buffer_map (uuid, &map, GST_MAP_READ);
5258       qtdemux_parse_uuid (qtdemux, map.data, map.size);
5259       gst_buffer_unmap (uuid, &map);
5260       gst_buffer_unref (uuid);
5261       break;
5262     }
5263     case FOURCC_sidx:
5264     {
5265       GstBuffer *sidx = NULL;
5266       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
5267       if (ret != GST_FLOW_OK)
5268         goto beach;
5269       qtdemux->offset += length;
5270       gst_buffer_map (sidx, &map, GST_MAP_READ);
5271       qtdemux_parse_sidx (qtdemux, map.data, map.size);
5272       gst_buffer_unmap (sidx, &map);
5273       gst_buffer_unref (sidx);
5274       break;
5275     }
5276     default:
5277     {
5278       GstBuffer *unknown = NULL;
5279
5280       GST_LOG_OBJECT (qtdemux,
5281           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
5282           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
5283           cur_offset);
5284       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
5285       if (ret != GST_FLOW_OK)
5286         goto beach;
5287       gst_buffer_map (unknown, &map, GST_MAP_READ);
5288       GST_MEMDUMP ("Unknown tag", map.data, map.size);
5289       gst_buffer_unmap (unknown, &map);
5290       gst_buffer_unref (unknown);
5291       qtdemux->offset += length;
5292       break;
5293     }
5294   }
5295
5296 beach:
5297   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
5298     /* digested all data, show what we have */
5299 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
5300     if (qtdemux->spherical_metadata)
5301       _send_spherical_metadata_msg_to_bus (qtdemux);
5302 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
5303     qtdemux_prepare_streams (qtdemux);
5304     QTDEMUX_EXPOSE_LOCK (qtdemux);
5305     ret = qtdemux_expose_streams (qtdemux);
5306     QTDEMUX_EXPOSE_UNLOCK (qtdemux);
5307
5308     qtdemux->state = QTDEMUX_STATE_MOVIE;
5309     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
5310         qtdemux->state);
5311     return ret;
5312   }
5313   return ret;
5314 }
5315
5316 /* Seeks to the previous keyframe of the indexed stream and
5317  * aligns other streams with respect to the keyframe timestamp
5318  * of indexed stream. Only called in case of Reverse Playback
5319  */
5320 static GstFlowReturn
5321 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
5322 {
5323   guint32 seg_idx = 0, k_index = 0;
5324   guint32 ref_seg_idx, ref_k_index;
5325   GstClockTime k_pos = 0, last_stop = 0;
5326   QtDemuxSegment *seg = NULL;
5327   QtDemuxStream *ref_str = NULL;
5328   guint64 seg_media_start_mov;  /* segment media start time in mov format */
5329   guint64 target_ts;
5330   gint i;
5331
5332   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
5333    * and finally align all the other streams on that timestamp with their
5334    * respective keyframes */
5335   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
5336     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
5337
5338     /* No candidate yet, take the first stream */
5339     if (!ref_str) {
5340       ref_str = str;
5341       continue;
5342     }
5343
5344     /* So that stream has a segment, we prefer video streams */
5345     if (str->subtype == FOURCC_vide) {
5346       ref_str = str;
5347       break;
5348     }
5349   }
5350
5351   if (G_UNLIKELY (!ref_str)) {
5352     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
5353     goto eos;
5354   }
5355
5356   if (G_UNLIKELY (!ref_str->from_sample)) {
5357     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
5358     goto eos;
5359   }
5360
5361   /* So that stream has been playing from from_sample to to_sample. We will
5362    * get the timestamp of the previous sample and search for a keyframe before
5363    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
5364   if (ref_str->subtype == FOURCC_vide) {
5365     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
5366         ref_str->from_sample - 1, FALSE);
5367   } else {
5368     if (ref_str->from_sample >= 10)
5369       k_index = ref_str->from_sample - 10;
5370     else
5371       k_index = 0;
5372   }
5373
5374   target_ts =
5375       ref_str->samples[k_index].timestamp +
5376       ref_str->samples[k_index].pts_offset;
5377
5378   /* get current segment for that stream */
5379   seg = &ref_str->segments[ref_str->segment_index];
5380   /* Use segment start in original timescale for comparisons */
5381   seg_media_start_mov = seg->trak_media_start;
5382
5383   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
5384       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
5385       k_index, target_ts, seg_media_start_mov,
5386       GST_TIME_ARGS (seg->media_start));
5387
5388   /* Crawl back through segments to find the one containing this I frame */
5389   while (target_ts < seg_media_start_mov) {
5390     GST_DEBUG_OBJECT (qtdemux,
5391         "keyframe position (sample %u) is out of segment %u " " target %"
5392         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
5393         ref_str->segment_index, target_ts, seg_media_start_mov);
5394
5395     if (G_UNLIKELY (!ref_str->segment_index)) {
5396       /* Reached first segment, let's consider it's EOS */
5397       goto eos;
5398     }
5399     ref_str->segment_index--;
5400     seg = &ref_str->segments[ref_str->segment_index];
5401     /* Use segment start in original timescale for comparisons */
5402     seg_media_start_mov = seg->trak_media_start;
5403   }
5404   /* Calculate time position of the keyframe and where we should stop */
5405   k_pos =
5406       QTSTREAMTIME_TO_GSTTIME (ref_str,
5407       target_ts - seg->trak_media_start) + seg->time;
5408   last_stop =
5409       QTSTREAMTIME_TO_GSTTIME (ref_str,
5410       ref_str->samples[ref_str->from_sample].timestamp -
5411       seg->trak_media_start) + seg->time;
5412
5413   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
5414       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
5415       k_index, GST_TIME_ARGS (k_pos));
5416
5417   /* Set last_stop with the keyframe timestamp we pushed of that stream */
5418   qtdemux->segment.position = last_stop;
5419   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
5420       GST_TIME_ARGS (last_stop));
5421
5422   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
5423     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
5424     goto eos;
5425   }
5426
5427   ref_seg_idx = ref_str->segment_index;
5428   ref_k_index = k_index;
5429
5430   /* Align them all on this */
5431   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
5432     guint32 index = 0;
5433     GstClockTime seg_time = 0;
5434     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
5435
5436     /* aligning reference stream again might lead to backing up to yet another
5437      * keyframe (due to timestamp rounding issues),
5438      * potentially putting more load on downstream; so let's try to avoid */
5439     if (str == ref_str) {
5440       seg_idx = ref_seg_idx;
5441       seg = &str->segments[seg_idx];
5442       k_index = ref_k_index;
5443       GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
5444           "sample at index %d", str->track_id, ref_str->segment_index, k_index);
5445     } else {
5446       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
5447       GST_DEBUG_OBJECT (qtdemux,
5448           "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
5449           str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
5450
5451       /* get segment and time in the segment */
5452       seg = &str->segments[seg_idx];
5453       seg_time = k_pos - seg->time;
5454
5455       /* get the media time in the segment.
5456        * No adjustment for empty "filler" segments */
5457       if (seg->media_start != GST_CLOCK_TIME_NONE)
5458         seg_time += seg->media_start;
5459
5460       /* get the index of the sample with media time */
5461       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
5462       GST_DEBUG_OBJECT (qtdemux,
5463           "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
5464           GST_TIME_ARGS (seg_time), index);
5465
5466       /* find previous keyframe */
5467       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
5468     }
5469
5470     /* Remember until where we want to go */
5471     str->to_sample = str->from_sample - 1;
5472     /* Define our time position */
5473     target_ts =
5474         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
5475     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
5476     if (seg->media_start != GST_CLOCK_TIME_NONE)
5477       str->time_position -= seg->media_start;
5478
5479     /* Now seek back in time */
5480     gst_qtdemux_move_stream (qtdemux, str, k_index);
5481     GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
5482         GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
5483         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
5484   }
5485
5486   return GST_FLOW_OK;
5487
5488 eos:
5489   return GST_FLOW_EOS;
5490 }
5491
5492 /*
5493  * Gets the current qt segment start, stop and position for the
5494  * given time offset. This is used in update_segment()
5495  */
5496 static void
5497 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5498     QtDemuxStream * stream, GstClockTime offset,
5499     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5500 {
5501   GstClockTime seg_time;
5502   GstClockTime start, stop, time;
5503   QtDemuxSegment *segment;
5504
5505   segment = &stream->segments[stream->segment_index];
5506
5507   /* get time in this segment */
5508   seg_time = (offset - segment->time) * segment->rate;
5509
5510   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5511       GST_TIME_ARGS (seg_time));
5512
5513   if (G_UNLIKELY (seg_time > segment->duration)) {
5514     GST_LOG_OBJECT (stream->pad,
5515         "seg_time > segment->duration %" GST_TIME_FORMAT,
5516         GST_TIME_ARGS (segment->duration));
5517     seg_time = segment->duration;
5518   }
5519
5520   /* qtdemux->segment.stop is in outside-time-realm, whereas
5521    * segment->media_stop is in track-time-realm.
5522    *
5523    * In order to compare the two, we need to bring segment.stop
5524    * into the track-time-realm
5525    *
5526    * FIXME - does this comment still hold? Don't see any conversion here */
5527
5528   stop = qtdemux->segment.stop;
5529   if (stop == GST_CLOCK_TIME_NONE)
5530     stop = qtdemux->segment.duration;
5531   if (stop == GST_CLOCK_TIME_NONE)
5532     stop = segment->media_stop;
5533   else
5534     stop =
5535         MIN (segment->media_stop, stop - segment->time + segment->media_start);
5536
5537   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5538     start = segment->time + seg_time;
5539     time = offset;
5540     stop = start - seg_time + segment->duration;
5541   } else if (qtdemux->segment.rate >= 0) {
5542     start = MIN (segment->media_start + seg_time, stop);
5543     time = offset;
5544   } else {
5545     if (segment->media_start >= qtdemux->segment.start) {
5546       time = segment->time;
5547     } else {
5548       time = segment->time + (qtdemux->segment.start - segment->media_start);
5549     }
5550
5551     start = MAX (segment->media_start, qtdemux->segment.start);
5552     stop = MIN (segment->media_start + seg_time, stop);
5553   }
5554
5555   *_start = start;
5556   *_stop = stop;
5557   *_time = time;
5558 }
5559
5560 /*
5561  * Updates the qt segment used for the stream and pushes a new segment event
5562  * downstream on this stream's pad.
5563  */
5564 static gboolean
5565 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5566     gint seg_idx, GstClockTime offset, GstClockTime * _start,
5567     GstClockTime * _stop)
5568 {
5569   QtDemuxSegment *segment;
5570   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5571   gdouble rate;
5572   GstEvent *event;
5573
5574   /* update the current segment */
5575   stream->segment_index = seg_idx;
5576
5577   /* get the segment */
5578   segment = &stream->segments[seg_idx];
5579
5580   if (G_UNLIKELY (offset < segment->time)) {
5581     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5582         GST_TIME_ARGS (segment->time));
5583     return FALSE;
5584   }
5585
5586   /* segment lies beyond total indicated duration */
5587   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5588           segment->time > qtdemux->segment.duration)) {
5589     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5590         " < segment->time %" GST_TIME_FORMAT,
5591         GST_TIME_ARGS (qtdemux->segment.duration),
5592         GST_TIME_ARGS (segment->time));
5593     return FALSE;
5594   }
5595
5596   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5597       &start, &stop, &time);
5598
5599   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5600       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5601       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5602
5603   /* combine global rate with that of the segment */
5604   rate = segment->rate * qtdemux->segment.rate;
5605
5606   /* Copy flags from main segment */
5607   stream->segment.flags = qtdemux->segment.flags;
5608
5609   /* update the segment values used for clipping */
5610   stream->segment.offset = qtdemux->segment.offset;
5611   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5612   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5613   stream->segment.rate = rate;
5614   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5615       stream->cslg_shift);
5616   stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5617       stream->cslg_shift);
5618   stream->segment.time = time;
5619   stream->segment.position = stream->segment.start;
5620
5621   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5622       &stream->segment);
5623
5624   /* now prepare and send the segment */
5625   if (stream->pad) {
5626     event = gst_event_new_segment (&stream->segment);
5627     if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5628       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5629     }
5630     gst_pad_push_event (stream->pad, event);
5631     /* assume we can send more data now */
5632     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5633     /* clear to send tags on this pad now */
5634     gst_qtdemux_push_tags (qtdemux, stream);
5635   }
5636
5637   if (_start)
5638     *_start = start;
5639   if (_stop)
5640     *_stop = stop;
5641
5642   return TRUE;
5643 }
5644
5645 /* activate the given segment number @seg_idx of @stream at time @offset.
5646  * @offset is an absolute global position over all the segments.
5647  *
5648  * This will push out a NEWSEGMENT event with the right values and
5649  * position the stream index to the first decodable sample before
5650  * @offset.
5651  */
5652 static gboolean
5653 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5654     guint32 seg_idx, GstClockTime offset)
5655 {
5656   QtDemuxSegment *segment;
5657   guint32 index, kf_index;
5658   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5659
5660   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5661       seg_idx, GST_TIME_ARGS (offset));
5662
5663   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5664           &start, &stop))
5665     return FALSE;
5666
5667   segment = &stream->segments[stream->segment_index];
5668
5669   /* in the fragmented case, we pick a fragment that starts before our
5670    * desired position and rely on downstream to wait for a keyframe
5671    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5672    * tfra entries tells us which trun/sample the key unit is in, but we don't
5673    * make use of this additional information at the moment) */
5674   if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5675     stream->to_sample = G_MAXUINT32;
5676     return TRUE;
5677   } else {
5678     /* well, it will be taken care of below */
5679     qtdemux->fragmented_seek_pending = FALSE;
5680     /* FIXME ideally the do_fragmented_seek can be done right here,
5681      * rather than at loop level
5682      * (which might even allow handling edit lists in a fragmented file) */
5683   }
5684
5685   /* We don't need to look for a sample in push-based */
5686   if (!qtdemux->pullbased)
5687     return TRUE;
5688
5689   /* and move to the keyframe before the indicated media time of the
5690    * segment */
5691   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5692     if (qtdemux->segment.rate >= 0) {
5693       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5694       stream->to_sample = G_MAXUINT32;
5695       GST_DEBUG_OBJECT (stream->pad,
5696           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5697           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5698           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5699     } else {
5700       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5701       stream->to_sample = index;
5702       GST_DEBUG_OBJECT (stream->pad,
5703           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5704           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5705           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5706     }
5707   } else {
5708     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5709         "this is an empty segment");
5710     return TRUE;
5711   }
5712
5713   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5714    * encountered an error and printed a message so we return appropriately */
5715   if (index == -1)
5716     return FALSE;
5717
5718   /* we're at the right spot */
5719   if (index == stream->sample_index) {
5720     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5721     return TRUE;
5722   }
5723
5724   /* find keyframe of the target index */
5725   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5726
5727 /* *INDENT-OFF* */
5728 /* indent does stupid stuff with stream->samples[].timestamp */
5729
5730   /* if we move forwards, we don't have to go back to the previous
5731    * keyframe since we already sent that. We can also just jump to
5732    * the keyframe right before the target index if there is one. */
5733   if (index > stream->sample_index) {
5734     /* moving forwards check if we move past a keyframe */
5735     if (kf_index > stream->sample_index) {
5736       GST_DEBUG_OBJECT (stream->pad,
5737            "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5738            GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5739            GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5740       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5741     } else {
5742       GST_DEBUG_OBJECT (stream->pad,
5743           "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5744           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5745           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5746     }
5747   } else {
5748     GST_DEBUG_OBJECT (stream->pad,
5749         "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5750         GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5751         GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5752     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5753   }
5754
5755 /* *INDENT-ON* */
5756
5757   return TRUE;
5758 }
5759
5760 /* prepare to get the current sample of @stream, getting essential values.
5761  *
5762  * This function will also prepare and send the segment when needed.
5763  *
5764  * Return FALSE if the stream is EOS.
5765  *
5766  * PULL-BASED
5767  */
5768 static gboolean
5769 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5770     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5771     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5772     gboolean * keyframe)
5773 {
5774   QtDemuxSample *sample;
5775   GstClockTime time_position;
5776   guint32 seg_idx;
5777
5778   g_return_val_if_fail (stream != NULL, FALSE);
5779
5780   time_position = stream->time_position;
5781   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5782     goto eos;
5783
5784   seg_idx = stream->segment_index;
5785   if (G_UNLIKELY (seg_idx == -1)) {
5786     /* find segment corresponding to time_position if we are looking
5787      * for a segment. */
5788     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5789   }
5790
5791   /* different segment, activate it, sample_index will be set. */
5792   if (G_UNLIKELY (stream->segment_index != seg_idx))
5793     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5794
5795   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5796               segments[stream->segment_index]))) {
5797     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5798
5799     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5800         " prepare empty sample");
5801
5802     *empty = TRUE;
5803     *pts = *dts = time_position;
5804     *duration = seg->duration - (time_position - seg->time);
5805
5806     return TRUE;
5807   }
5808
5809   *empty = FALSE;
5810
5811   if (stream->sample_index == -1)
5812     stream->sample_index = 0;
5813
5814   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5815       stream->sample_index, stream->n_samples);
5816
5817   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5818     if (!qtdemux->fragmented)
5819       goto eos;
5820
5821     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5822     do {
5823       GstFlowReturn flow;
5824
5825       GST_OBJECT_LOCK (qtdemux);
5826       flow = qtdemux_add_fragmented_samples (qtdemux);
5827       GST_OBJECT_UNLOCK (qtdemux);
5828
5829       if (flow != GST_FLOW_OK)
5830         goto eos;
5831     }
5832     while (stream->sample_index >= stream->n_samples);
5833   }
5834
5835   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5836     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5837         stream->sample_index);
5838     return FALSE;
5839   }
5840
5841   /* now get the info for the sample we're at */
5842   sample = &stream->samples[stream->sample_index];
5843
5844   *dts = QTSAMPLE_DTS (stream, sample);
5845   *pts = QTSAMPLE_PTS (stream, sample);
5846   *offset = sample->offset;
5847   *size = sample->size;
5848   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5849   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5850
5851   return TRUE;
5852
5853   /* special cases */
5854 eos:
5855   {
5856     stream->time_position = GST_CLOCK_TIME_NONE;
5857     return FALSE;
5858   }
5859 }
5860
5861 /* move to the next sample in @stream.
5862  *
5863  * Moves to the next segment when needed.
5864  */
5865 static void
5866 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5867 {
5868   QtDemuxSample *sample;
5869   QtDemuxSegment *segment;
5870
5871   /* get current segment */
5872   segment = &stream->segments[stream->segment_index];
5873
5874   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5875     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5876     goto next_segment;
5877   }
5878
5879   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5880     /* Mark the stream as EOS */
5881     GST_DEBUG_OBJECT (qtdemux,
5882         "reached max allowed sample %u, mark EOS", stream->to_sample);
5883     stream->time_position = GST_CLOCK_TIME_NONE;
5884     return;
5885   }
5886
5887   /* move to next sample */
5888   stream->sample_index++;
5889   stream->offset_in_sample = 0;
5890
5891   /* reached the last sample, we need the next segment */
5892   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5893     goto next_segment;
5894
5895   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5896     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5897         stream->sample_index);
5898     return;
5899   }
5900
5901   /* get next sample */
5902   sample = &stream->samples[stream->sample_index];
5903
5904   /* see if we are past the segment */
5905   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5906     goto next_segment;
5907
5908   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5909     /* inside the segment, update time_position, looks very familiar to
5910      * GStreamer segments, doesn't it? */
5911     stream->time_position =
5912         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5913   } else {
5914     /* not yet in segment, time does not yet increment. This means
5915      * that we are still prerolling keyframes to the decoder so it can
5916      * decode the first sample of the segment. */
5917     stream->time_position = segment->time;
5918   }
5919   return;
5920
5921   /* move to the next segment */
5922 next_segment:
5923   {
5924     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5925
5926     if (stream->segment_index == stream->n_segments - 1) {
5927       /* are we at the end of the last segment, we're EOS */
5928       stream->time_position = GST_CLOCK_TIME_NONE;
5929     } else {
5930       /* else we're only at the end of the current segment */
5931       stream->time_position = segment->stop_time;
5932     }
5933     /* make sure we select a new segment */
5934
5935     /* accumulate previous segments */
5936     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5937       stream->accumulated_base +=
5938           (stream->segment.stop -
5939           stream->segment.start) / ABS (stream->segment.rate);
5940
5941     stream->segment_index = -1;
5942   }
5943 }
5944
5945 static void
5946 gst_qtdemux_sync_streams (GstQTDemux * demux)
5947 {
5948   gint i;
5949
5950   if (QTDEMUX_N_STREAMS (demux) <= 1)
5951     return;
5952
5953   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5954     QtDemuxStream *stream;
5955     GstClockTime end_time;
5956
5957     stream = QTDEMUX_NTH_STREAM (demux, i);
5958
5959     if (!stream->pad)
5960       continue;
5961
5962     /* TODO advance time on subtitle streams here, if any some day */
5963
5964     /* some clips/trailers may have unbalanced streams at the end,
5965      * so send EOS on shorter stream to prevent stalling others */
5966
5967     /* do not mess with EOS if SEGMENT seeking */
5968     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5969       continue;
5970
5971     if (demux->pullbased) {
5972       /* loop mode is sample time based */
5973       if (!STREAM_IS_EOS (stream))
5974         continue;
5975     } else {
5976       /* push mode is byte position based */
5977       if (stream->n_samples &&
5978           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5979         continue;
5980     }
5981
5982     if (stream->sent_eos)
5983       continue;
5984
5985     /* only act if some gap */
5986     end_time = stream->segments[stream->n_segments - 1].stop_time;
5987     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5988         ", stream end: %" GST_TIME_FORMAT,
5989         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5990     if (GST_CLOCK_TIME_IS_VALID (end_time)
5991         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5992       GstEvent *event;
5993
5994       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5995           GST_PAD_NAME (stream->pad));
5996       stream->sent_eos = TRUE;
5997       event = gst_event_new_eos ();
5998       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
5999         gst_event_set_seqnum (event, demux->segment_seqnum);
6000       gst_pad_push_event (stream->pad, event);
6001     }
6002   }
6003 }
6004
6005 /* EOS and NOT_LINKED need to be combined. This means that we return:
6006  *
6007  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
6008  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
6009  */
6010 static GstFlowReturn
6011 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
6012     GstFlowReturn ret)
6013 {
6014   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
6015
6016   if (stream->pad)
6017     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
6018         ret);
6019   else
6020     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
6021
6022   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
6023   return ret;
6024 }
6025
6026 /* the input buffer metadata must be writable. Returns NULL when the buffer is
6027  * completely clipped
6028  *
6029  * Should be used only with raw buffers */
6030 static GstBuffer *
6031 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6032     GstBuffer * buf)
6033 {
6034   guint64 start, stop, cstart, cstop, diff;
6035   GstClockTime pts, duration;
6036   gsize size, osize;
6037   gint num_rate, denom_rate;
6038   gint frame_size;
6039   gboolean clip_data;
6040   guint offset;
6041
6042   osize = size = gst_buffer_get_size (buf);
6043   offset = 0;
6044
6045   /* depending on the type, setup the clip parameters */
6046   if (stream->subtype == FOURCC_soun) {
6047     frame_size = CUR_STREAM (stream)->bytes_per_frame;
6048     num_rate = GST_SECOND;
6049     denom_rate = (gint) CUR_STREAM (stream)->rate;
6050     clip_data = TRUE;
6051   } else if (stream->subtype == FOURCC_vide) {
6052     frame_size = size;
6053     num_rate = CUR_STREAM (stream)->fps_n;
6054     denom_rate = CUR_STREAM (stream)->fps_d;
6055     clip_data = FALSE;
6056   } else
6057     goto wrong_type;
6058
6059   if (frame_size <= 0)
6060     goto bad_frame_size;
6061
6062   /* we can only clip if we have a valid pts */
6063   pts = GST_BUFFER_PTS (buf);
6064   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
6065     goto no_pts;
6066
6067   duration = GST_BUFFER_DURATION (buf);
6068
6069   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
6070     duration =
6071         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
6072   }
6073
6074   start = pts;
6075   stop = start + duration;
6076
6077   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
6078               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
6079     goto clipped;
6080
6081   /* see if some clipping happened */
6082   diff = cstart - start;
6083   if (diff > 0) {
6084     pts += diff;
6085     duration -= diff;
6086
6087     if (clip_data) {
6088       /* bring clipped time to samples and to bytes */
6089       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
6090       diff *= frame_size;
6091
6092       GST_DEBUG_OBJECT (qtdemux,
6093           "clipping start to %" GST_TIME_FORMAT " %"
6094           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
6095
6096       offset = diff;
6097       size -= diff;
6098     }
6099   }
6100   diff = stop - cstop;
6101   if (diff > 0) {
6102     duration -= diff;
6103
6104     if (clip_data) {
6105       /* bring clipped time to samples and then to bytes */
6106       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
6107       diff *= frame_size;
6108       GST_DEBUG_OBJECT (qtdemux,
6109           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
6110           " bytes", GST_TIME_ARGS (cstop), diff);
6111       size -= diff;
6112     }
6113   }
6114
6115   if (offset != 0 || size != osize)
6116     gst_buffer_resize (buf, offset, size);
6117
6118   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
6119   GST_BUFFER_PTS (buf) = pts;
6120   GST_BUFFER_DURATION (buf) = duration;
6121
6122   return buf;
6123
6124   /* dropped buffer */
6125 wrong_type:
6126   {
6127     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6128     return buf;
6129   }
6130 bad_frame_size:
6131   {
6132     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
6133     return buf;
6134   }
6135 no_pts:
6136   {
6137     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
6138     return buf;
6139   }
6140 clipped:
6141   {
6142     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
6143     gst_buffer_unref (buf);
6144     return NULL;
6145   }
6146 }
6147
6148 static GstBuffer *
6149 gst_qtdemux_align_buffer (GstQTDemux * demux,
6150     GstBuffer * buffer, gsize alignment)
6151 {
6152   GstMapInfo map;
6153
6154   gst_buffer_map (buffer, &map, GST_MAP_READ);
6155
6156   if (map.size < sizeof (guintptr)) {
6157     gst_buffer_unmap (buffer, &map);
6158     return buffer;
6159   }
6160
6161   if (((guintptr) map.data) & (alignment - 1)) {
6162     GstBuffer *new_buffer;
6163     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
6164
6165     new_buffer = gst_buffer_new_allocate (NULL,
6166         gst_buffer_get_size (buffer), &params);
6167
6168     /* Copy data "by hand", so ensure alignment is kept: */
6169     gst_buffer_fill (new_buffer, 0, map.data, map.size);
6170
6171     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
6172     GST_DEBUG_OBJECT (demux,
6173         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
6174         alignment);
6175
6176     gst_buffer_unmap (buffer, &map);
6177     gst_buffer_unref (buffer);
6178
6179     return new_buffer;
6180   }
6181
6182   gst_buffer_unmap (buffer, &map);
6183   return buffer;
6184 }
6185
6186 static guint8 *
6187 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
6188     gsize * res)
6189 {
6190   guint8 *storage;
6191   gsize i;
6192
6193   /* We are converting from pairs to triplets */
6194   *res = ccpair_size / 2 * 3;
6195   storage = g_malloc (*res);
6196   for (i = 0; i * 2 < ccpair_size; i += 1) {
6197     /* FIXME: Use line offset 0 as we simply can't know here */
6198     if (field == 1)
6199       storage[i * 3] = 0x80 | 0x00;
6200     else
6201       storage[i * 3] = 0x00 | 0x00;
6202     storage[i * 3 + 1] = ccpair[i * 2];
6203     storage[i * 3 + 2] = ccpair[i * 2 + 1];
6204   }
6205
6206   return storage;
6207 }
6208
6209 static guint8 *
6210 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
6211     gsize * cclen)
6212 {
6213   guint8 *res = NULL;
6214   guint32 atom_length, fourcc;
6215   QtDemuxStreamStsdEntry *stsd_entry;
6216
6217   GST_MEMDUMP ("caption atom", data, size);
6218
6219   /* There might be multiple atoms */
6220
6221   *cclen = 0;
6222   if (size < 8)
6223     goto invalid_cdat;
6224   atom_length = QT_UINT32 (data);
6225   fourcc = QT_FOURCC (data + 4);
6226   if (G_UNLIKELY (atom_length > size || atom_length == 8))
6227     goto invalid_cdat;
6228
6229   GST_DEBUG_OBJECT (stream->pad, "here");
6230
6231   /* Check if we have somethig compatible */
6232   stsd_entry = CUR_STREAM (stream);
6233   switch (stsd_entry->fourcc) {
6234     case FOURCC_c608:{
6235       guint8 *cdat = NULL, *cdt2 = NULL;
6236       gsize cdat_size = 0, cdt2_size = 0;
6237       /* Should be cdat or cdt2 */
6238       if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
6239         GST_WARNING_OBJECT (stream->pad,
6240             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
6241             GST_FOURCC_ARGS (fourcc));
6242         goto invalid_cdat;
6243       }
6244
6245       /* Convert to S334-1 Annex A byte triplet */
6246       if (fourcc == FOURCC_cdat)
6247         cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
6248       else
6249         cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
6250       GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
6251           size, atom_length);
6252
6253       /* Check for another atom ? */
6254       if (size > atom_length + 8) {
6255         guint32 new_atom_length = QT_UINT32 (data + atom_length);
6256         if (size >= atom_length + new_atom_length) {
6257           fourcc = QT_FOURCC (data + atom_length + 4);
6258           if (fourcc == FOURCC_cdat) {
6259             if (cdat == NULL)
6260               cdat =
6261                   convert_to_s334_1a (data + atom_length + 8,
6262                   new_atom_length - 8, 1, &cdat_size);
6263             else
6264               GST_WARNING_OBJECT (stream->pad,
6265                   "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
6266           } else {
6267             if (cdt2 == NULL)
6268               cdt2 =
6269                   convert_to_s334_1a (data + atom_length + 8,
6270                   new_atom_length - 8, 2, &cdt2_size);
6271             else
6272               GST_WARNING_OBJECT (stream->pad,
6273                   "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
6274           }
6275         }
6276       }
6277
6278       *cclen = cdat_size + cdt2_size;
6279       res = g_malloc (*cclen);
6280       if (cdat_size)
6281         memcpy (res, cdat, cdat_size);
6282       if (cdt2_size)
6283         memcpy (res + cdat_size, cdt2, cdt2_size);
6284       g_free (cdat);
6285       g_free (cdt2);
6286     }
6287       break;
6288     case FOURCC_c708:
6289       if (fourcc != FOURCC_ccdp) {
6290         GST_WARNING_OBJECT (stream->pad,
6291             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
6292             GST_FOURCC_ARGS (fourcc));
6293         goto invalid_cdat;
6294       }
6295       *cclen = atom_length - 8;
6296       res = g_memdup (data + 8, *cclen);
6297       break;
6298     default:
6299       /* Keep this here in case other closed caption formats are added */
6300       g_assert_not_reached ();
6301       break;
6302   }
6303
6304   GST_MEMDUMP ("Output", res, *cclen);
6305   return res;
6306
6307   /* Errors */
6308 invalid_cdat:
6309   GST_WARNING ("[cdat] atom is too small or invalid");
6310   return NULL;
6311 }
6312
6313 /* the input buffer metadata must be writable,
6314  * but time/duration etc not yet set and need not be preserved */
6315 static GstBuffer *
6316 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6317     GstBuffer * buf)
6318 {
6319   GstMapInfo map;
6320   guint nsize = 0;
6321   gchar *str;
6322
6323   /* not many cases for now */
6324   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
6325     /* send a one time dvd clut event */
6326     if (stream->pending_event && stream->pad)
6327       gst_pad_push_event (stream->pad, stream->pending_event);
6328     stream->pending_event = NULL;
6329   }
6330
6331   if (G_UNLIKELY (stream->subtype != FOURCC_text
6332           && stream->subtype != FOURCC_sbtl &&
6333           stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
6334     return buf;
6335   }
6336
6337   gst_buffer_map (buf, &map, GST_MAP_READ);
6338
6339   /* empty buffer is sent to terminate previous subtitle */
6340   if (map.size <= 2) {
6341     gst_buffer_unmap (buf, &map);
6342     gst_buffer_unref (buf);
6343     return NULL;
6344   }
6345   if (stream->subtype == FOURCC_subp) {
6346     /* That's all the processing needed for subpictures */
6347     gst_buffer_unmap (buf, &map);
6348     return buf;
6349   }
6350
6351   if (stream->subtype == FOURCC_clcp) {
6352     guint8 *cc;
6353     gsize cclen = 0;
6354     /* For closed caption, we need to extract the information from the
6355      * [cdat],[cdt2] or [ccdp] atom */
6356     cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
6357     gst_buffer_unmap (buf, &map);
6358     gst_buffer_unref (buf);
6359     if (cc) {
6360       buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
6361     } else {
6362       /* Conversion failed or there's nothing */
6363       buf = NULL;
6364     }
6365     return buf;
6366   }
6367
6368   nsize = GST_READ_UINT16_BE (map.data);
6369   nsize = MIN (nsize, map.size - 2);
6370
6371   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
6372       nsize, map.size);
6373
6374   /* takes care of UTF-8 validation or UTF-16 recognition,
6375    * no other encoding expected */
6376   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
6377   gst_buffer_unmap (buf, &map);
6378   if (str) {
6379     gst_buffer_unref (buf);
6380     buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
6381   } else {
6382     /* this should not really happen unless the subtitle is corrupted */
6383     gst_buffer_unref (buf);
6384     buf = NULL;
6385   }
6386
6387   /* FIXME ? convert optional subsequent style info to markup */
6388
6389   return buf;
6390 }
6391
6392 static GstFlowReturn
6393 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6394     GstBuffer * buf)
6395 {
6396   GstFlowReturn ret = GST_FLOW_OK;
6397   GstClockTime pts, duration;
6398
6399   if (stream->need_clip)
6400     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6401
6402   if (G_UNLIKELY (buf == NULL))
6403     goto exit;
6404
6405   if (G_UNLIKELY (stream->discont)) {
6406     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6407     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6408     stream->discont = FALSE;
6409   } else {
6410     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6411   }
6412
6413   GST_LOG_OBJECT (qtdemux,
6414       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6415       ", duration %" GST_TIME_FORMAT " on pad %s",
6416       GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6417       GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6418       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6419
6420   if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
6421     GstStructure *crypto_info;
6422     QtDemuxCencSampleSetInfo *info =
6423         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6424     gint index;
6425     GstEvent *event;
6426
6427     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6428       GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6429           GST_PTR_FORMAT, event);
6430       gst_pad_push_event (stream->pad, event);
6431     }
6432
6433     if (info->crypto_info == NULL) {
6434       GST_DEBUG_OBJECT (qtdemux,
6435           "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6436     } else {
6437       /* The end of the crypto_info array matches our n_samples position,
6438        * so count backward from there */
6439       index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6440       if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6441         /* steal structure from array */
6442         crypto_info = g_ptr_array_index (info->crypto_info, index);
6443         g_ptr_array_index (info->crypto_info, index) = NULL;
6444         GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6445             info->crypto_info->len);
6446         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6447           GST_ERROR_OBJECT (qtdemux,
6448               "failed to attach cenc metadata to buffer");
6449       } else {
6450         GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6451             index, stream->sample_index);
6452       }
6453     }
6454   }
6455
6456   if (stream->alignment > 1)
6457     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6458
6459   pts = GST_BUFFER_PTS (buf);
6460   duration = GST_BUFFER_DURATION (buf);
6461
6462   ret = gst_pad_push (stream->pad, buf);
6463
6464   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6465     /* mark position in stream, we'll need this to know when to send GAP event */
6466     stream->segment.position = pts + duration;
6467   }
6468
6469 exit:
6470
6471   return ret;
6472 }
6473
6474 static GstFlowReturn
6475 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6476     GstBuffer * buf)
6477 {
6478   GstFlowReturn ret = GST_FLOW_OK;
6479
6480   if (stream->subtype == FOURCC_clcp
6481       && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6482     GstMapInfo map;
6483     guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6484     guint n_triplets, i;
6485     guint field1_off = 0, field2_off = 0;
6486
6487     /* We have to split CEA608 buffers so that each outgoing buffer contains
6488      * one byte pair per field according to the framerate of the video track.
6489      *
6490      * If there is only a single byte pair per field we don't have to do
6491      * anything
6492      */
6493
6494     gst_buffer_map (buf, &map, GST_MAP_READ);
6495
6496     n_triplets = map.size / 3;
6497     for (i = 0; i < n_triplets; i++) {
6498       if (map.data[3 * i] & 0x80)
6499         n_field1++;
6500       else
6501         n_field2++;
6502     }
6503
6504     g_assert (n_field1 || n_field2);
6505
6506     /* If there's more than 1 frame we have to split, otherwise we can just
6507      * pass through */
6508     if (n_field1 > 1 || n_field2 > 1) {
6509       n_output_buffers =
6510           gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6511           CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6512
6513       for (i = 0; i < n_output_buffers; i++) {
6514         GstBuffer *outbuf =
6515             gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6516         GstMapInfo outmap;
6517         guint8 *outptr;
6518
6519         gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6520         outptr = outmap.data;
6521
6522         if (n_field1) {
6523           gboolean found = FALSE;
6524
6525           while (map.data + field1_off < map.data + map.size) {
6526             if (map.data[field1_off] & 0x80) {
6527               memcpy (outptr, &map.data[field1_off], 3);
6528               field1_off += 3;
6529               found = TRUE;
6530               break;
6531             }
6532             field1_off += 3;
6533           }
6534
6535           if (!found) {
6536             const guint8 empty[] = { 0x80, 0x80, 0x80 };
6537
6538             memcpy (outptr, empty, 3);
6539           }
6540
6541           outptr += 3;
6542         }
6543
6544         if (n_field2) {
6545           gboolean found = FALSE;
6546
6547           while (map.data + field2_off < map.data + map.size) {
6548             if ((map.data[field2_off] & 0x80) == 0) {
6549               memcpy (outptr, &map.data[field2_off], 3);
6550               field2_off += 3;
6551               found = TRUE;
6552               break;
6553             }
6554             field2_off += 3;
6555           }
6556
6557           if (!found) {
6558             const guint8 empty[] = { 0x00, 0x80, 0x80 };
6559
6560             memcpy (outptr, empty, 3);
6561           }
6562
6563           outptr += 3;
6564         }
6565
6566         gst_buffer_unmap (outbuf, &outmap);
6567
6568         GST_BUFFER_PTS (outbuf) =
6569             GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6570             GST_SECOND * CUR_STREAM (stream)->fps_d,
6571             CUR_STREAM (stream)->fps_n);
6572         GST_BUFFER_DURATION (outbuf) =
6573             gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6574             CUR_STREAM (stream)->fps_n);
6575         GST_BUFFER_OFFSET (outbuf) = -1;
6576         GST_BUFFER_OFFSET_END (outbuf) = -1;
6577
6578         ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6579
6580         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6581           break;
6582       }
6583       gst_buffer_unmap (buf, &map);
6584       gst_buffer_unref (buf);
6585     } else {
6586       gst_buffer_unmap (buf, &map);
6587       ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6588     }
6589   } else {
6590     ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6591   }
6592
6593   return ret;
6594 }
6595
6596 /* Sets a buffer's attributes properly and pushes it downstream.
6597  * Also checks for additional actions and custom processing that may
6598  * need to be done first.
6599  */
6600 static GstFlowReturn
6601 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6602     QtDemuxStream * stream, GstBuffer * buf,
6603     GstClockTime dts, GstClockTime pts, GstClockTime duration,
6604     gboolean keyframe, GstClockTime position, guint64 byte_position)
6605 {
6606   GstFlowReturn ret = GST_FLOW_OK;
6607
6608   /* offset the timestamps according to the edit list */
6609
6610   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6611     gchar *url;
6612     GstMapInfo map;
6613
6614     gst_buffer_map (buf, &map, GST_MAP_READ);
6615     url = g_strndup ((gchar *) map.data, map.size);
6616     gst_buffer_unmap (buf, &map);
6617     if (url != NULL && strlen (url) != 0) {
6618       /* we have RTSP redirect now */
6619       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6620           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6621               gst_structure_new ("redirect",
6622                   "new-location", G_TYPE_STRING, url, NULL)));
6623       qtdemux->posted_redirect = TRUE;
6624     } else {
6625       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6626           "posting");
6627     }
6628     g_free (url);
6629   }
6630
6631   /* position reporting */
6632   if (qtdemux->segment.rate >= 0) {
6633     qtdemux->segment.position = position;
6634     gst_qtdemux_sync_streams (qtdemux);
6635   }
6636
6637   if (G_UNLIKELY (!stream->pad)) {
6638     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6639     gst_buffer_unref (buf);
6640     goto exit;
6641   }
6642
6643   /* send out pending buffers */
6644   while (stream->buffers) {
6645     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6646
6647     if (G_UNLIKELY (stream->discont)) {
6648       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6649       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6650       stream->discont = FALSE;
6651     } else {
6652       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6653     }
6654
6655     if (stream->alignment > 1)
6656       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6657     gst_pad_push (stream->pad, buffer);
6658
6659     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6660   }
6661
6662   /* we're going to modify the metadata */
6663   buf = gst_buffer_make_writable (buf);
6664
6665   if (G_UNLIKELY (stream->need_process))
6666     buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
6667
6668   if (!buf) {
6669     goto exit;
6670   }
6671
6672   GST_BUFFER_DTS (buf) = dts;
6673   GST_BUFFER_PTS (buf) = pts;
6674   GST_BUFFER_DURATION (buf) = duration;
6675   GST_BUFFER_OFFSET (buf) = -1;
6676   GST_BUFFER_OFFSET_END (buf) = -1;
6677
6678   if (!keyframe) {
6679     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6680     stream->on_keyframe = FALSE;
6681   } else {
6682     stream->on_keyframe = TRUE;
6683   }
6684
6685   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6686     gst_buffer_append_memory (buf,
6687         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6688
6689   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6690     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6691   }
6692 #if 0
6693   if (G_UNLIKELY (qtdemux->element_index)) {
6694     GstClockTime stream_time;
6695
6696     stream_time =
6697         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6698         timestamp);
6699     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6700       GST_LOG_OBJECT (qtdemux,
6701           "adding association %" GST_TIME_FORMAT "-> %"
6702           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6703       gst_index_add_association (qtdemux->element_index,
6704           qtdemux->index_id,
6705           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6706           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6707           GST_FORMAT_BYTES, byte_position, NULL);
6708     }
6709   }
6710 #endif
6711
6712   ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6713
6714 exit:
6715   return ret;
6716 }
6717
6718 static const QtDemuxRandomAccessEntry *
6719 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6720     GstClockTime pos, gboolean after)
6721 {
6722   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6723   guint n_entries = stream->n_ra_entries;
6724   guint i;
6725
6726   /* we assume the table is sorted */
6727   for (i = 0; i < n_entries; ++i) {
6728     if (entries[i].ts > pos)
6729       break;
6730   }
6731
6732   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6733    * probably okay to assume that the index lists the very first fragment */
6734   if (i == 0)
6735     return &entries[0];
6736
6737   if (after)
6738     return &entries[i];
6739   else
6740     return &entries[i - 1];
6741 }
6742
6743 static gboolean
6744 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6745 {
6746   const QtDemuxRandomAccessEntry *best_entry = NULL;
6747   gint i;
6748
6749   GST_OBJECT_LOCK (qtdemux);
6750
6751   g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6752
6753   /* first see if we can determine where to go to using mfra,
6754    * before we start clearing things */
6755   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6756     const QtDemuxRandomAccessEntry *entry;
6757     QtDemuxStream *stream;
6758     gboolean is_audio_or_video;
6759
6760     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6761
6762     if (stream->ra_entries == NULL)
6763       continue;
6764
6765     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6766       is_audio_or_video = TRUE;
6767     else
6768       is_audio_or_video = FALSE;
6769
6770     entry =
6771         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6772         stream->time_position, !is_audio_or_video);
6773
6774     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6775         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6776
6777     stream->pending_seek = entry;
6778
6779     /* decide position to jump to just based on audio/video tracks, not subs */
6780     if (!is_audio_or_video)
6781       continue;
6782
6783     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6784       best_entry = entry;
6785   }
6786
6787   /* no luck, will handle seek otherwise */
6788   if (best_entry == NULL) {
6789     GST_OBJECT_UNLOCK (qtdemux);
6790     return FALSE;
6791   }
6792
6793   /* ok, now we can prepare for processing as of located moof */
6794   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6795     QtDemuxStream *stream;
6796
6797     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6798
6799     g_free (stream->samples);
6800     stream->samples = NULL;
6801     stream->n_samples = 0;
6802     stream->stbl_index = -1;    /* no samples have yet been parsed */
6803     stream->sample_index = -1;
6804
6805     if (stream->protection_scheme_info) {
6806       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6807       if (stream->protection_scheme_type == FOURCC_cenc) {
6808         QtDemuxCencSampleSetInfo *info =
6809             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6810         if (info->crypto_info) {
6811           g_ptr_array_free (info->crypto_info, TRUE);
6812           info->crypto_info = NULL;
6813         }
6814       }
6815     }
6816   }
6817
6818   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6819       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6820       GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6821       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6822
6823   qtdemux->moof_offset = best_entry->moof_offset;
6824
6825   qtdemux_add_fragmented_samples (qtdemux);
6826
6827   GST_OBJECT_UNLOCK (qtdemux);
6828   return TRUE;
6829 }
6830
6831 static GstFlowReturn
6832 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6833 {
6834   GstFlowReturn ret = GST_FLOW_OK;
6835   GstBuffer *buf = NULL;
6836   QtDemuxStream *stream, *target_stream = NULL;
6837   GstClockTime min_time;
6838   guint64 offset = 0;
6839   GstClockTime dts = GST_CLOCK_TIME_NONE;
6840   GstClockTime pts = GST_CLOCK_TIME_NONE;
6841   GstClockTime duration = 0;
6842   gboolean keyframe = FALSE;
6843   guint sample_size = 0;
6844   gboolean empty = 0;
6845   guint size;
6846   gint i;
6847
6848   if (qtdemux->fragmented_seek_pending) {
6849     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6850     if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6851       GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6852       qtdemux->fragmented_seek_pending = FALSE;
6853     } else {
6854       GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6855     }
6856   }
6857
6858   /* Figure out the next stream sample to output, min_time is expressed in
6859    * global time and runs over the edit list segments. */
6860   min_time = G_MAXUINT64;
6861   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6862     GstClockTime position;
6863
6864     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6865     position = stream->time_position;
6866
6867     /* position of -1 is EOS */
6868     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6869       min_time = position;
6870       target_stream = stream;
6871     }
6872   }
6873   /* all are EOS */
6874   if (G_UNLIKELY (target_stream == NULL)) {
6875     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6876     goto eos;
6877   }
6878
6879   /* check for segment end */
6880   if (G_UNLIKELY (qtdemux->segment.stop != -1
6881           && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6882               || (qtdemux->segment.rate < 0
6883                   && qtdemux->segment.start > min_time))
6884           && target_stream->on_keyframe)) {
6885     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6886     target_stream->time_position = GST_CLOCK_TIME_NONE;
6887     goto eos_stream;
6888   }
6889
6890   /* gap events for subtitle streams */
6891   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6892     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6893     if (stream->pad && (stream->subtype == FOURCC_subp
6894             || stream->subtype == FOURCC_text
6895             || stream->subtype == FOURCC_sbtl)) {
6896       /* send one second gap events until the stream catches up */
6897       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6898       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6899           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6900           stream->segment.position + GST_SECOND < min_time) {
6901         GstEvent *gap =
6902             gst_event_new_gap (stream->segment.position, GST_SECOND);
6903         gst_pad_push_event (stream->pad, gap);
6904         stream->segment.position += GST_SECOND;
6905       }
6906     }
6907   }
6908
6909   stream = target_stream;
6910   /* fetch info for the current sample of this stream */
6911   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6912               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6913     goto eos_stream;
6914
6915   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6916   if (stream->new_caps) {
6917     gst_qtdemux_configure_stream (qtdemux, stream);
6918     qtdemux_do_allocation (stream, qtdemux);
6919   }
6920
6921   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6922   if (G_UNLIKELY (qtdemux->segment.
6923           flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6924     if (stream->subtype == FOURCC_vide && !keyframe) {
6925       GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6926           stream->track_id);
6927       goto next;
6928     }
6929   }
6930
6931   GST_DEBUG_OBJECT (qtdemux,
6932       "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6933       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6934       ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6935       sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6936       GST_TIME_ARGS (duration));
6937
6938   if (G_UNLIKELY (empty)) {
6939     /* empty segment, push a gap if there's a second or more
6940      * difference and move to the next one */
6941     if ((pts + duration - stream->segment.position) >= GST_SECOND)
6942       gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6943     stream->segment.position = pts + duration;
6944     goto next;
6945   }
6946
6947   /* hmm, empty sample, skip and move to next sample */
6948   if (G_UNLIKELY (sample_size <= 0))
6949     goto next;
6950
6951   /* last pushed sample was out of boundary, goto next sample */
6952   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6953     goto next;
6954
6955   if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6956     size = sample_size;
6957   } else {
6958     GST_DEBUG_OBJECT (qtdemux,
6959         "size %d larger than stream max_buffer_size %d, trimming",
6960         sample_size, stream->max_buffer_size);
6961     size =
6962         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6963   }
6964
6965   if (qtdemux->cenc_aux_info_offset > 0) {
6966     GstMapInfo map;
6967     GstByteReader br;
6968     GstBuffer *aux_info = NULL;
6969
6970     /* pull the data stored before the sample */
6971     ret =
6972         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6973         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6974     if (G_UNLIKELY (ret != GST_FLOW_OK))
6975       goto beach;
6976     gst_buffer_map (aux_info, &map, GST_MAP_READ);
6977     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6978     gst_byte_reader_init (&br, map.data + 8, map.size);
6979     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6980             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6981       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6982       gst_buffer_unmap (aux_info, &map);
6983       gst_buffer_unref (aux_info);
6984       ret = GST_FLOW_ERROR;
6985       goto beach;
6986     }
6987     gst_buffer_unmap (aux_info, &map);
6988     gst_buffer_unref (aux_info);
6989   }
6990
6991   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6992       offset);
6993
6994   if (stream->use_allocator) {
6995     /* if we have a per-stream allocator, use it */
6996     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6997   }
6998
6999   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
7000       size, &buf);
7001   if (G_UNLIKELY (ret != GST_FLOW_OK))
7002     goto beach;
7003
7004   if (size != sample_size) {
7005     pts += gst_util_uint64_scale_int (GST_SECOND,
7006         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
7007         stream->timescale);
7008     dts +=
7009         gst_util_uint64_scale_int (GST_SECOND,
7010         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
7011         stream->timescale);
7012     duration =
7013         gst_util_uint64_scale_int (GST_SECOND,
7014         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
7015   }
7016
7017   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
7018       dts, pts, duration, keyframe, min_time, offset);
7019
7020   if (size != sample_size) {
7021     QtDemuxSample *sample = &stream->samples[stream->sample_index];
7022     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
7023
7024     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
7025         sample->timestamp +
7026         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
7027     if (time_position >= segment->media_start) {
7028       /* inside the segment, update time_position, looks very familiar to
7029        * GStreamer segments, doesn't it? */
7030       stream->time_position = (time_position - segment->media_start) +
7031           segment->time;
7032     } else {
7033       /* not yet in segment, time does not yet increment. This means
7034        * that we are still prerolling keyframes to the decoder so it can
7035        * decode the first sample of the segment. */
7036       stream->time_position = segment->time;
7037     }
7038   }
7039
7040   /* combine flows */
7041   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
7042   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
7043    * we have no more data for the pad to push */
7044   if (ret == GST_FLOW_EOS)
7045     ret = GST_FLOW_OK;
7046
7047   stream->offset_in_sample += size;
7048   if (stream->offset_in_sample >= sample_size) {
7049     gst_qtdemux_advance_sample (qtdemux, stream);
7050   }
7051   goto beach;
7052
7053 next:
7054   gst_qtdemux_advance_sample (qtdemux, stream);
7055
7056 beach:
7057   return ret;
7058
7059   /* special cases */
7060 eos:
7061   {
7062     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
7063     ret = GST_FLOW_EOS;
7064     goto beach;
7065   }
7066 eos_stream:
7067   {
7068     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
7069     /* EOS will be raised if all are EOS */
7070     ret = GST_FLOW_OK;
7071     goto beach;
7072   }
7073 }
7074
7075 static void
7076 gst_qtdemux_loop (GstPad * pad)
7077 {
7078   GstQTDemux *qtdemux;
7079   guint64 cur_offset;
7080   GstFlowReturn ret;
7081
7082   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
7083
7084   cur_offset = qtdemux->offset;
7085   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
7086       cur_offset, qt_demux_state_string (qtdemux->state));
7087
7088   switch (qtdemux->state) {
7089     case QTDEMUX_STATE_INITIAL:
7090     case QTDEMUX_STATE_HEADER:
7091       ret = gst_qtdemux_loop_state_header (qtdemux);
7092       break;
7093     case QTDEMUX_STATE_MOVIE:
7094       ret = gst_qtdemux_loop_state_movie (qtdemux);
7095       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
7096         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
7097       }
7098       break;
7099     default:
7100       /* ouch */
7101       goto invalid_state;
7102   }
7103
7104   /* if something went wrong, pause */
7105   if (ret != GST_FLOW_OK)
7106     goto pause;
7107
7108 done:
7109   gst_object_unref (qtdemux);
7110   return;
7111
7112   /* ERRORS */
7113 invalid_state:
7114   {
7115     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
7116         (NULL), ("streaming stopped, invalid state"));
7117     gst_pad_pause_task (pad);
7118     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
7119     goto done;
7120   }
7121 pause:
7122   {
7123     const gchar *reason = gst_flow_get_name (ret);
7124
7125     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
7126
7127     gst_pad_pause_task (pad);
7128
7129     /* fatal errors need special actions */
7130     /* check EOS */
7131     if (ret == GST_FLOW_EOS) {
7132       if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
7133         /* we have no streams, post an error */
7134         gst_qtdemux_post_no_playable_stream_error (qtdemux);
7135       }
7136       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
7137         gint64 stop;
7138
7139         if ((stop = qtdemux->segment.stop) == -1)
7140           stop = qtdemux->segment.duration;
7141
7142         if (qtdemux->segment.rate >= 0) {
7143           GstMessage *message;
7144           GstEvent *event;
7145
7146           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
7147           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
7148               GST_FORMAT_TIME, stop);
7149           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
7150           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
7151             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
7152             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7153           }
7154           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
7155           gst_qtdemux_push_event (qtdemux, event);
7156         } else {
7157           GstMessage *message;
7158           GstEvent *event;
7159
7160           /*  For Reverse Playback */
7161           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
7162           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
7163               GST_FORMAT_TIME, qtdemux->segment.start);
7164           event = gst_event_new_segment_done (GST_FORMAT_TIME,
7165               qtdemux->segment.start);
7166           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
7167             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
7168             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7169           }
7170           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
7171           gst_qtdemux_push_event (qtdemux, event);
7172         }
7173       } else {
7174         GstEvent *event;
7175
7176         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
7177         event = gst_event_new_eos ();
7178         if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
7179           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7180         gst_qtdemux_push_event (qtdemux, event);
7181       }
7182     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
7183       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
7184       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
7185     }
7186     goto done;
7187   }
7188 }
7189
7190 /*
7191  * has_next_entry
7192  *
7193  * Returns if there are samples to be played.
7194  */
7195 static gboolean
7196 has_next_entry (GstQTDemux * demux)
7197 {
7198   QtDemuxStream *stream;
7199   gint i;
7200
7201   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
7202
7203   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7204     stream = QTDEMUX_NTH_STREAM (demux, i);
7205
7206     if (stream->sample_index == -1) {
7207       stream->sample_index = 0;
7208       stream->offset_in_sample = 0;
7209     }
7210
7211     if (stream->sample_index >= stream->n_samples) {
7212       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7213       continue;
7214     }
7215     GST_DEBUG_OBJECT (demux, "Found a sample");
7216     return TRUE;
7217   }
7218
7219   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
7220   return FALSE;
7221 }
7222
7223 /*
7224  * next_entry_size
7225  *
7226  * Returns the size of the first entry at the current offset.
7227  * If -1, there are none (which means EOS or empty file).
7228  */
7229 static guint64
7230 next_entry_size (GstQTDemux * demux)
7231 {
7232   QtDemuxStream *stream, *target_stream = NULL;
7233   guint64 smalloffs = (guint64) - 1;
7234   QtDemuxSample *sample;
7235   gint i;
7236
7237   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
7238       demux->offset);
7239
7240   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7241     stream = QTDEMUX_NTH_STREAM (demux, i);
7242
7243     if (stream->sample_index == -1) {
7244       stream->sample_index = 0;
7245       stream->offset_in_sample = 0;
7246     }
7247
7248     if (stream->sample_index >= stream->n_samples) {
7249       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7250       continue;
7251     }
7252
7253     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7254       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7255           stream->sample_index);
7256       return -1;
7257     }
7258
7259     sample = &stream->samples[stream->sample_index];
7260
7261     GST_LOG_OBJECT (demux,
7262         "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7263         " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7264         stream->sample_index, sample->offset, sample->size);
7265
7266     if (((smalloffs == -1)
7267             || (sample->offset < smalloffs)) && (sample->size)) {
7268       smalloffs = sample->offset;
7269       target_stream = stream;
7270     }
7271   }
7272
7273   if (!target_stream)
7274     return -1;
7275
7276   GST_LOG_OBJECT (demux,
7277       "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7278       G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7279
7280   stream = target_stream;
7281   sample = &stream->samples[stream->sample_index];
7282
7283   if (sample->offset >= demux->offset) {
7284     demux->todrop = sample->offset - demux->offset;
7285     return sample->size + demux->todrop;
7286   }
7287
7288   GST_DEBUG_OBJECT (demux,
7289       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7290   return -1;
7291 }
7292
7293 static void
7294 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7295 {
7296   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7297
7298   gst_element_post_message (GST_ELEMENT_CAST (demux),
7299       gst_message_new_element (GST_OBJECT_CAST (demux),
7300           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7301 }
7302
7303 static gboolean
7304 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7305 {
7306   GstEvent *event;
7307   gboolean res = 0;
7308
7309   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7310
7311   event =
7312       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7313       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7314       GST_SEEK_TYPE_NONE, -1);
7315
7316   /* store seqnum to drop flush events, they don't need to reach downstream */
7317   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7318   res = gst_pad_push_event (demux->sinkpad, event);
7319   demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7320
7321   return res;
7322 }
7323
7324 /* check for seekable upstream, above and beyond a mere query */
7325 static void
7326 gst_qtdemux_check_seekability (GstQTDemux * demux)
7327 {
7328   GstQuery *query;
7329   gboolean seekable = FALSE;
7330   gint64 start = -1, stop = -1;
7331
7332   if (demux->upstream_size)
7333     return;
7334
7335   if (demux->upstream_format_is_time)
7336     return;
7337
7338   query = gst_query_new_seeking (GST_FORMAT_BYTES);
7339   if (!gst_pad_peer_query (demux->sinkpad, query)) {
7340     GST_DEBUG_OBJECT (demux, "seeking query failed");
7341     goto done;
7342   }
7343
7344   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7345
7346   /* try harder to query upstream size if we didn't get it the first time */
7347   if (seekable && stop == -1) {
7348     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7349     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7350   }
7351
7352   /* if upstream doesn't know the size, it's likely that it's not seekable in
7353    * practice even if it technically may be seekable */
7354   if (seekable && (start != 0 || stop <= start)) {
7355     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7356     seekable = FALSE;
7357   }
7358
7359 done:
7360   gst_query_unref (query);
7361
7362   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7363       G_GUINT64_FORMAT ")", seekable, start, stop);
7364   demux->upstream_seekable = seekable;
7365   demux->upstream_size = seekable ? stop : -1;
7366 }
7367
7368 static void
7369 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7370 {
7371   g_return_if_fail (bytes <= demux->todrop);
7372
7373   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7374   gst_adapter_flush (demux->adapter, bytes);
7375   demux->neededbytes -= bytes;
7376   demux->offset += bytes;
7377   demux->todrop -= bytes;
7378 }
7379
7380 /* PUSH-MODE only: Send a segment, if not done already. */
7381 static void
7382 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7383 {
7384   if (G_UNLIKELY (demux->need_segment)) {
7385     gint i;
7386
7387     if (!demux->upstream_format_is_time) {
7388       gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7389     } else {
7390       GstEvent *segment_event;
7391       segment_event = gst_event_new_segment (&demux->segment);
7392       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7393         gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7394       gst_qtdemux_push_event (demux, segment_event);
7395     }
7396
7397     demux->need_segment = FALSE;
7398
7399     /* clear to send tags on all streams */
7400     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7401       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7402       gst_qtdemux_push_tags (demux, stream);
7403       if (CUR_STREAM (stream)->sparse) {
7404         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7405         gst_pad_push_event (stream->pad,
7406             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7407       }
7408     }
7409   }
7410 }
7411
7412 /* Used for push mode only. */
7413 static void
7414 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7415     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7416 {
7417   GstClockTime ts, dur;
7418
7419   ts = pos;
7420   dur =
7421       stream->segments[segment_index].duration - (pos -
7422       stream->segments[segment_index].time);
7423   stream->time_position += dur;
7424
7425   /* Only gaps with a duration of at least one second are propagated.
7426    * Same workaround as in pull mode.
7427    * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7428   if (dur >= GST_SECOND) {
7429     GstEvent *gap;
7430     gap = gst_event_new_gap (ts, dur);
7431
7432     GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7433         "segment: %" GST_PTR_FORMAT, gap);
7434     gst_pad_push_event (stream->pad, gap);
7435   }
7436 }
7437
7438 static GstFlowReturn
7439 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7440 {
7441   GstQTDemux *demux;
7442
7443   demux = GST_QTDEMUX (parent);
7444
7445   GST_DEBUG_OBJECT (demux,
7446       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7447       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7448       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7449       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7450       gst_buffer_get_size (inbuf), demux->offset);
7451
7452   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7453     gboolean is_gap_input = FALSE;
7454     gint i;
7455
7456     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7457
7458     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7459       QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7460     }
7461
7462     /* Check if we can land back on our feet in the case where upstream is
7463      * handling the seeking/pushing of samples with gaps in between (like
7464      * in the case of trick-mode DASH for example) */
7465     if (demux->upstream_format_is_time
7466         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7467       for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7468         guint32 res;
7469         QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7470         GST_LOG_OBJECT (demux,
7471             "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7472             " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7473         res =
7474             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7475             stream, GST_BUFFER_OFFSET (inbuf));
7476         if (res != -1) {
7477           QtDemuxSample *sample = &stream->samples[res];
7478           GST_LOG_OBJECT (demux,
7479               "Checking if sample %d from track-id %u is valid (offset:%"
7480               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7481               stream->track_id, sample->offset, sample->size);
7482           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7483             GST_LOG_OBJECT (demux,
7484                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7485                 res);
7486             is_gap_input = TRUE;
7487             /* We can go back to standard playback mode */
7488             demux->state = QTDEMUX_STATE_MOVIE;
7489             /* Remember which sample this stream is at */
7490             stream->sample_index = res;
7491             /* Finally update all push-based values to the expected values */
7492             demux->neededbytes = stream->samples[res].size;
7493             demux->offset = GST_BUFFER_OFFSET (inbuf);
7494             demux->mdatleft =
7495                 demux->mdatsize - demux->offset + demux->mdatoffset;
7496             demux->todrop = 0;
7497           }
7498         }
7499       }
7500       if (!is_gap_input) {
7501         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7502         /* Reset state if it's a real discont */
7503         demux->neededbytes = 16;
7504         demux->state = QTDEMUX_STATE_INITIAL;
7505         demux->offset = GST_BUFFER_OFFSET (inbuf);
7506         gst_adapter_clear (demux->adapter);
7507       }
7508     }
7509     /* Reverse fragmented playback, need to flush all we have before
7510      * consuming a new fragment.
7511      * The samples array have the timestamps calculated by accumulating the
7512      * durations but this won't work for reverse playback of fragments as
7513      * the timestamps of a subsequent fragment should be smaller than the
7514      * previously received one. */
7515     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7516       gst_qtdemux_process_adapter (demux, TRUE);
7517       g_ptr_array_foreach (demux->active_streams,
7518           (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7519     }
7520   }
7521
7522   gst_adapter_push (demux->adapter, inbuf);
7523
7524   GST_DEBUG_OBJECT (demux,
7525       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7526       demux->neededbytes, gst_adapter_available (demux->adapter));
7527
7528   return gst_qtdemux_process_adapter (demux, FALSE);
7529 }
7530
7531 static GstFlowReturn
7532 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7533 {
7534   GstFlowReturn ret = GST_FLOW_OK;
7535
7536   /* we never really mean to buffer that much */
7537   if (demux->neededbytes == -1) {
7538     goto eos;
7539   }
7540
7541   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7542       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7543
7544 #ifndef GST_DISABLE_GST_DEBUG
7545     {
7546       guint64 discont_offset, distance_from_discont;
7547
7548       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7549       distance_from_discont =
7550           gst_adapter_distance_from_discont (demux->adapter);
7551
7552       GST_DEBUG_OBJECT (demux,
7553           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7554           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7555           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7556           demux->offset, discont_offset, distance_from_discont);
7557     }
7558 #endif
7559
7560     switch (demux->state) {
7561       case QTDEMUX_STATE_INITIAL:{
7562         const guint8 *data;
7563         guint32 fourcc;
7564         guint64 size;
7565
7566         gst_qtdemux_check_seekability (demux);
7567
7568         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7569
7570         /* get fourcc/length, set neededbytes */
7571         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7572             &size, &fourcc);
7573         gst_adapter_unmap (demux->adapter);
7574         data = NULL;
7575         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7576             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7577         if (size == 0) {
7578           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7579               (_("This file is invalid and cannot be played.")),
7580               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7581                   GST_FOURCC_ARGS (fourcc)));
7582           ret = GST_FLOW_ERROR;
7583           break;
7584         }
7585         if (fourcc == FOURCC_mdat) {
7586           gint next_entry = next_entry_size (demux);
7587           if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7588                   || !demux->fragmented)) {
7589             /* we have the headers, start playback */
7590             demux->state = QTDEMUX_STATE_MOVIE;
7591             demux->neededbytes = next_entry;
7592             demux->mdatleft = size;
7593             demux->mdatsize = demux->mdatleft;
7594           } else {
7595             /* no headers yet, try to get them */
7596             guint bs;
7597             gboolean res;
7598             guint64 old, target;
7599
7600           buffer_data:
7601             old = demux->offset;
7602             target = old + size;
7603
7604             /* try to jump over the atom with a seek */
7605             /* only bother if it seems worth doing so,
7606              * and avoids possible upstream/server problems */
7607             if (demux->upstream_seekable &&
7608                 demux->upstream_size > 4 * (1 << 20)) {
7609               res = qtdemux_seek_offset (demux, target);
7610             } else {
7611               GST_DEBUG_OBJECT (demux, "skipping seek");
7612               res = FALSE;
7613             }
7614
7615             if (res) {
7616               GST_DEBUG_OBJECT (demux, "seek success");
7617               /* remember the offset fo the first mdat so we can seek back to it
7618                * after we have the headers */
7619               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7620                 demux->first_mdat = old;
7621                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7622                     demux->first_mdat);
7623               }
7624               /* seek worked, continue reading */
7625               demux->offset = target;
7626               demux->neededbytes = 16;
7627               demux->state = QTDEMUX_STATE_INITIAL;
7628             } else {
7629               /* seek failed, need to buffer */
7630               demux->offset = old;
7631               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7632               /* there may be multiple mdat (or alike) buffers */
7633               /* sanity check */
7634               if (demux->mdatbuffer)
7635                 bs = gst_buffer_get_size (demux->mdatbuffer);
7636               else
7637                 bs = 0;
7638               if (size + bs > 10 * (1 << 20))
7639                 goto no_moov;
7640               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7641               demux->neededbytes = size;
7642               if (!demux->mdatbuffer)
7643                 demux->mdatoffset = demux->offset;
7644             }
7645           }
7646         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7647           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7648               (_("This file is invalid and cannot be played.")),
7649               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7650                   GST_FOURCC_ARGS (fourcc), size));
7651           ret = GST_FLOW_ERROR;
7652           break;
7653         } else {
7654           /* this means we already started buffering and still no moov header,
7655            * let's continue buffering everything till we get moov */
7656           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7657                   || fourcc == FOURCC_moof))
7658             goto buffer_data;
7659           demux->neededbytes = size;
7660           demux->state = QTDEMUX_STATE_HEADER;
7661         }
7662         break;
7663       }
7664       case QTDEMUX_STATE_HEADER:{
7665         const guint8 *data;
7666         guint32 fourcc;
7667
7668         GST_DEBUG_OBJECT (demux, "In header");
7669
7670         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7671
7672         /* parse the header */
7673         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7674             &fourcc);
7675         if (fourcc == FOURCC_moov) {
7676           /* in usual fragmented setup we could try to scan for more
7677            * and end up at the the moov (after mdat) again */
7678           if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7679               (!demux->fragmented
7680                   || demux->last_moov_offset == demux->offset)) {
7681             GST_DEBUG_OBJECT (demux,
7682                 "Skipping moov atom as we have (this) one already");
7683           } else {
7684             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7685
7686             if (demux->got_moov && demux->fragmented) {
7687               GST_DEBUG_OBJECT (demux,
7688                   "Got a second moov, clean up data from old one");
7689               if (demux->moov_node_compressed) {
7690                 g_node_destroy (demux->moov_node_compressed);
7691                 if (demux->moov_node)
7692                   g_free (demux->moov_node->data);
7693               }
7694               demux->moov_node_compressed = NULL;
7695               if (demux->moov_node)
7696                 g_node_destroy (demux->moov_node);
7697               demux->moov_node = NULL;
7698             }
7699
7700             demux->last_moov_offset = demux->offset;
7701
7702             /* Update streams with new moov */
7703             gst_qtdemux_stream_concat (demux,
7704                 demux->old_streams, demux->active_streams);
7705
7706             qtdemux_parse_moov (demux, data, demux->neededbytes);
7707             qtdemux_node_dump (demux, demux->moov_node);
7708             qtdemux_parse_tree (demux);
7709             qtdemux_prepare_streams (demux);
7710             QTDEMUX_EXPOSE_LOCK (demux);
7711             qtdemux_expose_streams (demux);
7712             QTDEMUX_EXPOSE_UNLOCK (demux);
7713
7714             demux->got_moov = TRUE;
7715
7716             gst_qtdemux_check_send_pending_segment (demux);
7717
7718             if (demux->moov_node_compressed) {
7719               g_node_destroy (demux->moov_node_compressed);
7720               g_free (demux->moov_node->data);
7721             }
7722             demux->moov_node_compressed = NULL;
7723             g_node_destroy (demux->moov_node);
7724             demux->moov_node = NULL;
7725             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7726           }
7727         } else if (fourcc == FOURCC_moof) {
7728           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7729             guint64 dist = 0;
7730             GstClockTime prev_pts;
7731             guint64 prev_offset;
7732             guint64 adapter_discont_offset, adapter_discont_dist;
7733
7734             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7735
7736             /*
7737              * The timestamp of the moof buffer is relevant as some scenarios
7738              * won't have the initial timestamp in the atoms. Whenever a new
7739              * buffer has started, we get that buffer's PTS and use it as a base
7740              * timestamp for the trun entries.
7741              *
7742              * To keep track of the current buffer timestamp and starting point
7743              * we use gst_adapter_prev_pts that gives us the PTS and the distance
7744              * from the beggining of the buffer, with the distance and demux->offset
7745              * we know if it is still the same buffer or not.
7746              */
7747             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7748             prev_offset = demux->offset - dist;
7749             if (demux->fragment_start_offset == -1
7750                 || prev_offset > demux->fragment_start_offset) {
7751               demux->fragment_start_offset = prev_offset;
7752               demux->fragment_start = prev_pts;
7753               GST_DEBUG_OBJECT (demux,
7754                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7755                   GST_TIME_FORMAT, demux->fragment_start_offset,
7756                   GST_TIME_ARGS (demux->fragment_start));
7757             }
7758
7759             /* We can't use prev_offset() here because this would require
7760              * upstream to set consistent and correct offsets on all buffers
7761              * since the discont. Nothing ever did that in the past and we
7762              * would break backwards compatibility here then.
7763              * Instead take the offset we had at the last discont and count
7764              * the bytes from there. This works with old code as there would
7765              * be no discont between moov and moof, and also works with
7766              * adaptivedemux which correctly sets offset and will set the
7767              * DISCONT flag accordingly when needed.
7768              *
7769              * We also only do this for upstream TIME segments as otherwise
7770              * there are potential backwards compatibility problems with
7771              * seeking in PUSH mode and upstream providing inconsistent
7772              * timestamps. */
7773             adapter_discont_offset =
7774                 gst_adapter_offset_at_discont (demux->adapter);
7775             adapter_discont_dist =
7776                 gst_adapter_distance_from_discont (demux->adapter);
7777
7778             GST_DEBUG_OBJECT (demux,
7779                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7780                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7781                 demux->offset, adapter_discont_offset, adapter_discont_dist);
7782
7783             if (demux->upstream_format_is_time) {
7784               demux->moof_offset = adapter_discont_offset;
7785               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7786                 demux->moof_offset += adapter_discont_dist;
7787               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7788                 demux->moof_offset = demux->offset;
7789             } else {
7790               demux->moof_offset = demux->offset;
7791             }
7792
7793             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7794                     demux->moof_offset, NULL)) {
7795               gst_adapter_unmap (demux->adapter);
7796               ret = GST_FLOW_ERROR;
7797               goto done;
7798             }
7799
7800             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7801             if (demux->mss_mode && !demux->exposed) {
7802               QTDEMUX_EXPOSE_LOCK (demux);
7803               qtdemux_expose_streams (demux);
7804               QTDEMUX_EXPOSE_UNLOCK (demux);
7805             }
7806
7807             gst_qtdemux_check_send_pending_segment (demux);
7808           } else {
7809             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7810           }
7811         } else if (fourcc == FOURCC_ftyp) {
7812           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7813           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7814         } else if (fourcc == FOURCC_uuid) {
7815           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7816           qtdemux_parse_uuid (demux, data, demux->neededbytes);
7817         } else if (fourcc == FOURCC_sidx) {
7818           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7819           qtdemux_parse_sidx (demux, data, demux->neededbytes);
7820         } else {
7821           switch (fourcc) {
7822             case FOURCC_styp:
7823               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7824                * FALLTHROUGH */
7825             case FOURCC_skip:
7826             case FOURCC_free:
7827               /* [free] and [skip] are padding atoms */
7828               GST_DEBUG_OBJECT (demux,
7829                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7830                   GST_FOURCC_ARGS (fourcc));
7831               break;
7832             default:
7833               GST_WARNING_OBJECT (demux,
7834                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7835                   GST_FOURCC_ARGS (fourcc));
7836               /* Let's jump that one and go back to initial state */
7837               break;
7838           }
7839         }
7840         gst_adapter_unmap (demux->adapter);
7841         data = NULL;
7842
7843         if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7844           gsize remaining_data_size = 0;
7845
7846           /* the mdat was before the header */
7847           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7848               QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7849           /* restore our adapter/offset view of things with upstream;
7850            * put preceding buffered data ahead of current moov data.
7851            * This should also handle evil mdat, moov, mdat cases and alike */
7852           gst_adapter_flush (demux->adapter, demux->neededbytes);
7853
7854           /* Store any remaining data after the mdat for later usage */
7855           remaining_data_size = gst_adapter_available (demux->adapter);
7856           if (remaining_data_size > 0) {
7857             g_assert (demux->restoredata_buffer == NULL);
7858             demux->restoredata_buffer =
7859                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7860             demux->restoredata_offset = demux->offset + demux->neededbytes;
7861             GST_DEBUG_OBJECT (demux,
7862                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7863                 G_GUINT64_FORMAT, remaining_data_size,
7864                 demux->restoredata_offset);
7865           }
7866
7867           gst_adapter_push (demux->adapter, demux->mdatbuffer);
7868           demux->mdatbuffer = NULL;
7869           demux->offset = demux->mdatoffset;
7870           demux->neededbytes = next_entry_size (demux);
7871           demux->state = QTDEMUX_STATE_MOVIE;
7872           demux->mdatleft = gst_adapter_available (demux->adapter);
7873           demux->mdatsize = demux->mdatleft;
7874         } else {
7875           GST_DEBUG_OBJECT (demux, "Carrying on normally");
7876           gst_adapter_flush (demux->adapter, demux->neededbytes);
7877
7878           /* only go back to the mdat if there are samples to play */
7879           if (demux->got_moov && demux->first_mdat != -1
7880               && has_next_entry (demux)) {
7881             gboolean res;
7882
7883             /* we need to seek back */
7884             res = qtdemux_seek_offset (demux, demux->first_mdat);
7885             if (res) {
7886               demux->offset = demux->first_mdat;
7887             } else {
7888               GST_DEBUG_OBJECT (demux, "Seek back failed");
7889             }
7890           } else {
7891             demux->offset += demux->neededbytes;
7892           }
7893           demux->neededbytes = 16;
7894           demux->state = QTDEMUX_STATE_INITIAL;
7895         }
7896
7897         break;
7898       }
7899       case QTDEMUX_STATE_BUFFER_MDAT:{
7900         GstBuffer *buf;
7901         guint8 fourcc[4];
7902
7903         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7904             demux->offset);
7905         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7906         gst_buffer_extract (buf, 0, fourcc, 4);
7907         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7908             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7909         if (demux->mdatbuffer)
7910           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7911         else
7912           demux->mdatbuffer = buf;
7913         demux->offset += demux->neededbytes;
7914         demux->neededbytes = 16;
7915         demux->state = QTDEMUX_STATE_INITIAL;
7916         gst_qtdemux_post_progress (demux, 1, 1);
7917
7918         break;
7919       }
7920       case QTDEMUX_STATE_MOVIE:{
7921         QtDemuxStream *stream = NULL;
7922         QtDemuxSample *sample;
7923         GstClockTime dts, pts, duration;
7924         gboolean keyframe;
7925         gint i;
7926
7927         GST_DEBUG_OBJECT (demux,
7928             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7929
7930         if (demux->fragmented) {
7931           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7932               demux->mdatleft);
7933           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7934             /* if needed data starts within this atom,
7935              * then it should not exceed this atom */
7936             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7937               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7938                   (_("This file is invalid and cannot be played.")),
7939                   ("sample data crosses atom boundary"));
7940               ret = GST_FLOW_ERROR;
7941               break;
7942             }
7943             demux->mdatleft -= demux->neededbytes;
7944           } else {
7945             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7946             /* so we are dropping more than left in this atom */
7947             gst_qtdemux_drop_data (demux, demux->mdatleft);
7948             demux->mdatleft = 0;
7949
7950             /* need to resume atom parsing so we do not miss any other pieces */
7951             demux->state = QTDEMUX_STATE_INITIAL;
7952             demux->neededbytes = 16;
7953
7954             /* check if there was any stored post mdat data from previous buffers */
7955             if (demux->restoredata_buffer) {
7956               g_assert (gst_adapter_available (demux->adapter) == 0);
7957
7958               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7959               demux->restoredata_buffer = NULL;
7960               demux->offset = demux->restoredata_offset;
7961             }
7962
7963             break;
7964           }
7965         }
7966
7967         if (demux->todrop) {
7968           if (demux->cenc_aux_info_offset > 0) {
7969             GstByteReader br;
7970             const guint8 *data;
7971
7972             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7973             data = gst_adapter_map (demux->adapter, demux->todrop);
7974             gst_byte_reader_init (&br, data + 8, demux->todrop);
7975             if (!qtdemux_parse_cenc_aux_info (demux,
7976                     QTDEMUX_NTH_STREAM (demux, 0), &br,
7977                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7978               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7979               ret = GST_FLOW_ERROR;
7980               gst_adapter_unmap (demux->adapter);
7981               g_free (demux->cenc_aux_info_sizes);
7982               demux->cenc_aux_info_sizes = NULL;
7983               goto done;
7984             }
7985             demux->cenc_aux_info_offset = 0;
7986             g_free (demux->cenc_aux_info_sizes);
7987             demux->cenc_aux_info_sizes = NULL;
7988             gst_adapter_unmap (demux->adapter);
7989           }
7990           gst_qtdemux_drop_data (demux, demux->todrop);
7991         }
7992
7993         /* first buffer? */
7994         /* initial newsegment sent here after having added pads,
7995          * possible others in sink_event */
7996         gst_qtdemux_check_send_pending_segment (demux);
7997
7998         /* Figure out which stream this packet belongs to */
7999         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
8000           stream = QTDEMUX_NTH_STREAM (demux, i);
8001           if (stream->sample_index >= stream->n_samples) {
8002             /* reset to be checked below G_UNLIKELY (stream == NULL) */
8003             stream = NULL;
8004             continue;
8005           }
8006           GST_LOG_OBJECT (demux,
8007               "Checking track-id %u (sample_index:%d / offset:%"
8008               G_GUINT64_FORMAT " / size:%d)", stream->track_id,
8009               stream->sample_index,
8010               stream->samples[stream->sample_index].offset,
8011               stream->samples[stream->sample_index].size);
8012
8013           if (stream->samples[stream->sample_index].offset == demux->offset)
8014             break;
8015         }
8016
8017         if (G_UNLIKELY (stream == NULL))
8018           goto unknown_stream;
8019
8020         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
8021
8022         if (stream->new_caps) {
8023           gst_qtdemux_configure_stream (demux, stream);
8024         }
8025
8026         /* Put data in a buffer, set timestamps, caps, ... */
8027         sample = &stream->samples[stream->sample_index];
8028
8029         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
8030           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
8031               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
8032
8033           dts = QTSAMPLE_DTS (stream, sample);
8034           pts = QTSAMPLE_PTS (stream, sample);
8035           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
8036           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
8037
8038           /* check for segment end */
8039           if (G_UNLIKELY (demux->segment.stop != -1
8040                   && demux->segment.stop <= pts && stream->on_keyframe)
8041               && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
8042             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
8043             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
8044
8045             /* skip this data, stream is EOS */
8046             gst_adapter_flush (demux->adapter, demux->neededbytes);
8047             demux->offset += demux->neededbytes;
8048
8049             /* check if all streams are eos */
8050             ret = GST_FLOW_EOS;
8051             for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
8052               if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
8053                 ret = GST_FLOW_OK;
8054                 break;
8055               }
8056             }
8057           } else {
8058             GstBuffer *outbuf;
8059
8060             outbuf =
8061                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
8062
8063             /* FIXME: should either be an assert or a plain check */
8064             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
8065
8066             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
8067                 dts, pts, duration, keyframe, dts, demux->offset);
8068           }
8069
8070           /* combine flows */
8071           ret = gst_qtdemux_combine_flows (demux, stream, ret);
8072         } else {
8073           /* skip this data, stream is EOS */
8074           gst_adapter_flush (demux->adapter, demux->neededbytes);
8075         }
8076
8077         stream->sample_index++;
8078         stream->offset_in_sample = 0;
8079
8080         /* update current offset and figure out size of next buffer */
8081         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
8082             demux->offset, demux->neededbytes);
8083         demux->offset += demux->neededbytes;
8084         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
8085             demux->offset);
8086
8087
8088         if (ret == GST_FLOW_EOS) {
8089           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
8090           demux->neededbytes = -1;
8091           goto eos;
8092         }
8093
8094         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
8095           if (demux->fragmented) {
8096             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
8097             /* there may be more to follow, only finish this atom */
8098             demux->todrop = demux->mdatleft;
8099             demux->neededbytes = demux->todrop;
8100             break;
8101           }
8102           goto eos;
8103         }
8104         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
8105           goto non_ok_unlinked_flow;
8106         }
8107         break;
8108       }
8109       default:
8110         goto invalid_state;
8111     }
8112   }
8113
8114   /* when buffering movie data, at least show user something is happening */
8115   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
8116       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
8117     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
8118         demux->neededbytes);
8119   }
8120 done:
8121
8122   return ret;
8123
8124   /* ERRORS */
8125 non_ok_unlinked_flow:
8126   {
8127     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
8128         gst_flow_get_name (ret));
8129     return ret;
8130   }
8131 unknown_stream:
8132   {
8133     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
8134     ret = GST_FLOW_ERROR;
8135     goto done;
8136   }
8137 eos:
8138   {
8139     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
8140     ret = GST_FLOW_EOS;
8141     goto done;
8142   }
8143 invalid_state:
8144   {
8145     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
8146         (NULL), ("qtdemuxer invalid state %d", demux->state));
8147     ret = GST_FLOW_ERROR;
8148     goto done;
8149   }
8150 no_moov:
8151   {
8152     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
8153         (NULL), ("no 'moov' atom within the first 10 MB"));
8154     ret = GST_FLOW_ERROR;
8155     goto done;
8156   }
8157 }
8158
8159 static gboolean
8160 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
8161 {
8162   GstQuery *query;
8163   gboolean pull_mode;
8164
8165   query = gst_query_new_scheduling ();
8166
8167   if (!gst_pad_peer_query (sinkpad, query)) {
8168     gst_query_unref (query);
8169     goto activate_push;
8170   }
8171
8172   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
8173       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
8174   gst_query_unref (query);
8175
8176   if (!pull_mode)
8177     goto activate_push;
8178
8179   GST_DEBUG_OBJECT (sinkpad, "activating pull");
8180   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
8181
8182 activate_push:
8183   {
8184     GST_DEBUG_OBJECT (sinkpad, "activating push");
8185     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
8186   }
8187 }
8188
8189 static gboolean
8190 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
8191     GstPadMode mode, gboolean active)
8192 {
8193   gboolean res;
8194   GstQTDemux *demux = GST_QTDEMUX (parent);
8195
8196   switch (mode) {
8197     case GST_PAD_MODE_PUSH:
8198       demux->pullbased = FALSE;
8199       res = TRUE;
8200       break;
8201     case GST_PAD_MODE_PULL:
8202       if (active) {
8203         demux->pullbased = TRUE;
8204         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
8205             sinkpad, NULL);
8206       } else {
8207         res = gst_pad_stop_task (sinkpad);
8208       }
8209       break;
8210     default:
8211       res = FALSE;
8212       break;
8213   }
8214   return res;
8215 }
8216
8217 #ifdef HAVE_ZLIB
8218 static void *
8219 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
8220 {
8221   guint8 *buffer;
8222   z_stream z;
8223   int ret;
8224
8225   memset (&z, 0, sizeof (z));
8226   z.zalloc = NULL;
8227   z.zfree = NULL;
8228   z.opaque = NULL;
8229
8230   if ((ret = inflateInit (&z)) != Z_OK) {
8231     GST_ERROR ("inflateInit() returned %d", ret);
8232     return NULL;
8233   }
8234
8235   z.next_in = z_buffer;
8236   z.avail_in = z_length;
8237
8238   buffer = (guint8 *) g_malloc (*length);
8239   z.avail_out = *length;
8240   z.next_out = (Bytef *) buffer;
8241   do {
8242     ret = inflate (&z, Z_NO_FLUSH);
8243     if (ret == Z_STREAM_END) {
8244       break;
8245     } else if (ret != Z_OK) {
8246       GST_WARNING ("inflate() returned %d", ret);
8247       break;
8248     }
8249
8250     *length += 4096;
8251     buffer = (guint8 *) g_realloc (buffer, *length);
8252     z.next_out = (Bytef *) (buffer + z.total_out);
8253     z.avail_out += 4096;
8254   } while (z.avail_in > 0);
8255
8256   if (ret != Z_STREAM_END) {
8257     g_free (buffer);
8258     buffer = NULL;
8259     *length = 0;
8260   } else {
8261     *length = z.total_out;
8262   }
8263
8264   inflateEnd (&z);
8265
8266   return buffer;
8267 }
8268 #endif /* HAVE_ZLIB */
8269
8270 static gboolean
8271 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8272 {
8273   GNode *cmov;
8274
8275   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8276
8277   /* counts as header data */
8278   qtdemux->header_size += length;
8279
8280   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8281   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8282
8283   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8284   if (cmov) {
8285     guint32 method;
8286     GNode *dcom;
8287     GNode *cmvd;
8288     guint32 dcom_len;
8289
8290     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8291     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8292     if (dcom == NULL || cmvd == NULL)
8293       goto invalid_compression;
8294
8295     dcom_len = QT_UINT32 (dcom->data);
8296     if (dcom_len < 12)
8297       goto invalid_compression;
8298
8299     method = QT_FOURCC ((guint8 *) dcom->data + 8);
8300     switch (method) {
8301 #ifdef HAVE_ZLIB
8302       case FOURCC_zlib:{
8303         guint uncompressed_length;
8304         guint compressed_length;
8305         guint8 *buf;
8306         guint32 cmvd_len;
8307
8308         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8309         if (cmvd_len < 12)
8310           goto invalid_compression;
8311
8312         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8313         compressed_length = cmvd_len - 12;
8314         GST_LOG ("length = %u", uncompressed_length);
8315
8316         buf =
8317             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8318             compressed_length, &uncompressed_length);
8319
8320         if (buf) {
8321           qtdemux->moov_node_compressed = qtdemux->moov_node;
8322           qtdemux->moov_node = g_node_new (buf);
8323
8324           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8325               uncompressed_length);
8326         }
8327         break;
8328       }
8329 #endif /* HAVE_ZLIB */
8330       default:
8331         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8332             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8333         break;
8334     }
8335   }
8336   return TRUE;
8337
8338   /* ERRORS */
8339 invalid_compression:
8340   {
8341     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8342     return FALSE;
8343   }
8344 }
8345
8346 static gboolean
8347 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8348     const guint8 * end)
8349 {
8350   while (G_UNLIKELY (buf < end)) {
8351     GNode *child;
8352     guint32 len;
8353
8354     if (G_UNLIKELY (buf + 4 > end)) {
8355       GST_LOG_OBJECT (qtdemux, "buffer overrun");
8356       break;
8357     }
8358     len = QT_UINT32 (buf);
8359     if (G_UNLIKELY (len == 0)) {
8360       GST_LOG_OBJECT (qtdemux, "empty container");
8361       break;
8362     }
8363     if (G_UNLIKELY (len < 8)) {
8364       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8365       break;
8366     }
8367     if (G_UNLIKELY (len > (end - buf))) {
8368       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8369           (gint) (end - buf));
8370       break;
8371     }
8372
8373     child = g_node_new ((guint8 *) buf);
8374     g_node_append (node, child);
8375     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8376     qtdemux_parse_node (qtdemux, child, buf, len);
8377
8378     buf += len;
8379   }
8380   return TRUE;
8381 }
8382
8383 static gboolean
8384 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8385     GNode * xdxt)
8386 {
8387   int len = QT_UINT32 (xdxt->data);
8388   guint8 *buf = xdxt->data;
8389   guint8 *end = buf + len;
8390   GstBuffer *buffer;
8391
8392   /* skip size and type */
8393   buf += 8;
8394   end -= 8;
8395
8396   while (buf < end) {
8397     gint size;
8398     guint32 type;
8399
8400     size = QT_UINT32 (buf);
8401     type = QT_FOURCC (buf + 4);
8402
8403     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8404
8405     if (buf + size > end || size <= 0)
8406       break;
8407
8408     buf += 8;
8409     size -= 8;
8410
8411     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8412         GST_FOURCC_ARGS (type));
8413
8414     switch (type) {
8415       case FOURCC_tCtH:
8416         buffer = gst_buffer_new_and_alloc (size);
8417         gst_buffer_fill (buffer, 0, buf, size);
8418         stream->buffers = g_slist_append (stream->buffers, buffer);
8419         GST_LOG_OBJECT (qtdemux, "parsing theora header");
8420         break;
8421       case FOURCC_tCt_:
8422         buffer = gst_buffer_new_and_alloc (size);
8423         gst_buffer_fill (buffer, 0, buf, size);
8424         stream->buffers = g_slist_append (stream->buffers, buffer);
8425         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8426         break;
8427       case FOURCC_tCtC:
8428         buffer = gst_buffer_new_and_alloc (size);
8429         gst_buffer_fill (buffer, 0, buf, size);
8430         stream->buffers = g_slist_append (stream->buffers, buffer);
8431         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8432         break;
8433       default:
8434         GST_WARNING_OBJECT (qtdemux,
8435             "unknown theora cookie %" GST_FOURCC_FORMAT,
8436             GST_FOURCC_ARGS (type));
8437         break;
8438     }
8439     buf += size;
8440   }
8441   return TRUE;
8442 }
8443
8444 static gboolean
8445 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8446     guint length)
8447 {
8448   guint32 fourcc = 0;
8449   guint32 node_length = 0;
8450   const QtNodeType *type;
8451   const guint8 *end;
8452
8453   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8454
8455   if (G_UNLIKELY (length < 8))
8456     goto not_enough_data;
8457
8458   node_length = QT_UINT32 (buffer);
8459   fourcc = QT_FOURCC (buffer + 4);
8460
8461   /* ignore empty nodes */
8462   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8463     return TRUE;
8464
8465   type = qtdemux_type_get (fourcc);
8466
8467   end = buffer + length;
8468
8469   GST_LOG_OBJECT (qtdemux,
8470       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8471       GST_FOURCC_ARGS (fourcc), node_length, type->name);
8472
8473   if (node_length > length)
8474     goto broken_atom_size;
8475
8476   if (type->flags & QT_FLAG_CONTAINER) {
8477     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8478   } else {
8479     switch (fourcc) {
8480       case FOURCC_stsd:
8481       {
8482         if (node_length < 20) {
8483           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8484           break;
8485         }
8486         GST_DEBUG_OBJECT (qtdemux,
8487             "parsing stsd (sample table, sample description) atom");
8488         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8489         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8490         break;
8491       }
8492       case FOURCC_mp4a:
8493       case FOURCC_alac:
8494       case FOURCC_fLaC:
8495       {
8496         guint32 version;
8497         guint32 offset;
8498         guint min_size;
8499
8500         /* also read alac (or whatever) in stead of mp4a in the following,
8501          * since a similar layout is used in other cases as well */
8502         if (fourcc == FOURCC_mp4a)
8503           min_size = 20;
8504         else if (fourcc == FOURCC_fLaC)
8505           min_size = 86;
8506         else
8507           min_size = 40;
8508
8509         /* There are two things we might encounter here: a true mp4a atom, and
8510            an mp4a entry in an stsd atom. The latter is what we're interested
8511            in, and it looks like an atom, but isn't really one. The true mp4a
8512            atom is short, so we detect it based on length here. */
8513         if (length < min_size) {
8514           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8515               GST_FOURCC_ARGS (fourcc));
8516           break;
8517         }
8518
8519         /* 'version' here is the sound sample description version. Types 0 and
8520            1 are documented in the QTFF reference, but type 2 is not: it's
8521            described in Apple header files instead (struct SoundDescriptionV2
8522            in Movies.h) */
8523         version = QT_UINT16 (buffer + 16);
8524
8525         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8526             GST_FOURCC_ARGS (fourcc), version);
8527
8528         /* parse any esds descriptors */
8529         switch (version) {
8530           case 0:
8531             offset = 0x24;
8532             break;
8533           case 1:
8534             offset = 0x34;
8535             break;
8536           case 2:
8537             offset = 0x48;
8538             break;
8539           default:
8540             GST_WARNING_OBJECT (qtdemux,
8541                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8542                 GST_FOURCC_ARGS (fourcc), version);
8543             offset = 0;
8544             break;
8545         }
8546         if (offset)
8547           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8548         break;
8549       }
8550       case FOURCC_mp4v:
8551       case FOURCC_MP4V:
8552       case FOURCC_fmp4:
8553       case FOURCC_FMP4:
8554       case FOURCC_apcs:
8555       case FOURCC_apch:
8556       case FOURCC_apcn:
8557       case FOURCC_apco:
8558       case FOURCC_ap4h:
8559       case FOURCC_xvid:
8560       case FOURCC_XVID:
8561       case FOURCC_H264:
8562       case FOURCC_avc1:
8563       case FOURCC_avc3:
8564       case FOURCC_H265:
8565       case FOURCC_hvc1:
8566       case FOURCC_hev1:
8567       case FOURCC_mjp2:
8568       case FOURCC_encv:
8569       {
8570         guint32 version;
8571         guint32 str_len;
8572
8573         /* codec_data is contained inside these atoms, which all have
8574          * the same format. */
8575         /* video sample description size is 86 bytes without extension.
8576          * node_length have to be bigger than 86 bytes because video sample
8577          * description can include extenstions such as esds, fiel, glbl, etc. */
8578         if (node_length < 86) {
8579           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8580               " sample description length too short (%u < 86)",
8581               GST_FOURCC_ARGS (fourcc), node_length);
8582           break;
8583         }
8584
8585         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8586             GST_FOURCC_ARGS (fourcc));
8587
8588         /* version (2 bytes) : this is set to 0, unless a compressor has changed
8589          *              its data format.
8590          * revision level (2 bytes) : must be set to 0. */
8591         version = QT_UINT32 (buffer + 16);
8592         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8593
8594         /* compressor name : PASCAL string and informative purposes
8595          * first byte : the number of bytes to be displayed.
8596          *              it has to be less than 32 because it is reserved
8597          *              space of 32 bytes total including itself. */
8598         str_len = QT_UINT8 (buffer + 50);
8599         if (str_len < 32)
8600           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8601               (char *) buffer + 51);
8602         else
8603           GST_WARNING_OBJECT (qtdemux,
8604               "compressorname length too big (%u > 31)", str_len);
8605
8606         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8607             end - buffer);
8608         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8609         break;
8610       }
8611       case FOURCC_meta:
8612       {
8613         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8614
8615         /* You are reading this correctly. QTFF specifies that the
8616          * metadata atom is a short atom, whereas ISO BMFF specifies
8617          * it's a full atom. But since so many people are doing things
8618          * differently, we actually peek into the atom to see which
8619          * variant it is */
8620         if (length < 16) {
8621           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8622               GST_FOURCC_ARGS (fourcc));
8623           break;
8624         }
8625         if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8626           /* Variant 1: What QTFF specifies. 'meta' is a short header which
8627            * starts with a 'hdlr' atom */
8628           qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8629         } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8630           /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8631            * with version/flags both set to zero */
8632           qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8633         } else
8634           GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8635         break;
8636       }
8637       case FOURCC_mp4s:
8638       {
8639         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8640         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8641         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8642         break;
8643       }
8644       case FOURCC_XiTh:
8645       {
8646         guint32 version;
8647         guint32 offset;
8648
8649         if (length < 16) {
8650           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8651               GST_FOURCC_ARGS (fourcc));
8652           break;
8653         }
8654
8655         version = QT_UINT32 (buffer + 12);
8656         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8657
8658         switch (version) {
8659           case 0x00000001:
8660             offset = 0x62;
8661             break;
8662           default:
8663             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8664             offset = 0;
8665             break;
8666         }
8667         if (offset) {
8668           if (length < offset) {
8669             GST_WARNING_OBJECT (qtdemux,
8670                 "skipping too small %" GST_FOURCC_FORMAT " box",
8671                 GST_FOURCC_ARGS (fourcc));
8672             break;
8673           }
8674           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8675         }
8676         break;
8677       }
8678       case FOURCC_in24:
8679       {
8680         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8681         break;
8682       }
8683       case FOURCC_uuid:
8684       {
8685         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8686         break;
8687       }
8688       case FOURCC_enca:
8689       {
8690         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8691         break;
8692       }
8693 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
8694       case FOURCC_SA3D:
8695       {
8696         qtdemux_parse_SA3D (qtdemux, buffer, end - buffer);
8697         break;
8698       }
8699 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
8700       default:
8701         if (!strcmp (type->name, "unknown"))
8702           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8703         break;
8704     }
8705   }
8706   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8707       GST_FOURCC_ARGS (fourcc));
8708   return TRUE;
8709
8710 /* ERRORS */
8711 not_enough_data:
8712   {
8713     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8714         (_("This file is corrupt and cannot be played.")),
8715         ("Not enough data for an atom header, got only %u bytes", length));
8716     return FALSE;
8717   }
8718 broken_atom_size:
8719   {
8720     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8721         (_("This file is corrupt and cannot be played.")),
8722         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8723             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8724             length));
8725     return FALSE;
8726   }
8727 }
8728
8729 static GNode *
8730 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
8731 {
8732   GNode *child;
8733   guint8 *buffer;
8734   guint32 child_fourcc;
8735
8736   for (child = g_node_first_child (node); child;
8737       child = g_node_next_sibling (child)) {
8738     buffer = (guint8 *) child->data;
8739
8740     child_fourcc = QT_FOURCC (buffer + 4);
8741
8742     if (G_UNLIKELY (child_fourcc == fourcc)) {
8743       return child;
8744     }
8745   }
8746   return NULL;
8747 }
8748
8749 static GNode *
8750 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
8751     GstByteReader * parser)
8752 {
8753   GNode *child;
8754   guint8 *buffer;
8755   guint32 child_fourcc, child_len;
8756
8757   for (child = g_node_first_child (node); child;
8758       child = g_node_next_sibling (child)) {
8759     buffer = (guint8 *) child->data;
8760
8761     child_len = QT_UINT32 (buffer);
8762     child_fourcc = QT_FOURCC (buffer + 4);
8763
8764     if (G_UNLIKELY (child_fourcc == fourcc)) {
8765       if (G_UNLIKELY (child_len < (4 + 4)))
8766         return NULL;
8767       /* FIXME: must verify if atom length < parent atom length */
8768       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8769       return child;
8770     }
8771   }
8772   return NULL;
8773 }
8774
8775 static GNode *
8776 qtdemux_tree_get_child_by_index (GNode * node, guint index)
8777 {
8778   return g_node_nth_child (node, index);
8779 }
8780
8781 static GNode *
8782 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
8783     GstByteReader * parser)
8784 {
8785   GNode *child;
8786   guint8 *buffer;
8787   guint32 child_fourcc, child_len;
8788
8789   for (child = g_node_next_sibling (node); child;
8790       child = g_node_next_sibling (child)) {
8791     buffer = (guint8 *) child->data;
8792
8793     child_fourcc = QT_FOURCC (buffer + 4);
8794
8795     if (child_fourcc == fourcc) {
8796       if (parser) {
8797         child_len = QT_UINT32 (buffer);
8798         if (G_UNLIKELY (child_len < (4 + 4)))
8799           return NULL;
8800         /* FIXME: must verify if atom length < parent atom length */
8801         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8802       }
8803       return child;
8804     }
8805   }
8806   return NULL;
8807 }
8808
8809 static GNode *
8810 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8811 {
8812   return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8813 }
8814
8815 static void
8816 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8817 {
8818 /* FIXME: This can only reliably work if demuxers have a
8819  * separate streaming thread per srcpad. This should be
8820  * done in a demuxer base class, which integrates parts
8821  * of multiqueue
8822  *
8823  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8824  */
8825 #if 0
8826   GstQuery *query;
8827
8828   query = gst_query_new_allocation (stream->caps, FALSE);
8829
8830   if (!gst_pad_peer_query (stream->pad, query)) {
8831     /* not a problem, just debug a little */
8832     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8833   }
8834
8835   if (stream->allocator)
8836     gst_object_unref (stream->allocator);
8837
8838   if (gst_query_get_n_allocation_params (query) > 0) {
8839     /* try the allocator */
8840     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8841         &stream->params);
8842     stream->use_allocator = TRUE;
8843   } else {
8844     stream->allocator = NULL;
8845     gst_allocation_params_init (&stream->params);
8846     stream->use_allocator = FALSE;
8847   }
8848   gst_query_unref (query);
8849 #endif
8850 }
8851
8852 static gboolean
8853 pad_query (const GValue * item, GValue * value, gpointer user_data)
8854 {
8855   GstPad *pad = g_value_get_object (item);
8856   GstQuery *query = user_data;
8857   gboolean res;
8858
8859   res = gst_pad_peer_query (pad, query);
8860
8861   if (res) {
8862     g_value_set_boolean (value, TRUE);
8863     return FALSE;
8864   }
8865
8866   GST_INFO_OBJECT (pad, "pad peer query failed");
8867   return TRUE;
8868 }
8869
8870 static gboolean
8871 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8872     GstPadDirection direction)
8873 {
8874   GstIterator *it;
8875   GstIteratorFoldFunction func = pad_query;
8876   GValue res = { 0, };
8877
8878   g_value_init (&res, G_TYPE_BOOLEAN);
8879   g_value_set_boolean (&res, FALSE);
8880
8881   /* Ask neighbor */
8882   if (direction == GST_PAD_SRC)
8883     it = gst_element_iterate_src_pads (element);
8884   else
8885     it = gst_element_iterate_sink_pads (element);
8886
8887   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8888     gst_iterator_resync (it);
8889
8890   gst_iterator_free (it);
8891
8892   return g_value_get_boolean (&res);
8893 }
8894
8895 static void
8896 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8897     QtDemuxStream * stream)
8898 {
8899   GstQuery *query;
8900   GstContext *ctxt;
8901   GstElement *element = GST_ELEMENT (qtdemux);
8902   GstStructure *st;
8903   gchar **filtered_sys_ids;
8904   GValue event_list = G_VALUE_INIT;
8905   GList *walk;
8906
8907   /* 1. Check if we already have the context. */
8908   if (qtdemux->preferred_protection_system_id != NULL) {
8909     GST_LOG_OBJECT (element,
8910         "already have the protection context, no need to request it again");
8911     return;
8912   }
8913
8914   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8915   filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8916       (const gchar **) qtdemux->protection_system_ids->pdata);
8917
8918   g_ptr_array_remove_index (qtdemux->protection_system_ids,
8919       qtdemux->protection_system_ids->len - 1);
8920   GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8921       "decryptors for %u of them, running context request",
8922       qtdemux->protection_system_ids->len,
8923       filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8924
8925
8926   if (stream->protection_scheme_event_queue.length) {
8927     GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8928         stream->protection_scheme_event_queue.length);
8929     walk = stream->protection_scheme_event_queue.tail;
8930   } else {
8931     GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8932         qtdemux->protection_event_queue.length);
8933     walk = qtdemux->protection_event_queue.tail;
8934   }
8935
8936   g_value_init (&event_list, GST_TYPE_LIST);
8937   for (; walk; walk = g_list_previous (walk)) {
8938     GValue *event_value = g_new0 (GValue, 1);
8939     g_value_init (event_value, GST_TYPE_EVENT);
8940     g_value_set_boxed (event_value, walk->data);
8941     gst_value_list_append_and_take_value (&event_list, event_value);
8942   }
8943
8944   /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
8945    *      check if downstream already has a context of the specific type
8946    *  2b) Query upstream as above.
8947    */
8948   query = gst_query_new_context ("drm-preferred-decryption-system-id");
8949   st = gst_query_writable_structure (query);
8950   gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8951       "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8952       NULL);
8953   gst_structure_set_value (st, "stream-encryption-events", &event_list);
8954   if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8955     gst_query_parse_context (query, &ctxt);
8956     GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8957     gst_element_set_context (element, ctxt);
8958   } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8959     gst_query_parse_context (query, &ctxt);
8960     GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8961     gst_element_set_context (element, ctxt);
8962   } else {
8963     /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8964      *    the required context type and afterwards check if a
8965      *    usable context was set now as in 1). The message could
8966      *    be handled by the parent bins of the element and the
8967      *    application.
8968      */
8969     GstMessage *msg;
8970
8971     GST_INFO_OBJECT (element, "posting need context message");
8972     msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8973         "drm-preferred-decryption-system-id");
8974     st = (GstStructure *) gst_message_get_structure (msg);
8975     gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8976         "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8977         NULL);
8978
8979     gst_structure_set_value (st, "stream-encryption-events", &event_list);
8980     gst_element_post_message (element, msg);
8981   }
8982
8983   g_strfreev (filtered_sys_ids);
8984   g_value_unset (&event_list);
8985   gst_query_unref (query);
8986 }
8987
8988 static gboolean
8989 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8990     QtDemuxStream * stream)
8991 {
8992   GstStructure *s;
8993   const gchar *selected_system = NULL;
8994
8995   g_return_val_if_fail (qtdemux != NULL, FALSE);
8996   g_return_val_if_fail (stream != NULL, FALSE);
8997   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8998       FALSE);
8999
9000   if (stream->protection_scheme_type != FOURCC_cenc) {
9001     GST_ERROR_OBJECT (qtdemux,
9002         "unsupported protection scheme: %" GST_FOURCC_FORMAT,
9003         GST_FOURCC_ARGS (stream->protection_scheme_type));
9004     return FALSE;
9005   }
9006   if (qtdemux->protection_system_ids == NULL) {
9007     GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
9008         "cenc protection system information has been found");
9009     return FALSE;
9010   }
9011
9012   gst_qtdemux_request_protection_context (qtdemux, stream);
9013   if (qtdemux->preferred_protection_system_id != NULL) {
9014     const gchar *preferred_system_array[] =
9015         { qtdemux->preferred_protection_system_id, NULL };
9016
9017     selected_system = gst_protection_select_system (preferred_system_array);
9018
9019     if (selected_system) {
9020       GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
9021           qtdemux->preferred_protection_system_id);
9022     } else {
9023       GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
9024           "because there is no available decryptor",
9025           qtdemux->preferred_protection_system_id);
9026     }
9027   }
9028
9029   if (!selected_system) {
9030     g_ptr_array_add (qtdemux->protection_system_ids, NULL);
9031     selected_system = gst_protection_select_system ((const gchar **)
9032         qtdemux->protection_system_ids->pdata);
9033     g_ptr_array_remove_index (qtdemux->protection_system_ids,
9034         qtdemux->protection_system_ids->len - 1);
9035   }
9036
9037   if (!selected_system) {
9038     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
9039         "suitable decryptor element has been found");
9040     return FALSE;
9041   }
9042
9043   GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
9044       selected_system);
9045
9046   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9047   if (!gst_structure_has_name (s, "application/x-cenc")) {
9048     gst_structure_set (s,
9049         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
9050         GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
9051         NULL);
9052     gst_structure_set_name (s, "application/x-cenc");
9053   }
9054   return TRUE;
9055 }
9056
9057 static gboolean
9058 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
9059 {
9060   /* fps is calculated base on the duration of the average framerate since
9061    * qt does not have a fixed framerate. */
9062   gboolean fps_available = TRUE;
9063   guint32 first_duration = 0;
9064
9065   if (stream->n_samples > 0)
9066     first_duration = stream->samples[0].duration;
9067
9068   if ((stream->n_samples == 1 && first_duration == 0)
9069       || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
9070     /* still frame */
9071     CUR_STREAM (stream)->fps_n = 0;
9072     CUR_STREAM (stream)->fps_d = 1;
9073   } else {
9074     if (stream->duration == 0 || stream->n_samples < 2) {
9075       CUR_STREAM (stream)->fps_n = stream->timescale;
9076       CUR_STREAM (stream)->fps_d = 1;
9077       fps_available = FALSE;
9078     } else {
9079       GstClockTime avg_duration;
9080       guint64 duration;
9081       guint32 n_samples;
9082
9083       /* duration and n_samples can be updated for fragmented format
9084        * so, framerate of fragmented format is calculated using data in a moof */
9085       if (qtdemux->fragmented && stream->n_samples_moof > 0
9086           && stream->duration_moof > 0) {
9087         n_samples = stream->n_samples_moof;
9088         duration = stream->duration_moof;
9089       } else {
9090         n_samples = stream->n_samples;
9091         duration = stream->duration;
9092       }
9093
9094       /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
9095       /* stream->duration is guint64, timescale, n_samples are guint32 */
9096       avg_duration =
9097           gst_util_uint64_scale_round (duration -
9098           first_duration, GST_SECOND,
9099           (guint64) (stream->timescale) * (n_samples - 1));
9100
9101       GST_LOG_OBJECT (qtdemux,
9102           "Calculating avg sample duration based on stream (or moof) duration %"
9103           G_GUINT64_FORMAT
9104           " minus first sample %u, leaving %d samples gives %"
9105           GST_TIME_FORMAT, duration, first_duration,
9106           n_samples - 1, GST_TIME_ARGS (avg_duration));
9107
9108 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
9109       gst_video_guess_framerate (avg_duration,
9110         &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
9111       if (CUR_STREAM (stream)->fps_d == 0)
9112         fps_available = FALSE;
9113 #else
9114       fps_available =
9115           gst_video_guess_framerate (avg_duration,
9116           &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
9117 #endif
9118
9119       GST_DEBUG_OBJECT (qtdemux,
9120           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
9121           stream->timescale, CUR_STREAM (stream)->fps_n,
9122           CUR_STREAM (stream)->fps_d);
9123     }
9124   }
9125
9126   return fps_available;
9127 }
9128
9129 static gboolean
9130 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
9131 {
9132   if (stream->subtype == FOURCC_vide) {
9133     gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9134
9135     if (CUR_STREAM (stream)->caps) {
9136       CUR_STREAM (stream)->caps =
9137           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9138
9139       if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
9140         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9141             "width", G_TYPE_INT, CUR_STREAM (stream)->width,
9142             "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
9143
9144       /* set framerate if calculated framerate is reliable */
9145       if (fps_available) {
9146         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9147             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9148             CUR_STREAM (stream)->fps_d, NULL);
9149       }
9150
9151       /* calculate pixel-aspect-ratio using display width and height */
9152       GST_DEBUG_OBJECT (qtdemux,
9153           "video size %dx%d, target display size %dx%d",
9154           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
9155           stream->display_width, stream->display_height);
9156       /* qt file might have pasp atom */
9157       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9158         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
9159             CUR_STREAM (stream)->par_h);
9160         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9161             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9162             CUR_STREAM (stream)->par_h, NULL);
9163       } else if (stream->display_width > 0 && stream->display_height > 0
9164           && CUR_STREAM (stream)->width > 0
9165           && CUR_STREAM (stream)->height > 0) {
9166         gint n, d;
9167
9168         /* calculate the pixel aspect ratio using the display and pixel w/h */
9169         n = stream->display_width * CUR_STREAM (stream)->height;
9170         d = stream->display_height * CUR_STREAM (stream)->width;
9171         if (n == d)
9172           n = d = 1;
9173         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
9174         CUR_STREAM (stream)->par_w = n;
9175         CUR_STREAM (stream)->par_h = d;
9176         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9177             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9178             CUR_STREAM (stream)->par_h, NULL);
9179       }
9180
9181       if (CUR_STREAM (stream)->interlace_mode > 0) {
9182         if (CUR_STREAM (stream)->interlace_mode == 1) {
9183           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9184               G_TYPE_STRING, "progressive", NULL);
9185         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
9186           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9187               G_TYPE_STRING, "interleaved", NULL);
9188           if (CUR_STREAM (stream)->field_order == 9) {
9189             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9190                 G_TYPE_STRING, "top-field-first", NULL);
9191           } else if (CUR_STREAM (stream)->field_order == 14) {
9192             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9193                 G_TYPE_STRING, "bottom-field-first", NULL);
9194           }
9195         }
9196       }
9197
9198       /* Create incomplete colorimetry here if needed */
9199       if (CUR_STREAM (stream)->colorimetry.range ||
9200           CUR_STREAM (stream)->colorimetry.matrix ||
9201           CUR_STREAM (stream)->colorimetry.transfer
9202           || CUR_STREAM (stream)->colorimetry.primaries) {
9203         gchar *colorimetry =
9204             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
9205         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
9206             G_TYPE_STRING, colorimetry, NULL);
9207         g_free (colorimetry);
9208       }
9209
9210       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
9211         guint par_w = 1, par_h = 1;
9212
9213         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9214           par_w = CUR_STREAM (stream)->par_w;
9215           par_h = CUR_STREAM (stream)->par_h;
9216         }
9217
9218         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
9219                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
9220                 par_h)) {
9221           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
9222         }
9223
9224         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9225             "multiview-mode", G_TYPE_STRING,
9226             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
9227             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
9228             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
9229       }
9230     }
9231   }
9232
9233   else if (stream->subtype == FOURCC_soun) {
9234     if (CUR_STREAM (stream)->caps) {
9235       CUR_STREAM (stream)->caps =
9236           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9237       if (CUR_STREAM (stream)->rate > 0)
9238         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9239             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
9240       if (CUR_STREAM (stream)->n_channels > 0)
9241         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9242             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
9243       if (CUR_STREAM (stream)->n_channels > 2) {
9244         /* FIXME: Need to parse the 'chan' atom to get channel layouts
9245          * correctly; this is just the minimum we can do - assume
9246          * we don't actually have any channel positions. */
9247         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9248             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
9249       }
9250     }
9251   }
9252
9253   else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
9254     const GstStructure *s;
9255     QtDemuxStream *fps_stream = NULL;
9256     gboolean fps_available = FALSE;
9257
9258     /* CEA608 closed caption tracks are a bit special in that each sample
9259      * can contain CCs for multiple frames, and CCs can be omitted and have to
9260      * be inferred from the duration of the sample then.
9261      *
9262      * As such we take the framerate from the (first) video track here for
9263      * CEA608 as there must be one CC byte pair for every video frame
9264      * according to the spec.
9265      *
9266      * For CEA708 all is fine and there is one sample per frame.
9267      */
9268
9269     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9270     if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
9271       gint i;
9272
9273       for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
9274         QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
9275
9276         if (tmp->subtype == FOURCC_vide) {
9277           fps_stream = tmp;
9278           break;
9279         }
9280       }
9281
9282       if (fps_stream) {
9283         fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
9284         CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
9285         CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
9286       }
9287     } else {
9288       fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9289       fps_stream = stream;
9290     }
9291
9292     CUR_STREAM (stream)->caps =
9293         gst_caps_make_writable (CUR_STREAM (stream)->caps);
9294
9295     /* set framerate if calculated framerate is reliable */
9296     if (fps_available) {
9297       gst_caps_set_simple (CUR_STREAM (stream)->caps,
9298           "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9299           CUR_STREAM (stream)->fps_d, NULL);
9300     }
9301   }
9302
9303   if (stream->pad) {
9304     GstCaps *prev_caps = NULL;
9305
9306     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9307     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9308     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9309     gst_pad_set_active (stream->pad, TRUE);
9310
9311     gst_pad_use_fixed_caps (stream->pad);
9312
9313     if (stream->protected) {
9314       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9315         GST_ERROR_OBJECT (qtdemux,
9316             "Failed to configure protected stream caps.");
9317         return FALSE;
9318       }
9319     }
9320
9321     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9322         CUR_STREAM (stream)->caps);
9323     if (stream->new_stream) {
9324       GstEvent *event;
9325       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9326
9327       event =
9328           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9329           0);
9330       if (event) {
9331         gst_event_parse_stream_flags (event, &stream_flags);
9332         if (gst_event_parse_group_id (event, &qtdemux->group_id))
9333           qtdemux->have_group_id = TRUE;
9334         else
9335           qtdemux->have_group_id = FALSE;
9336         gst_event_unref (event);
9337       } else if (!qtdemux->have_group_id) {
9338         qtdemux->have_group_id = TRUE;
9339         qtdemux->group_id = gst_util_group_id_next ();
9340       }
9341
9342       stream->new_stream = FALSE;
9343       event = gst_event_new_stream_start (stream->stream_id);
9344       if (qtdemux->have_group_id)
9345         gst_event_set_group_id (event, qtdemux->group_id);
9346       if (stream->disabled)
9347         stream_flags |= GST_STREAM_FLAG_UNSELECT;
9348       if (CUR_STREAM (stream)->sparse) {
9349         stream_flags |= GST_STREAM_FLAG_SPARSE;
9350       } else {
9351         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9352       }
9353       gst_event_set_stream_flags (event, stream_flags);
9354       gst_pad_push_event (stream->pad, event);
9355     }
9356
9357     prev_caps = gst_pad_get_current_caps (stream->pad);
9358
9359     if (CUR_STREAM (stream)->caps) {
9360       if (!prev_caps
9361           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9362         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9363             CUR_STREAM (stream)->caps);
9364         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9365       } else {
9366         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9367       }
9368     } else {
9369       GST_WARNING_OBJECT (qtdemux, "stream without caps");
9370     }
9371
9372     if (prev_caps)
9373       gst_caps_unref (prev_caps);
9374     stream->new_caps = FALSE;
9375   }
9376   return TRUE;
9377 }
9378
9379 static void
9380 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9381     QtDemuxStream * stream)
9382 {
9383   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9384     return;
9385
9386   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9387       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9388   if (G_UNLIKELY (stream->stsd_sample_description_id >=
9389           stream->stsd_entries_length)) {
9390     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9391         (_("This file is invalid and cannot be played.")),
9392         ("New sample description id is out of bounds (%d >= %d)",
9393             stream->stsd_sample_description_id, stream->stsd_entries_length));
9394   } else {
9395     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9396     stream->new_caps = TRUE;
9397   }
9398 }
9399
9400 static gboolean
9401 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9402     QtDemuxStream * stream, GstTagList * list)
9403 {
9404   gboolean ret = TRUE;
9405
9406   if (stream->subtype == FOURCC_vide) {
9407     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9408
9409     stream->pad =
9410         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9411     g_free (name);
9412
9413     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9414       gst_object_unref (stream->pad);
9415       stream->pad = NULL;
9416       ret = FALSE;
9417       goto done;
9418     }
9419
9420     qtdemux->n_video_streams++;
9421   } else if (stream->subtype == FOURCC_soun) {
9422     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9423
9424     stream->pad =
9425         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9426     g_free (name);
9427     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9428       gst_object_unref (stream->pad);
9429       stream->pad = NULL;
9430       ret = FALSE;
9431       goto done;
9432     }
9433     qtdemux->n_audio_streams++;
9434   } else if (stream->subtype == FOURCC_strm) {
9435     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9436   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9437       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9438       || stream->subtype == FOURCC_clcp) {
9439     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9440
9441     stream->pad =
9442         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9443     g_free (name);
9444     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9445       gst_object_unref (stream->pad);
9446       stream->pad = NULL;
9447       ret = FALSE;
9448       goto done;
9449     }
9450     qtdemux->n_sub_streams++;
9451   } else if (CUR_STREAM (stream)->caps) {
9452     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9453
9454     stream->pad =
9455         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9456     g_free (name);
9457     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9458       gst_object_unref (stream->pad);
9459       stream->pad = NULL;
9460       ret = FALSE;
9461       goto done;
9462     }
9463     qtdemux->n_video_streams++;
9464   } else {
9465     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9466     goto done;
9467   }
9468
9469   if (stream->pad) {
9470     GList *l;
9471
9472     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9473         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9474     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9475     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9476
9477     if (stream->stream_tags)
9478       gst_tag_list_unref (stream->stream_tags);
9479     stream->stream_tags = list;
9480     list = NULL;
9481     /* global tags go on each pad anyway */
9482     stream->send_global_tags = TRUE;
9483     /* send upstream GST_EVENT_PROTECTION events that were received before
9484        this source pad was created */
9485     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9486       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9487   }
9488 done:
9489   if (list)
9490     gst_tag_list_unref (list);
9491   return ret;
9492 }
9493
9494 /* find next atom with @fourcc starting at @offset */
9495 static GstFlowReturn
9496 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9497     guint64 * length, guint32 fourcc)
9498 {
9499   GstFlowReturn ret;
9500   guint32 lfourcc;
9501   GstBuffer *buf;
9502
9503   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9504       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9505
9506   while (TRUE) {
9507     GstMapInfo map;
9508
9509     buf = NULL;
9510     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9511     if (G_UNLIKELY (ret != GST_FLOW_OK))
9512       goto locate_failed;
9513     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9514       /* likely EOF */
9515       ret = GST_FLOW_EOS;
9516       gst_buffer_unref (buf);
9517       goto locate_failed;
9518     }
9519     gst_buffer_map (buf, &map, GST_MAP_READ);
9520     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9521     gst_buffer_unmap (buf, &map);
9522     gst_buffer_unref (buf);
9523
9524     if (G_UNLIKELY (*length == 0)) {
9525       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9526       ret = GST_FLOW_ERROR;
9527       goto locate_failed;
9528     }
9529
9530     if (lfourcc == fourcc) {
9531       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
9532           *offset);
9533       break;
9534     } else {
9535       GST_LOG_OBJECT (qtdemux,
9536           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9537           GST_FOURCC_ARGS (fourcc), *offset);
9538       *offset += *length;
9539     }
9540   }
9541
9542   return GST_FLOW_OK;
9543
9544 locate_failed:
9545   {
9546     /* might simply have had last one */
9547     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9548     return ret;
9549   }
9550 }
9551
9552 /* should only do something in pull mode */
9553 /* call with OBJECT lock */
9554 static GstFlowReturn
9555 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9556 {
9557   guint64 length, offset;
9558   GstBuffer *buf = NULL;
9559   GstFlowReturn ret = GST_FLOW_OK;
9560   GstFlowReturn res = GST_FLOW_OK;
9561   GstMapInfo map;
9562
9563   offset = qtdemux->moof_offset;
9564   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9565
9566   if (!offset) {
9567     GST_DEBUG_OBJECT (qtdemux, "no next moof");
9568     return GST_FLOW_EOS;
9569   }
9570
9571   /* best not do pull etc with lock held */
9572   GST_OBJECT_UNLOCK (qtdemux);
9573
9574   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9575   if (ret != GST_FLOW_OK)
9576     goto flow_failed;
9577
9578   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9579   if (G_UNLIKELY (ret != GST_FLOW_OK))
9580     goto flow_failed;
9581   gst_buffer_map (buf, &map, GST_MAP_READ);
9582   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9583     gst_buffer_unmap (buf, &map);
9584     gst_buffer_unref (buf);
9585     buf = NULL;
9586     goto parse_failed;
9587   }
9588
9589   gst_buffer_unmap (buf, &map);
9590   gst_buffer_unref (buf);
9591   buf = NULL;
9592
9593   offset += length;
9594   /* look for next moof */
9595   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9596   if (G_UNLIKELY (ret != GST_FLOW_OK))
9597     goto flow_failed;
9598
9599 exit:
9600   GST_OBJECT_LOCK (qtdemux);
9601
9602   qtdemux->moof_offset = offset;
9603
9604   return res;
9605
9606 parse_failed:
9607   {
9608     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9609     offset = 0;
9610     res = GST_FLOW_ERROR;
9611     goto exit;
9612   }
9613 flow_failed:
9614   {
9615     /* maybe upstream temporarily flushing */
9616     if (ret != GST_FLOW_FLUSHING) {
9617       GST_DEBUG_OBJECT (qtdemux, "no next moof");
9618       offset = 0;
9619     } else {
9620       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9621       /* resume at current position next time */
9622     }
9623     res = ret;
9624     goto exit;
9625   }
9626 }
9627
9628 /* initialise bytereaders for stbl sub-atoms */
9629 static gboolean
9630 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9631 {
9632   stream->stbl_index = -1;      /* no samples have yet been parsed */
9633   stream->sample_index = -1;
9634
9635   /* time-to-sample atom */
9636   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9637     goto corrupt_file;
9638
9639   /* copy atom data into a new buffer for later use */
9640   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
9641
9642   /* skip version + flags */
9643   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9644       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9645     goto corrupt_file;
9646   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9647
9648   /* make sure there's enough data */
9649   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9650     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9651     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9652         stream->n_sample_times);
9653     if (!stream->n_sample_times)
9654       goto corrupt_file;
9655   }
9656
9657   /* sync sample atom */
9658   stream->stps_present = FALSE;
9659   if ((stream->stss_present =
9660           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9661               &stream->stss) ? TRUE : FALSE) == TRUE) {
9662     /* copy atom data into a new buffer for later use */
9663     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
9664
9665     /* skip version + flags */
9666     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9667         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9668       goto corrupt_file;
9669
9670     if (stream->n_sample_syncs) {
9671       /* make sure there's enough data */
9672       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9673         goto corrupt_file;
9674     }
9675
9676     /* partial sync sample atom */
9677     if ((stream->stps_present =
9678             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9679                 &stream->stps) ? TRUE : FALSE) == TRUE) {
9680       /* copy atom data into a new buffer for later use */
9681       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
9682
9683       /* skip version + flags */
9684       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9685           !gst_byte_reader_get_uint32_be (&stream->stps,
9686               &stream->n_sample_partial_syncs))
9687         goto corrupt_file;
9688
9689       /* if there are no entries, the stss table contains the real
9690        * sync samples */
9691       if (stream->n_sample_partial_syncs) {
9692         /* make sure there's enough data */
9693         if (!qt_atom_parser_has_chunks (&stream->stps,
9694                 stream->n_sample_partial_syncs, 4))
9695           goto corrupt_file;
9696       }
9697     }
9698   }
9699
9700   /* sample size */
9701   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9702     goto no_samples;
9703
9704   /* copy atom data into a new buffer for later use */
9705   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
9706
9707   /* skip version + flags */
9708   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9709       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9710     goto corrupt_file;
9711
9712   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9713     goto corrupt_file;
9714
9715   if (!stream->n_samples)
9716     goto no_samples;
9717
9718   /* sample-to-chunk atom */
9719   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9720     goto corrupt_file;
9721
9722   /* copy atom data into a new buffer for later use */
9723   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
9724
9725   /* skip version + flags */
9726   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9727       !gst_byte_reader_get_uint32_be (&stream->stsc,
9728           &stream->n_samples_per_chunk))
9729     goto corrupt_file;
9730
9731   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9732       stream->n_samples_per_chunk);
9733
9734   /* make sure there's enough data */
9735   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9736           12))
9737     goto corrupt_file;
9738
9739
9740   /* chunk offset */
9741   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9742     stream->co_size = sizeof (guint32);
9743   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9744           &stream->stco))
9745     stream->co_size = sizeof (guint64);
9746   else
9747     goto corrupt_file;
9748
9749   /* copy atom data into a new buffer for later use */
9750   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
9751
9752   /* skip version + flags */
9753   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9754     goto corrupt_file;
9755
9756   /* chunks_are_samples == TRUE means treat chunks as samples */
9757   stream->chunks_are_samples = stream->sample_size
9758       && !CUR_STREAM (stream)->sampled;
9759   if (stream->chunks_are_samples) {
9760     /* treat chunks as samples */
9761     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9762       goto corrupt_file;
9763   } else {
9764     /* skip number of entries */
9765     if (!gst_byte_reader_skip (&stream->stco, 4))
9766       goto corrupt_file;
9767
9768     /* make sure there are enough data in the stsz atom */
9769     if (!stream->sample_size) {
9770       /* different sizes for each sample */
9771       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9772         goto corrupt_file;
9773     }
9774   }
9775
9776   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9777       stream->n_samples, (guint) sizeof (QtDemuxSample),
9778       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9779
9780   if (stream->n_samples >=
9781       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9782     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9783         "be larger than %uMB (broken file?)", stream->n_samples,
9784         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9785     return FALSE;
9786   }
9787
9788   g_assert (stream->samples == NULL);
9789   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9790   if (!stream->samples) {
9791     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9792         stream->n_samples);
9793     return FALSE;
9794   }
9795
9796   /* composition time-to-sample */
9797   if ((stream->ctts_present =
9798           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9799               &stream->ctts) ? TRUE : FALSE) == TRUE) {
9800     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9801
9802     /* copy atom data into a new buffer for later use */
9803     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
9804
9805     /* skip version + flags */
9806     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9807         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9808             &stream->n_composition_times))
9809       goto corrupt_file;
9810
9811     /* make sure there's enough data */
9812     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9813             4 + 4))
9814       goto corrupt_file;
9815
9816     /* This is optional, if missing we iterate the ctts */
9817     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9818       if (!gst_byte_reader_skip (&cslg, 1 + 3)
9819           || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9820         g_free ((gpointer) cslg.data);
9821         goto corrupt_file;
9822       }
9823     } else {
9824       gint32 cslg_least = 0;
9825       guint num_entries, pos;
9826       gint i;
9827
9828       pos = gst_byte_reader_get_pos (&stream->ctts);
9829       num_entries = stream->n_composition_times;
9830
9831       stream->cslg_shift = 0;
9832
9833       for (i = 0; i < num_entries; i++) {
9834         gint32 offset;
9835
9836         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9837         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9838         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9839          * slightly inaccurate PTS could be more usable than corrupted one */
9840         if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9841           GST_WARNING_OBJECT (qtdemux,
9842               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9843               " larger than duration %" G_GUINT64_FORMAT,
9844               offset, stream->duration);
9845
9846           stream->cslg_shift = 0;
9847           stream->ctts_present = FALSE;
9848           return TRUE;
9849         }
9850
9851         if (offset < cslg_least)
9852           cslg_least = offset;
9853       }
9854
9855       if (cslg_least < 0)
9856         stream->cslg_shift = ABS (cslg_least);
9857       else
9858         stream->cslg_shift = 0;
9859
9860       /* reset the reader so we can generate sample table */
9861       gst_byte_reader_set_pos (&stream->ctts, pos);
9862     }
9863   } else {
9864     /* Ensure the cslg_shift value is consistent so we can use it
9865      * unconditionnally to produce TS and Segment */
9866     stream->cslg_shift = 0;
9867   }
9868
9869   return TRUE;
9870
9871 corrupt_file:
9872   {
9873     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9874         (_("This file is corrupt and cannot be played.")), (NULL));
9875     return FALSE;
9876   }
9877 no_samples:
9878   {
9879     gst_qtdemux_stbl_free (stream);
9880     if (!qtdemux->fragmented) {
9881       /* not quite good */
9882       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9883       return FALSE;
9884     } else {
9885       /* may pick up samples elsewhere */
9886       return TRUE;
9887     }
9888   }
9889 }
9890
9891 /* collect samples from the next sample to be parsed up to sample @n for @stream
9892  * by reading the info from @stbl
9893  *
9894  * This code can be executed from both the streaming thread and the seeking
9895  * thread so it takes the object lock to protect itself
9896  */
9897 static gboolean
9898 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9899 {
9900   gint i, j, k;
9901   QtDemuxSample *samples, *first, *cur, *last;
9902   guint32 n_samples_per_chunk;
9903   guint32 n_samples;
9904
9905   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9906       GST_FOURCC_FORMAT ", pad %s",
9907       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9908       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9909
9910   n_samples = stream->n_samples;
9911
9912   if (n >= n_samples)
9913     goto out_of_samples;
9914
9915   GST_OBJECT_LOCK (qtdemux);
9916   if (n <= stream->stbl_index)
9917     goto already_parsed;
9918
9919   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9920
9921   if (!stream->stsz.data) {
9922     /* so we already parsed and passed all the moov samples;
9923      * onto fragmented ones */
9924     g_assert (qtdemux->fragmented);
9925     goto done;
9926   }
9927
9928   /* pointer to the sample table */
9929   samples = stream->samples;
9930
9931   /* starts from -1, moves to the next sample index to parse */
9932   stream->stbl_index++;
9933
9934   /* keep track of the first and last sample to fill */
9935   first = &samples[stream->stbl_index];
9936   last = &samples[n];
9937
9938   if (!stream->chunks_are_samples) {
9939     /* set the sample sizes */
9940     if (stream->sample_size == 0) {
9941       /* different sizes for each sample */
9942       for (cur = first; cur <= last; cur++) {
9943         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9944         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9945             (guint) (cur - samples), cur->size);
9946       }
9947     } else {
9948       /* samples have the same size */
9949       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9950       for (cur = first; cur <= last; cur++)
9951         cur->size = stream->sample_size;
9952     }
9953   }
9954
9955   n_samples_per_chunk = stream->n_samples_per_chunk;
9956   cur = first;
9957
9958   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9959     guint32 last_chunk;
9960
9961     if (stream->stsc_chunk_index >= stream->last_chunk
9962         || stream->stsc_chunk_index < stream->first_chunk) {
9963       stream->first_chunk =
9964           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9965       stream->samples_per_chunk =
9966           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9967       /* starts from 1 */
9968       stream->stsd_sample_description_id =
9969           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9970
9971       /* chunk numbers are counted from 1 it seems */
9972       if (G_UNLIKELY (stream->first_chunk == 0))
9973         goto corrupt_file;
9974
9975       --stream->first_chunk;
9976
9977       /* the last chunk of each entry is calculated by taking the first chunk
9978        * of the next entry; except if there is no next, where we fake it with
9979        * INT_MAX */
9980       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9981         stream->last_chunk = G_MAXUINT32;
9982       } else {
9983         stream->last_chunk =
9984             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9985         if (G_UNLIKELY (stream->last_chunk == 0))
9986           goto corrupt_file;
9987
9988         --stream->last_chunk;
9989       }
9990
9991       GST_LOG_OBJECT (qtdemux,
9992           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9993           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9994           stream->samples_per_chunk, stream->stsd_sample_description_id);
9995
9996       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9997         goto corrupt_file;
9998
9999       if (stream->last_chunk != G_MAXUINT32) {
10000         if (!qt_atom_parser_peek_sub (&stream->stco,
10001                 stream->first_chunk * stream->co_size,
10002                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
10003                 &stream->co_chunk))
10004           goto corrupt_file;
10005
10006       } else {
10007         stream->co_chunk = stream->stco;
10008         if (!gst_byte_reader_skip (&stream->co_chunk,
10009                 stream->first_chunk * stream->co_size))
10010           goto corrupt_file;
10011       }
10012
10013       stream->stsc_chunk_index = stream->first_chunk;
10014     }
10015
10016     last_chunk = stream->last_chunk;
10017
10018     if (stream->chunks_are_samples) {
10019       cur = &samples[stream->stsc_chunk_index];
10020
10021       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10022         if (j > n) {
10023           /* save state */
10024           stream->stsc_chunk_index = j;
10025           goto done;
10026         }
10027
10028         cur->offset =
10029             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
10030             stream->co_size);
10031
10032         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
10033             "%" G_GUINT64_FORMAT, j, cur->offset);
10034
10035         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
10036             CUR_STREAM (stream)->bytes_per_frame > 0) {
10037           cur->size =
10038               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
10039               CUR_STREAM (stream)->samples_per_frame *
10040               CUR_STREAM (stream)->bytes_per_frame;
10041         } else {
10042           cur->size = stream->samples_per_chunk;
10043         }
10044
10045         GST_DEBUG_OBJECT (qtdemux,
10046             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
10047             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
10048                     stream->stco_sample_index)), cur->size);
10049
10050         cur->timestamp = stream->stco_sample_index;
10051         cur->duration = stream->samples_per_chunk;
10052         cur->keyframe = TRUE;
10053         cur++;
10054
10055         stream->stco_sample_index += stream->samples_per_chunk;
10056       }
10057       stream->stsc_chunk_index = j;
10058     } else {
10059       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10060         guint32 samples_per_chunk;
10061         guint64 chunk_offset;
10062
10063         if (!stream->stsc_sample_index
10064             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
10065                 &stream->chunk_offset))
10066           goto corrupt_file;
10067
10068         samples_per_chunk = stream->samples_per_chunk;
10069         chunk_offset = stream->chunk_offset;
10070
10071         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
10072           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
10073               G_GUINT64_FORMAT " and size %d",
10074               (guint) (cur - samples), chunk_offset, cur->size);
10075
10076           cur->offset = chunk_offset;
10077           chunk_offset += cur->size;
10078           cur++;
10079
10080           if (G_UNLIKELY (cur > last)) {
10081             /* save state */
10082             stream->stsc_sample_index = k + 1;
10083             stream->chunk_offset = chunk_offset;
10084             stream->stsc_chunk_index = j;
10085             goto done2;
10086           }
10087         }
10088         stream->stsc_sample_index = 0;
10089       }
10090       stream->stsc_chunk_index = j;
10091     }
10092     stream->stsc_index++;
10093   }
10094
10095   if (stream->chunks_are_samples)
10096     goto ctts;
10097 done2:
10098   {
10099     guint32 n_sample_times;
10100
10101     n_sample_times = stream->n_sample_times;
10102     cur = first;
10103
10104     for (i = stream->stts_index; i < n_sample_times; i++) {
10105       guint32 stts_samples;
10106       gint32 stts_duration;
10107       gint64 stts_time;
10108
10109       if (stream->stts_sample_index >= stream->stts_samples
10110           || !stream->stts_sample_index) {
10111
10112         stream->stts_samples =
10113             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10114         stream->stts_duration =
10115             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10116
10117         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10118             i, stream->stts_samples, stream->stts_duration);
10119
10120         stream->stts_sample_index = 0;
10121       }
10122
10123       stts_samples = stream->stts_samples;
10124       stts_duration = stream->stts_duration;
10125       stts_time = stream->stts_time;
10126
10127       for (j = stream->stts_sample_index; j < stts_samples; j++) {
10128         GST_DEBUG_OBJECT (qtdemux,
10129             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10130             (guint) (cur - samples), j,
10131             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10132
10133         cur->timestamp = stts_time;
10134         cur->duration = stts_duration;
10135
10136         /* avoid 32-bit wrap-around,
10137          * but still mind possible 'negative' duration */
10138         stts_time += (gint64) stts_duration;
10139         cur++;
10140
10141         if (G_UNLIKELY (cur > last)) {
10142           /* save values */
10143           stream->stts_time = stts_time;
10144           stream->stts_sample_index = j + 1;
10145           if (stream->stts_sample_index >= stream->stts_samples)
10146             stream->stts_index++;
10147           goto done3;
10148         }
10149       }
10150       stream->stts_sample_index = 0;
10151       stream->stts_time = stts_time;
10152       stream->stts_index++;
10153     }
10154     /* fill up empty timestamps with the last timestamp, this can happen when
10155      * the last samples do not decode and so we don't have timestamps for them.
10156      * We however look at the last timestamp to estimate the track length so we
10157      * need something in here. */
10158     for (; cur < last; cur++) {
10159       GST_DEBUG_OBJECT (qtdemux,
10160           "fill sample %d: timestamp %" GST_TIME_FORMAT,
10161           (guint) (cur - samples),
10162           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10163       cur->timestamp = stream->stts_time;
10164       cur->duration = -1;
10165     }
10166   }
10167 done3:
10168   {
10169     /* sample sync, can be NULL */
10170     if (stream->stss_present == TRUE) {
10171       guint32 n_sample_syncs;
10172
10173       n_sample_syncs = stream->n_sample_syncs;
10174
10175       if (!n_sample_syncs) {
10176         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10177         stream->all_keyframe = TRUE;
10178       } else {
10179         for (i = stream->stss_index; i < n_sample_syncs; i++) {
10180           /* note that the first sample is index 1, not 0 */
10181           guint32 index;
10182
10183           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10184
10185           if (G_LIKELY (index > 0 && index <= n_samples)) {
10186             index -= 1;
10187             samples[index].keyframe = TRUE;
10188             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10189             /* and exit if we have enough samples */
10190             if (G_UNLIKELY (index >= n)) {
10191               i++;
10192               break;
10193             }
10194           }
10195         }
10196         /* save state */
10197         stream->stss_index = i;
10198       }
10199
10200       /* stps marks partial sync frames like open GOP I-Frames */
10201       if (stream->stps_present == TRUE) {
10202         guint32 n_sample_partial_syncs;
10203
10204         n_sample_partial_syncs = stream->n_sample_partial_syncs;
10205
10206         /* if there are no entries, the stss table contains the real
10207          * sync samples */
10208         if (n_sample_partial_syncs) {
10209           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10210             /* note that the first sample is index 1, not 0 */
10211             guint32 index;
10212
10213             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10214
10215             if (G_LIKELY (index > 0 && index <= n_samples)) {
10216               index -= 1;
10217               samples[index].keyframe = TRUE;
10218               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10219               /* and exit if we have enough samples */
10220               if (G_UNLIKELY (index >= n)) {
10221                 i++;
10222                 break;
10223               }
10224             }
10225           }
10226           /* save state */
10227           stream->stps_index = i;
10228         }
10229       }
10230     } else {
10231       /* no stss, all samples are keyframes */
10232       stream->all_keyframe = TRUE;
10233       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10234     }
10235   }
10236
10237 ctts:
10238   /* composition time to sample */
10239   if (stream->ctts_present == TRUE) {
10240     guint32 n_composition_times;
10241     guint32 ctts_count;
10242     gint32 ctts_soffset;
10243
10244     /* Fill in the pts_offsets */
10245     cur = first;
10246     n_composition_times = stream->n_composition_times;
10247
10248     for (i = stream->ctts_index; i < n_composition_times; i++) {
10249       if (stream->ctts_sample_index >= stream->ctts_count
10250           || !stream->ctts_sample_index) {
10251         stream->ctts_count =
10252             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10253         stream->ctts_soffset =
10254             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10255         stream->ctts_sample_index = 0;
10256       }
10257
10258       ctts_count = stream->ctts_count;
10259       ctts_soffset = stream->ctts_soffset;
10260
10261       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10262         cur->pts_offset = ctts_soffset;
10263         cur++;
10264
10265         if (G_UNLIKELY (cur > last)) {
10266           /* save state */
10267           stream->ctts_sample_index = j + 1;
10268           goto done;
10269         }
10270       }
10271       stream->ctts_sample_index = 0;
10272       stream->ctts_index++;
10273     }
10274   }
10275 done:
10276   stream->stbl_index = n;
10277   /* if index has been completely parsed, free data that is no-longer needed */
10278   if (n + 1 == stream->n_samples) {
10279     gst_qtdemux_stbl_free (stream);
10280     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10281     if (qtdemux->pullbased) {
10282       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10283       while (n + 1 == stream->n_samples)
10284         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10285           break;
10286     }
10287   }
10288   GST_OBJECT_UNLOCK (qtdemux);
10289
10290   return TRUE;
10291
10292   /* SUCCESS */
10293 already_parsed:
10294   {
10295     GST_LOG_OBJECT (qtdemux,
10296         "Tried to parse up to sample %u but this sample has already been parsed",
10297         n);
10298     /* if fragmented, there may be more */
10299     if (qtdemux->fragmented && n == stream->stbl_index)
10300       goto done;
10301     GST_OBJECT_UNLOCK (qtdemux);
10302     return TRUE;
10303   }
10304   /* ERRORS */
10305 out_of_samples:
10306   {
10307     GST_LOG_OBJECT (qtdemux,
10308         "Tried to parse up to sample %u but there are only %u samples", n + 1,
10309         stream->n_samples);
10310     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10311         (_("This file is corrupt and cannot be played.")), (NULL));
10312     return FALSE;
10313   }
10314 corrupt_file:
10315   {
10316     GST_OBJECT_UNLOCK (qtdemux);
10317     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10318         (_("This file is corrupt and cannot be played.")), (NULL));
10319     return FALSE;
10320   }
10321 }
10322
10323 /* collect all segment info for @stream.
10324  */
10325 static gboolean
10326 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10327     GNode * trak)
10328 {
10329   GNode *edts;
10330   /* accept edts if they contain gaps at start and there is only
10331    * one media segment */
10332   gboolean allow_pushbased_edts = TRUE;
10333   gint media_segments_count = 0;
10334
10335   /* parse and prepare segment info from the edit list */
10336   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10337   stream->n_segments = 0;
10338   stream->segments = NULL;
10339   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10340     GNode *elst;
10341     gint n_segments;
10342     gint segment_number, entry_size;
10343     guint64 time;
10344     GstClockTime stime;
10345     const guint8 *buffer;
10346     guint8 version;
10347     guint32 size;
10348
10349     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10350     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10351       goto done;
10352
10353     buffer = elst->data;
10354
10355     size = QT_UINT32 (buffer);
10356     /* version, flags, n_segments */
10357     if (size < 16) {
10358       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10359       goto done;
10360     }
10361     version = QT_UINT8 (buffer + 8);
10362     entry_size = (version == 1) ? 20 : 12;
10363
10364     n_segments = QT_UINT32 (buffer + 12);
10365
10366     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10367       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10368       goto done;
10369     }
10370
10371     /* we might allocate a bit too much, at least allocate 1 segment */
10372     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10373
10374     /* segments always start from 0 */
10375     time = 0;
10376     stime = 0;
10377     buffer += 16;
10378     for (segment_number = 0; segment_number < n_segments; segment_number++) {
10379       guint64 duration;
10380       guint64 media_time;
10381       gboolean empty_edit = FALSE;
10382       QtDemuxSegment *segment;
10383       guint32 rate_int;
10384       GstClockTime media_start = GST_CLOCK_TIME_NONE;
10385
10386       if (version == 1) {
10387         media_time = QT_UINT64 (buffer + 8);
10388         duration = QT_UINT64 (buffer);
10389         if (media_time == G_MAXUINT64)
10390           empty_edit = TRUE;
10391       } else {
10392         media_time = QT_UINT32 (buffer + 4);
10393         duration = QT_UINT32 (buffer);
10394         if (media_time == G_MAXUINT32)
10395           empty_edit = TRUE;
10396       }
10397
10398       if (!empty_edit)
10399         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10400
10401       segment = &stream->segments[segment_number];
10402
10403       /* time and duration expressed in global timescale */
10404       segment->time = stime;
10405       if (duration != 0 || empty_edit) {
10406         /* edge case: empty edits with duration=zero are treated here.
10407          * (files should not have these anyway). */
10408
10409         /* add non scaled values so we don't cause roundoff errors */
10410         time += duration;
10411         stime = QTTIME_TO_GSTTIME (qtdemux, time);
10412         segment->duration = stime - segment->time;
10413       } else {
10414         /* zero duration does not imply media_start == media_stop
10415          * but, only specify media_start. The edit ends with the track. */
10416         stime = segment->duration = GST_CLOCK_TIME_NONE;
10417         /* Don't allow more edits after this one. */
10418         n_segments = segment_number + 1;
10419       }
10420       segment->stop_time = stime;
10421
10422       segment->trak_media_start = media_time;
10423       /* media_time expressed in stream timescale */
10424       if (!empty_edit) {
10425         segment->media_start = media_start;
10426         segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10427             ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10428         media_segments_count++;
10429       } else {
10430         segment->media_start = GST_CLOCK_TIME_NONE;
10431         segment->media_stop = GST_CLOCK_TIME_NONE;
10432       }
10433       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10434
10435       if (rate_int <= 1) {
10436         /* 0 is not allowed, some programs write 1 instead of the floating point
10437          * value */
10438         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10439             rate_int);
10440         segment->rate = 1;
10441       } else {
10442         segment->rate = rate_int / 65536.0;
10443       }
10444
10445       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10446           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10447           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10448           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10449           segment_number, GST_TIME_ARGS (segment->time),
10450           GST_TIME_ARGS (segment->duration),
10451           GST_TIME_ARGS (segment->media_start), media_time,
10452           GST_TIME_ARGS (segment->media_stop),
10453           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10454           stream->timescale);
10455       if (segment->stop_time > qtdemux->segment.stop &&
10456           !qtdemux->upstream_format_is_time) {
10457         GST_WARNING_OBJECT (qtdemux, "Segment %d "
10458             " extends to %" GST_TIME_FORMAT
10459             " past the end of the declared movie duration %" GST_TIME_FORMAT
10460             " movie segment will be extended", segment_number,
10461             GST_TIME_ARGS (segment->stop_time),
10462             GST_TIME_ARGS (qtdemux->segment.stop));
10463         qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10464       }
10465
10466       buffer += entry_size;
10467     }
10468     GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10469     stream->n_segments = n_segments;
10470     if (media_segments_count != 1)
10471       allow_pushbased_edts = FALSE;
10472   }
10473 done:
10474
10475   /* push based does not handle segments, so act accordingly here,
10476    * and warn if applicable */
10477   if (!qtdemux->pullbased && !allow_pushbased_edts) {
10478     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10479     /* remove and use default one below, we stream like it anyway */
10480     g_free (stream->segments);
10481     stream->segments = NULL;
10482     stream->n_segments = 0;
10483   }
10484
10485   /* no segments, create one to play the complete trak */
10486   if (stream->n_segments == 0) {
10487     GstClockTime stream_duration =
10488         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10489
10490     if (stream->segments == NULL)
10491       stream->segments = g_new (QtDemuxSegment, 1);
10492
10493     /* represent unknown our way */
10494     if (stream_duration == 0)
10495       stream_duration = GST_CLOCK_TIME_NONE;
10496
10497     stream->segments[0].time = 0;
10498     stream->segments[0].stop_time = stream_duration;
10499     stream->segments[0].duration = stream_duration;
10500     stream->segments[0].media_start = 0;
10501     stream->segments[0].media_stop = stream_duration;
10502     stream->segments[0].rate = 1.0;
10503     stream->segments[0].trak_media_start = 0;
10504
10505     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10506         GST_TIME_ARGS (stream_duration));
10507     stream->n_segments = 1;
10508     stream->dummy_segment = TRUE;
10509   }
10510   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10511
10512   return TRUE;
10513 }
10514
10515 /*
10516  * Parses the stsd atom of a svq3 trak looking for
10517  * the SMI and gama atoms.
10518  */
10519 static void
10520 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10521     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10522 {
10523   const guint8 *_gamma = NULL;
10524   GstBuffer *_seqh = NULL;
10525   const guint8 *stsd_data = stsd_entry_data;
10526   guint32 length = QT_UINT32 (stsd_data);
10527   guint16 version;
10528
10529   if (length < 32) {
10530     GST_WARNING_OBJECT (qtdemux, "stsd too short");
10531     goto end;
10532   }
10533
10534   stsd_data += 16;
10535   length -= 16;
10536   version = QT_UINT16 (stsd_data);
10537   if (version == 3) {
10538     if (length >= 70) {
10539       length -= 70;
10540       stsd_data += 70;
10541       while (length > 8) {
10542         guint32 fourcc, size;
10543         const guint8 *data;
10544         size = QT_UINT32 (stsd_data);
10545         fourcc = QT_FOURCC (stsd_data + 4);
10546         data = stsd_data + 8;
10547
10548         if (size == 0) {
10549           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10550               "svq3 atom parsing");
10551           goto end;
10552         }
10553
10554         switch (fourcc) {
10555           case FOURCC_gama:{
10556             if (size == 12) {
10557               _gamma = data;
10558             } else {
10559               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10560                   " for gama atom, expected 12", size);
10561             }
10562             break;
10563           }
10564           case FOURCC_SMI_:{
10565             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10566               guint32 seqh_size;
10567               if (_seqh != NULL) {
10568                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10569                     " found, ignoring");
10570               } else {
10571                 seqh_size = QT_UINT32 (data + 4);
10572                 if (seqh_size > 0) {
10573                   _seqh = gst_buffer_new_and_alloc (seqh_size);
10574                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10575                 }
10576               }
10577             }
10578             break;
10579           }
10580           default:{
10581             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10582                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10583           }
10584         }
10585
10586         if (size <= length) {
10587           length -= size;
10588           stsd_data += size;
10589         }
10590       }
10591     } else {
10592       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10593     }
10594   } else {
10595     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10596         G_GUINT16_FORMAT, version);
10597     goto end;
10598   }
10599
10600 end:
10601   if (gamma) {
10602     *gamma = _gamma;
10603   }
10604   if (seqh) {
10605     *seqh = _seqh;
10606   } else if (_seqh) {
10607     gst_buffer_unref (_seqh);
10608   }
10609 }
10610
10611 static gchar *
10612 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10613 {
10614   GNode *dinf;
10615   GstByteReader dref;
10616   gchar *uri = NULL;
10617
10618   /*
10619    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10620    * atom that might contain a 'data' atom with the rtsp uri.
10621    * This case was reported in bug #597497, some info about
10622    * the hndl atom can be found in TN1195
10623    */
10624   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10625   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10626
10627   if (dinf) {
10628     guint32 dref_num_entries = 0;
10629     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10630         gst_byte_reader_skip (&dref, 4) &&
10631         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10632       gint i;
10633
10634       /* search dref entries for hndl atom */
10635       for (i = 0; i < dref_num_entries; i++) {
10636         guint32 size = 0, type;
10637         guint8 string_len = 0;
10638         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10639             qt_atom_parser_get_fourcc (&dref, &type)) {
10640           if (type == FOURCC_hndl) {
10641             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10642
10643             /* skip data reference handle bytes and the
10644              * following pascal string and some extra 4
10645              * bytes I have no idea what are */
10646             if (!gst_byte_reader_skip (&dref, 4) ||
10647                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10648                 !gst_byte_reader_skip (&dref, string_len + 4)) {
10649               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10650               break;
10651             }
10652
10653             /* iterate over the atoms to find the data atom */
10654             while (gst_byte_reader_get_remaining (&dref) >= 8) {
10655               guint32 atom_size;
10656               guint32 atom_type;
10657
10658               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10659                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10660                 if (atom_type == FOURCC_data) {
10661                   const guint8 *uri_aux = NULL;
10662
10663                   /* found the data atom that might contain the rtsp uri */
10664                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10665                       "hndl atom, interpreting it as an URI");
10666                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10667                           &uri_aux)) {
10668                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10669                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10670                     else
10671                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10672                           "didn't contain a rtsp address");
10673                   } else {
10674                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10675                         "atom contents");
10676                   }
10677                   break;
10678                 }
10679                 /* skipping to the next entry */
10680                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10681                   break;
10682               } else {
10683                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10684                     "atom header");
10685                 break;
10686               }
10687             }
10688             break;
10689           }
10690           /* skip to the next entry */
10691           if (!gst_byte_reader_skip (&dref, size - 8))
10692             break;
10693         } else {
10694           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10695         }
10696       }
10697       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10698     }
10699   }
10700   return uri;
10701 }
10702
10703 #define AMR_NB_ALL_MODES        0x81ff
10704 #define AMR_WB_ALL_MODES        0x83ff
10705 static guint
10706 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10707 {
10708   /* The 'damr' atom is of the form:
10709    *
10710    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10711    *    32 b       8 b          16 b           8 b                 8 b
10712    *
10713    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10714    * represents the highest mode used in the stream (and thus the maximum
10715    * bitrate), with a couple of special cases as seen below.
10716    */
10717
10718   /* Map of frame type ID -> bitrate */
10719   static const guint nb_bitrates[] = {
10720     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10721   };
10722   static const guint wb_bitrates[] = {
10723     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10724   };
10725   GstMapInfo map;
10726   gsize max_mode;
10727   guint16 mode_set;
10728
10729   gst_buffer_map (buf, &map, GST_MAP_READ);
10730
10731   if (map.size != 0x11) {
10732     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10733     goto bad_data;
10734   }
10735
10736   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10737     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10738         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10739     goto bad_data;
10740   }
10741
10742   mode_set = QT_UINT16 (map.data + 13);
10743
10744   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10745     max_mode = 7 + (wb ? 1 : 0);
10746   else
10747     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10748     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10749
10750   if (max_mode == -1) {
10751     GST_DEBUG ("No mode indication was found (mode set) = %x",
10752         (guint) mode_set);
10753     goto bad_data;
10754   }
10755
10756   gst_buffer_unmap (buf, &map);
10757   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10758
10759 bad_data:
10760   gst_buffer_unmap (buf, &map);
10761   return 0;
10762 }
10763
10764 static gboolean
10765 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10766     GstByteReader * reader, guint32 * matrix, const gchar * atom)
10767 {
10768   /*
10769    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10770    * [0 1 2]
10771    * [3 4 5]
10772    * [6 7 8]
10773    */
10774
10775   if (gst_byte_reader_get_remaining (reader) < 36)
10776     return FALSE;
10777
10778   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10779   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10780   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10781   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10782   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10783   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10784   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10785   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10786   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10787
10788   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10789   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10790       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10791       matrix[2] & 0xFF);
10792   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10793       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10794       matrix[5] & 0xFF);
10795   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10796       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10797       matrix[8] & 0xFF);
10798
10799   return TRUE;
10800 }
10801
10802 static void
10803 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10804     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10805 {
10806
10807 /* [a b c]
10808  * [d e f]
10809  * [g h i]
10810  *
10811  * This macro will only compare value abdegh, it expects cfi to have already
10812  * been checked
10813  */
10814 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10815                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
10816
10817   /* only handle the cases where the last column has standard values */
10818   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10819     const gchar *rotation_tag = NULL;
10820
10821     /* no rotation needed */
10822     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10823       /* NOP */
10824     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10825       rotation_tag = "rotate-90";
10826     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10827       rotation_tag = "rotate-180";
10828     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10829       rotation_tag = "rotate-270";
10830     } else {
10831       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10832     }
10833
10834     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10835         rotation_tag);
10836     if (rotation_tag != NULL) {
10837       if (*taglist == NULL)
10838         *taglist = gst_tag_list_new_empty ();
10839       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10840           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10841     }
10842   } else {
10843     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10844   }
10845 }
10846
10847 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10848  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10849  * Common Encryption (cenc), the function will also parse the tenc box (defined
10850  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10851  * (typically an enc[v|a|t|s] sample entry); the function will set
10852  * @original_fmt to the fourcc of the original unencrypted stream format.
10853  * Returns TRUE if successful; FALSE otherwise. */
10854 static gboolean
10855 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10856     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10857 {
10858   GNode *sinf;
10859   GNode *frma;
10860   GNode *schm;
10861   GNode *schi;
10862   QtDemuxCencSampleSetInfo *info;
10863   GNode *tenc;
10864   const guint8 *tenc_data;
10865
10866   g_return_val_if_fail (qtdemux != NULL, FALSE);
10867   g_return_val_if_fail (stream != NULL, FALSE);
10868   g_return_val_if_fail (container != NULL, FALSE);
10869   g_return_val_if_fail (original_fmt != NULL, FALSE);
10870
10871   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10872   if (G_UNLIKELY (!sinf)) {
10873     if (stream->protection_scheme_type == FOURCC_cenc) {
10874       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10875           "mandatory for Common Encryption");
10876       return FALSE;
10877     }
10878     return TRUE;
10879   }
10880
10881   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10882   if (G_UNLIKELY (!frma)) {
10883     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10884     return FALSE;
10885   }
10886
10887   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10888   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10889       GST_FOURCC_ARGS (*original_fmt));
10890
10891   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10892   if (!schm) {
10893     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10894     return FALSE;
10895   }
10896   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10897   stream->protection_scheme_version =
10898       QT_UINT32 ((const guint8 *) schm->data + 16);
10899
10900   GST_DEBUG_OBJECT (qtdemux,
10901       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10902       "protection_scheme_version: %#010x",
10903       GST_FOURCC_ARGS (stream->protection_scheme_type),
10904       stream->protection_scheme_version);
10905
10906   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10907   if (!schi) {
10908     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10909     return FALSE;
10910   }
10911   if (stream->protection_scheme_type != FOURCC_cenc &&
10912       stream->protection_scheme_type != FOURCC_piff) {
10913     GST_ERROR_OBJECT (qtdemux,
10914         "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10915         GST_FOURCC_ARGS (stream->protection_scheme_type));
10916     return FALSE;
10917   }
10918
10919   if (G_UNLIKELY (!stream->protection_scheme_info))
10920     stream->protection_scheme_info =
10921         g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10922
10923   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10924
10925   if (stream->protection_scheme_type == FOURCC_cenc) {
10926     guint32 is_encrypted;
10927     guint8 iv_size;
10928     const guint8 *default_kid;
10929
10930     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10931     if (!tenc) {
10932       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10933           "which is mandatory for Common Encryption");
10934       return FALSE;
10935     }
10936     tenc_data = (const guint8 *) tenc->data + 12;
10937     is_encrypted = QT_UINT24 (tenc_data);
10938     iv_size = QT_UINT8 (tenc_data + 3);
10939     default_kid = (tenc_data + 4);
10940     qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10941         is_encrypted, iv_size, default_kid);
10942   } else if (stream->protection_scheme_type == FOURCC_piff) {
10943     GstByteReader br;
10944     static const guint8 piff_track_encryption_uuid[] = {
10945       0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10946       0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10947     };
10948
10949     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10950     if (!tenc) {
10951       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10952           "which is mandatory for Common Encryption");
10953       return FALSE;
10954     }
10955
10956     tenc_data = (const guint8 *) tenc->data + 8;
10957     if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10958       gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10959       GST_ERROR_OBJECT (qtdemux,
10960           "Unsupported track encryption box with uuid: %s", box_uuid);
10961       g_free (box_uuid);
10962       return FALSE;
10963     }
10964     tenc_data = (const guint8 *) tenc->data + 16 + 12;
10965     gst_byte_reader_init (&br, tenc_data, 20);
10966     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10967       GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10968       return FALSE;
10969     }
10970     stream->protection_scheme_type = FOURCC_cenc;
10971   }
10972
10973   return TRUE;
10974 }
10975
10976 static gint
10977 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10978     QtDemuxStream ** stream2)
10979 {
10980   return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10981 }
10982
10983 /* parse the traks.
10984  * With each track we associate a new QtDemuxStream that contains all the info
10985  * about the trak.
10986  * traks that do not decode to something (like strm traks) will not have a pad.
10987  */
10988 static gboolean
10989 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10990 {
10991   GstByteReader tkhd;
10992   int offset;
10993   GNode *mdia;
10994   GNode *mdhd;
10995   GNode *hdlr;
10996   GNode *minf;
10997   GNode *stbl;
10998   GNode *stsd;
10999   GNode *mp4a;
11000   GNode *mp4v;
11001   GNode *esds;
11002   GNode *tref;
11003   GNode *udta;
11004   GNode *svmi;
11005
11006   QtDemuxStream *stream = NULL;
11007   const guint8 *stsd_data;
11008   const guint8 *stsd_entry_data;
11009   guint remaining_stsd_len;
11010   guint stsd_entry_count;
11011   guint stsd_index;
11012   guint16 lang_code;            /* quicktime lang code or packed iso code */
11013   guint32 version;
11014   guint32 tkhd_flags = 0;
11015   guint8 tkhd_version = 0;
11016   guint32 w = 0, h = 0;
11017   guint value_size, stsd_len, len;
11018   guint32 track_id;
11019   guint32 dummy;
11020
11021   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11022
11023   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11024       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11025       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11026     goto corrupt_file;
11027
11028   /* pick between 64 or 32 bits */
11029   value_size = tkhd_version == 1 ? 8 : 4;
11030   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11031       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11032     goto corrupt_file;
11033
11034   /* Check if current moov has duplicated track_id */
11035   if (qtdemux_find_stream (qtdemux, track_id))
11036     goto existing_stream;
11037
11038   stream = _create_stream (qtdemux, track_id);
11039   stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11040
11041   /* need defaults for fragments */
11042   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11043
11044   if ((tkhd_flags & 1) == 0)
11045     stream->disabled = TRUE;
11046
11047   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11048       tkhd_version, tkhd_flags, stream->track_id);
11049
11050   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11051     goto corrupt_file;
11052
11053   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11054     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11055     if (qtdemux->major_brand != FOURCC_mjp2 ||
11056         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11057       goto corrupt_file;
11058   }
11059
11060   len = QT_UINT32 ((guint8 *) mdhd->data);
11061   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11062   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11063   if (version == 0x01000000) {
11064     if (len < 42)
11065       goto corrupt_file;
11066     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11067     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11068     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11069   } else {
11070     if (len < 30)
11071       goto corrupt_file;
11072     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11073     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11074     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11075   }
11076
11077   if (lang_code < 0x400) {
11078     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11079   } else if (lang_code == 0x7fff) {
11080     stream->lang_id[0] = 0;     /* unspecified */
11081   } else {
11082     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11083     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11084     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11085     stream->lang_id[3] = 0;
11086   }
11087
11088   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11089       stream->timescale);
11090   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11091       stream->duration);
11092   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11093       lang_code, stream->lang_id);
11094
11095   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11096     goto corrupt_file;
11097
11098   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11099     /* chapters track reference */
11100     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11101     if (chap) {
11102       gsize length = GST_READ_UINT32_BE (chap->data);
11103       if (qtdemux->chapters_track_id)
11104         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11105
11106       if (length >= 12) {
11107         qtdemux->chapters_track_id =
11108             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11109       }
11110     }
11111   }
11112
11113   /* fragmented files may have bogus duration in moov */
11114   if (!qtdemux->fragmented &&
11115       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11116     guint64 tdur1, tdur2;
11117
11118     /* don't overflow */
11119     tdur1 = stream->timescale * (guint64) qtdemux->duration;
11120     tdur2 = qtdemux->timescale * (guint64) stream->duration;
11121
11122     /* HACK:
11123      * some of those trailers, nowadays, have prologue images that are
11124      * themselves video tracks as well. I haven't really found a way to
11125      * identify those yet, except for just looking at their duration. */
11126     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11127       GST_WARNING_OBJECT (qtdemux,
11128           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11129           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11130           "found, assuming preview image or something; skipping track",
11131           stream->duration, stream->timescale, qtdemux->duration,
11132           qtdemux->timescale);
11133       gst_qtdemux_stream_unref (stream);
11134       return TRUE;
11135     }
11136   }
11137
11138   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11139     goto corrupt_file;
11140
11141   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11142       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11143
11144   len = QT_UINT32 ((guint8 *) hdlr->data);
11145   if (len >= 20)
11146     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11147   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11148       GST_FOURCC_ARGS (stream->subtype));
11149
11150   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11151     goto corrupt_file;
11152
11153   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11154     goto corrupt_file;
11155
11156   /*parse svmi header if existing */
11157   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
11158   if (svmi) {
11159     len = QT_UINT32 ((guint8 *) svmi->data);
11160     version = QT_UINT32 ((guint8 *) svmi->data + 8);
11161     if (!version) {
11162       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
11163       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
11164       guint8 frame_type, frame_layout;
11165
11166       /* MPEG-A stereo video */
11167       if (qtdemux->major_brand == FOURCC_ss02)
11168         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
11169
11170       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
11171       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
11172       switch (frame_type) {
11173         case 0:
11174           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11175           break;
11176         case 1:
11177           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11178           break;
11179         case 2:
11180           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11181           break;
11182         case 3:
11183           /* mode 3 is primary/secondary view sequence, ie
11184            * left/right views in separate tracks. See section 7.2
11185            * of ISO/IEC 23000-11:2009 */
11186           GST_FIXME_OBJECT (qtdemux,
11187               "Implement stereo video in separate streams");
11188       }
11189
11190       if ((frame_layout & 0x1) == 0)
11191         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11192
11193       GST_LOG_OBJECT (qtdemux,
11194           "StereoVideo: composition type: %u, is_left_first: %u",
11195           frame_type, frame_layout);
11196       stream->multiview_mode = mode;
11197       stream->multiview_flags = flags;
11198     }
11199   }
11200
11201   /* parse rest of tkhd */
11202   if (stream->subtype == FOURCC_vide) {
11203     guint32 matrix[9];
11204
11205     /* version 1 uses some 64-bit ints */
11206     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11207       goto corrupt_file;
11208
11209     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11210       goto corrupt_file;
11211
11212     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11213         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11214       goto corrupt_file;
11215
11216     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11217         &stream->stream_tags);
11218   }
11219
11220   /* parse stsd */
11221   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11222     goto corrupt_file;
11223   stsd_data = (const guint8 *) stsd->data;
11224
11225   /* stsd should at least have one entry */
11226   stsd_len = QT_UINT32 (stsd_data);
11227   if (stsd_len < 24) {
11228     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11229     if (stream->subtype == FOURCC_vivo) {
11230       gst_qtdemux_stream_unref (stream);
11231       return TRUE;
11232     } else {
11233       goto corrupt_file;
11234     }
11235   }
11236
11237   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11238   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11239   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
11240   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
11241
11242   stsd_entry_data = stsd_data + 16;
11243   remaining_stsd_len = stsd_len - 16;
11244   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11245     guint32 fourcc;
11246     gchar *codec = NULL;
11247     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11248
11249     /* and that entry should fit within stsd */
11250     len = QT_UINT32 (stsd_entry_data);
11251     if (len > remaining_stsd_len)
11252       goto corrupt_file;
11253
11254     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11255     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
11256         GST_FOURCC_ARGS (entry->fourcc));
11257     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
11258
11259     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11260       goto error_encrypted;
11261
11262     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11263       /* FIXME this looks wrong, there might be multiple children
11264        * with the same type */
11265       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11266       stream->protected = TRUE;
11267       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11268         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11269     }
11270
11271     if (stream->subtype == FOURCC_vide) {
11272       GNode *colr;
11273       GNode *fiel;
11274       GNode *pasp;
11275       gboolean gray;
11276       gint depth, palette_size, palette_count;
11277       guint32 *palette_data = NULL;
11278
11279       entry->sampled = TRUE;
11280
11281       stream->display_width = w >> 16;
11282       stream->display_height = h >> 16;
11283
11284       offset = 16;
11285       if (len < 86)             /* TODO verify */
11286         goto corrupt_file;
11287
11288       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11289       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11290       entry->fps_n = 0;         /* this is filled in later */
11291       entry->fps_d = 0;         /* this is filled in later */
11292       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11293       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11294
11295       /* if color_table_id is 0, ctab atom must follow; however some files
11296        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11297        * if color table is not present we'll correct the value */
11298       if (entry->color_table_id == 0 &&
11299           (len < 90
11300               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11301         entry->color_table_id = -1;
11302       }
11303
11304       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11305           entry->width, entry->height, entry->bits_per_sample,
11306           entry->color_table_id);
11307
11308       depth = entry->bits_per_sample;
11309
11310       /* more than 32 bits means grayscale */
11311       gray = (depth > 32);
11312       /* low 32 bits specify the depth  */
11313       depth &= 0x1F;
11314
11315       /* different number of palette entries is determined by depth. */
11316       palette_count = 0;
11317       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11318         palette_count = (1 << depth);
11319       palette_size = palette_count * 4;
11320
11321       if (entry->color_table_id) {
11322         switch (palette_count) {
11323           case 0:
11324             break;
11325           case 2:
11326             palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
11327             break;
11328           case 4:
11329             palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
11330             break;
11331           case 16:
11332             if (gray)
11333               palette_data =
11334                   g_memdup (ff_qt_grayscale_palette_16, palette_size);
11335             else
11336               palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
11337             break;
11338           case 256:
11339             if (gray)
11340               palette_data =
11341                   g_memdup (ff_qt_grayscale_palette_256, palette_size);
11342             else
11343               palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
11344             break;
11345           default:
11346             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11347                 (_("The video in this file might not play correctly.")),
11348                 ("unsupported palette depth %d", depth));
11349             break;
11350         }
11351       } else {
11352         gint i, j, start, end;
11353
11354         if (len < 94)
11355           goto corrupt_file;
11356
11357         /* read table */
11358         start = QT_UINT32 (stsd_entry_data + offset + 70);
11359         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11360         end = QT_UINT16 (stsd_entry_data + offset + 76);
11361
11362         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11363             start, end, palette_count);
11364
11365         if (end > 255)
11366           end = 255;
11367         if (start > end)
11368           start = end;
11369
11370         if (len < 94 + (end - start) * 8)
11371           goto corrupt_file;
11372
11373         /* palette is always the same size */
11374         palette_data = g_malloc0 (256 * 4);
11375         palette_size = 256 * 4;
11376
11377         for (j = 0, i = start; i <= end; j++, i++) {
11378           guint32 a, r, g, b;
11379
11380           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11381           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11382           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11383           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11384
11385           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11386               (g & 0xff00) | (b >> 8);
11387         }
11388       }
11389
11390       if (entry->caps)
11391         gst_caps_unref (entry->caps);
11392
11393       entry->caps =
11394           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11395           &codec);
11396       if (G_UNLIKELY (!entry->caps)) {
11397         g_free (palette_data);
11398         goto unknown_stream;
11399       }
11400
11401       if (codec) {
11402         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11403             GST_TAG_VIDEO_CODEC, codec, NULL);
11404         g_free (codec);
11405         codec = NULL;
11406       }
11407
11408       if (palette_data) {
11409         GstStructure *s;
11410
11411         if (entry->rgb8_palette)
11412           gst_memory_unref (entry->rgb8_palette);
11413         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11414             palette_data, palette_size, 0, palette_size, palette_data, g_free);
11415
11416         s = gst_caps_get_structure (entry->caps, 0);
11417
11418         /* non-raw video has a palette_data property. raw video has the palette as
11419          * an extra plane that we append to the output buffers before we push
11420          * them*/
11421         if (!gst_structure_has_name (s, "video/x-raw")) {
11422           GstBuffer *palette;
11423
11424           palette = gst_buffer_new ();
11425           gst_buffer_append_memory (palette, entry->rgb8_palette);
11426           entry->rgb8_palette = NULL;
11427
11428           gst_caps_set_simple (entry->caps, "palette_data",
11429               GST_TYPE_BUFFER, palette, NULL);
11430           gst_buffer_unref (palette);
11431         }
11432       } else if (palette_count != 0) {
11433         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11434             (NULL), ("Unsupported palette depth %d", depth));
11435       }
11436
11437       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
11438           QT_UINT16 (stsd_entry_data + offset + 32));
11439
11440       esds = NULL;
11441       pasp = NULL;
11442       colr = NULL;
11443       fiel = NULL;
11444       /* pick 'the' stsd child */
11445       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11446       // We should skip parsing the stsd for non-protected streams if
11447       // the entry doesn't match the fourcc, since they don't change
11448       // format. However, for protected streams we can have partial
11449       // encryption, where parts of the stream are encrypted and parts
11450       // not. For both parts of such streams, we should ensure the
11451       // esds overrides are parsed for both from the stsd.
11452       if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11453         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11454           mp4v = NULL;
11455         else if (!stream->protected)
11456           mp4v = NULL;
11457       }
11458
11459       if (mp4v) {
11460         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11461         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11462         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11463         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11464       }
11465
11466       if (pasp) {
11467         const guint8 *pasp_data = (const guint8 *) pasp->data;
11468         gint len = QT_UINT32 (pasp_data);
11469
11470         if (len == 16) {
11471           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11472           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11473         } else {
11474           CUR_STREAM (stream)->par_w = 0;
11475           CUR_STREAM (stream)->par_h = 0;
11476         }
11477       } else {
11478         CUR_STREAM (stream)->par_w = 0;
11479         CUR_STREAM (stream)->par_h = 0;
11480       }
11481
11482       if (fiel) {
11483         const guint8 *fiel_data = (const guint8 *) fiel->data;
11484         gint len = QT_UINT32 (fiel_data);
11485
11486         if (len == 10) {
11487           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11488           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11489         }
11490       }
11491
11492       if (colr) {
11493         const guint8 *colr_data = (const guint8 *) colr->data;
11494         gint len = QT_UINT32 (colr_data);
11495
11496         if (len == 19 || len == 18) {
11497           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11498
11499           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11500             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11501             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11502             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11503             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11504
11505             switch (primaries) {
11506               case 1:
11507                 CUR_STREAM (stream)->colorimetry.primaries =
11508                     GST_VIDEO_COLOR_PRIMARIES_BT709;
11509                 break;
11510               case 5:
11511                 CUR_STREAM (stream)->colorimetry.primaries =
11512                     GST_VIDEO_COLOR_PRIMARIES_BT470BG;
11513                 break;
11514               case 6:
11515                 CUR_STREAM (stream)->colorimetry.primaries =
11516                     GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
11517                 break;
11518               case 9:
11519                 CUR_STREAM (stream)->colorimetry.primaries =
11520                     GST_VIDEO_COLOR_PRIMARIES_BT2020;
11521                 break;
11522               default:
11523                 break;
11524             }
11525
11526             switch (transfer_function) {
11527               case 1:
11528                 CUR_STREAM (stream)->colorimetry.transfer =
11529                     GST_VIDEO_TRANSFER_BT709;
11530                 break;
11531               case 7:
11532                 CUR_STREAM (stream)->colorimetry.transfer =
11533                     GST_VIDEO_TRANSFER_SMPTE240M;
11534                 break;
11535               default:
11536                 break;
11537             }
11538
11539             switch (matrix) {
11540               case 1:
11541                 CUR_STREAM (stream)->colorimetry.matrix =
11542                     GST_VIDEO_COLOR_MATRIX_BT709;
11543                 break;
11544               case 6:
11545                 CUR_STREAM (stream)->colorimetry.matrix =
11546                     GST_VIDEO_COLOR_MATRIX_BT601;
11547                 break;
11548               case 7:
11549                 CUR_STREAM (stream)->colorimetry.matrix =
11550                     GST_VIDEO_COLOR_MATRIX_SMPTE240M;
11551                 break;
11552               case 9:
11553                 CUR_STREAM (stream)->colorimetry.matrix =
11554                     GST_VIDEO_COLOR_MATRIX_BT2020;
11555                 break;
11556               default:
11557                 break;
11558             }
11559
11560             CUR_STREAM (stream)->colorimetry.range =
11561                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11562                 GST_VIDEO_COLOR_RANGE_16_235;
11563           } else {
11564             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11565           }
11566         } else {
11567           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11568         }
11569       }
11570
11571       if (esds) {
11572         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11573             stream->stream_tags);
11574       } else {
11575         switch (fourcc) {
11576           case FOURCC_H264:
11577           case FOURCC_avc1:
11578           case FOURCC_avc3:
11579           {
11580             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11581             const guint8 *avc_data = stsd_entry_data + 0x56;
11582
11583             /* find avcC */
11584             while (len >= 0x8) {
11585               gint size;
11586
11587               if (QT_UINT32 (avc_data) <= len)
11588                 size = QT_UINT32 (avc_data) - 0x8;
11589               else
11590                 size = len - 0x8;
11591
11592               if (size < 1)
11593                 /* No real data, so break out */
11594                 break;
11595
11596               switch (QT_FOURCC (avc_data + 0x4)) {
11597                 case FOURCC_avcC:
11598                 {
11599                   /* parse, if found */
11600                   GstBuffer *buf;
11601
11602                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11603
11604                   /* First 4 bytes are the length of the atom, the next 4 bytes
11605                    * are the fourcc, the next 1 byte is the version, and the
11606                    * subsequent bytes are profile_tier_level structure like data. */
11607                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11608                       avc_data + 8 + 1, size - 1);
11609                   buf = gst_buffer_new_and_alloc (size);
11610                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11611                   gst_caps_set_simple (entry->caps,
11612                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11613                   gst_buffer_unref (buf);
11614
11615                   break;
11616                 }
11617                 case FOURCC_strf:
11618                 {
11619                   GstBuffer *buf;
11620
11621                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11622
11623                   /* First 4 bytes are the length of the atom, the next 4 bytes
11624                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11625                    * next 1 byte is the version, and the
11626                    * subsequent bytes are sequence parameter set like data. */
11627
11628                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
11629                   if (size > 1) {
11630                     gst_codec_utils_h264_caps_set_level_and_profile
11631                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11632
11633                     buf = gst_buffer_new_and_alloc (size);
11634                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11635                     gst_caps_set_simple (entry->caps,
11636                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
11637                     gst_buffer_unref (buf);
11638                   }
11639                   break;
11640                 }
11641                 case FOURCC_btrt:
11642                 {
11643                   guint avg_bitrate, max_bitrate;
11644
11645                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11646                   if (size < 12)
11647                     break;
11648
11649                   max_bitrate = QT_UINT32 (avc_data + 0xc);
11650                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
11651
11652                   if (!max_bitrate && !avg_bitrate)
11653                     break;
11654
11655                   /* Some muxers seem to swap the average and maximum bitrates
11656                    * (I'm looking at you, YouTube), so we swap for sanity. */
11657                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11658                     guint temp = avg_bitrate;
11659
11660                     avg_bitrate = max_bitrate;
11661                     max_bitrate = temp;
11662                   }
11663
11664                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11665                     gst_tag_list_add (stream->stream_tags,
11666                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11667                         max_bitrate, NULL);
11668                   }
11669                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11670                     gst_tag_list_add (stream->stream_tags,
11671                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11672                         NULL);
11673                   }
11674
11675                   break;
11676                 }
11677
11678                 default:
11679                   break;
11680               }
11681
11682               len -= size + 8;
11683               avc_data += size + 8;
11684             }
11685
11686             break;
11687           }
11688           case FOURCC_H265:
11689           case FOURCC_hvc1:
11690           case FOURCC_hev1:
11691           {
11692             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11693             const guint8 *hevc_data = stsd_entry_data + 0x56;
11694
11695             /* find hevc */
11696             while (len >= 0x8) {
11697               gint size;
11698
11699               if (QT_UINT32 (hevc_data) <= len)
11700                 size = QT_UINT32 (hevc_data) - 0x8;
11701               else
11702                 size = len - 0x8;
11703
11704               if (size < 1)
11705                 /* No real data, so break out */
11706                 break;
11707
11708               switch (QT_FOURCC (hevc_data + 0x4)) {
11709                 case FOURCC_hvcC:
11710                 {
11711                   /* parse, if found */
11712                   GstBuffer *buf;
11713
11714                   GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11715
11716                   /* First 4 bytes are the length of the atom, the next 4 bytes
11717                    * are the fourcc, the next 1 byte is the version, and the
11718                    * subsequent bytes are sequence parameter set like data. */
11719                   gst_codec_utils_h265_caps_set_level_tier_and_profile
11720                       (entry->caps, hevc_data + 8 + 1, size - 1);
11721
11722                   buf = gst_buffer_new_and_alloc (size);
11723                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11724                   gst_caps_set_simple (entry->caps,
11725                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11726                   gst_buffer_unref (buf);
11727                   break;
11728                 }
11729                 default:
11730                   break;
11731               }
11732               len -= size + 8;
11733               hevc_data += size + 8;
11734             }
11735             break;
11736           }
11737           case FOURCC_mp4v:
11738           case FOURCC_MP4V:
11739           case FOURCC_fmp4:
11740           case FOURCC_FMP4:
11741           case FOURCC_xvid:
11742           case FOURCC_XVID:
11743           {
11744             GNode *glbl;
11745
11746             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11747                 GST_FOURCC_ARGS (fourcc));
11748
11749             /* codec data might be in glbl extension atom */
11750             glbl = mp4v ?
11751                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11752             if (glbl) {
11753               guint8 *data;
11754               GstBuffer *buf;
11755               gint len;
11756
11757               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11758               data = glbl->data;
11759               len = QT_UINT32 (data);
11760               if (len > 0x8) {
11761                 len -= 0x8;
11762                 buf = gst_buffer_new_and_alloc (len);
11763                 gst_buffer_fill (buf, 0, data + 8, len);
11764                 gst_caps_set_simple (entry->caps,
11765                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11766                 gst_buffer_unref (buf);
11767               }
11768             }
11769             break;
11770           }
11771           case FOURCC_mjp2:
11772           {
11773             /* see annex I of the jpeg2000 spec */
11774             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11775             const guint8 *data;
11776             const gchar *colorspace = NULL;
11777             gint ncomp = 0;
11778             guint32 ncomp_map = 0;
11779             gint32 *comp_map = NULL;
11780             guint32 nchan_def = 0;
11781             gint32 *chan_def = NULL;
11782
11783             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11784             /* some required atoms */
11785             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11786             if (!mjp2)
11787               break;
11788             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11789             if (!jp2h)
11790               break;
11791
11792             /* number of components; redundant with info in codestream, but useful
11793                to a muxer */
11794             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11795             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11796               break;
11797             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11798
11799             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11800             if (!colr)
11801               break;
11802             GST_DEBUG_OBJECT (qtdemux, "found colr");
11803             /* extract colour space info */
11804             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11805               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11806                 case 16:
11807                   colorspace = "sRGB";
11808                   break;
11809                 case 17:
11810                   colorspace = "GRAY";
11811                   break;
11812                 case 18:
11813                   colorspace = "sYUV";
11814                   break;
11815                 default:
11816                   colorspace = NULL;
11817                   break;
11818               }
11819             }
11820             if (!colorspace)
11821               /* colr is required, and only values 16, 17, and 18 are specified,
11822                  so error if we have no colorspace */
11823               break;
11824
11825             /* extract component mapping */
11826             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11827             if (cmap) {
11828               guint32 cmap_len = 0;
11829               int i;
11830               cmap_len = QT_UINT32 (cmap->data);
11831               if (cmap_len >= 8) {
11832                 /* normal box, subtract off header */
11833                 cmap_len -= 8;
11834                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11835                 if (cmap_len % 4 == 0) {
11836                   ncomp_map = (cmap_len / 4);
11837                   comp_map = g_new0 (gint32, ncomp_map);
11838                   for (i = 0; i < ncomp_map; i++) {
11839                     guint16 cmp;
11840                     guint8 mtyp, pcol;
11841                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11842                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11843                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11844                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11845                   }
11846                 }
11847               }
11848             }
11849             /* extract channel definitions */
11850             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11851             if (cdef) {
11852               guint32 cdef_len = 0;
11853               int i;
11854               cdef_len = QT_UINT32 (cdef->data);
11855               if (cdef_len >= 10) {
11856                 /* normal box, subtract off header and len */
11857                 cdef_len -= 10;
11858                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11859                 if (cdef_len % 6 == 0) {
11860                   nchan_def = (cdef_len / 6);
11861                   chan_def = g_new0 (gint32, nchan_def);
11862                   for (i = 0; i < nchan_def; i++)
11863                     chan_def[i] = -1;
11864                   for (i = 0; i < nchan_def; i++) {
11865                     guint16 cn, typ, asoc;
11866                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11867                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11868                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11869                     if (cn < nchan_def) {
11870                       switch (typ) {
11871                         case 0:
11872                           chan_def[cn] = asoc;
11873                           break;
11874                         case 1:
11875                           chan_def[cn] = 0;     /* alpha */
11876                           break;
11877                         default:
11878                           chan_def[cn] = -typ;
11879                       }
11880                     }
11881                   }
11882                 }
11883               }
11884             }
11885
11886             gst_caps_set_simple (entry->caps,
11887                 "num-components", G_TYPE_INT, ncomp, NULL);
11888             gst_caps_set_simple (entry->caps,
11889                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11890
11891             if (comp_map) {
11892               GValue arr = { 0, };
11893               GValue elt = { 0, };
11894               int i;
11895               g_value_init (&arr, GST_TYPE_ARRAY);
11896               g_value_init (&elt, G_TYPE_INT);
11897               for (i = 0; i < ncomp_map; i++) {
11898                 g_value_set_int (&elt, comp_map[i]);
11899                 gst_value_array_append_value (&arr, &elt);
11900               }
11901               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11902                   "component-map", &arr);
11903               g_value_unset (&elt);
11904               g_value_unset (&arr);
11905               g_free (comp_map);
11906             }
11907
11908             if (chan_def) {
11909               GValue arr = { 0, };
11910               GValue elt = { 0, };
11911               int i;
11912               g_value_init (&arr, GST_TYPE_ARRAY);
11913               g_value_init (&elt, G_TYPE_INT);
11914               for (i = 0; i < nchan_def; i++) {
11915                 g_value_set_int (&elt, chan_def[i]);
11916                 gst_value_array_append_value (&arr, &elt);
11917               }
11918               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11919                   "channel-definitions", &arr);
11920               g_value_unset (&elt);
11921               g_value_unset (&arr);
11922               g_free (chan_def);
11923             }
11924
11925             /* some optional atoms */
11926             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11927             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11928
11929             /* indicate possible fields in caps */
11930             if (field) {
11931               data = (guint8 *) field->data + 8;
11932               if (*data != 1)
11933                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11934                     (gint) * data, NULL);
11935             }
11936             /* add codec_data if provided */
11937             if (prefix) {
11938               GstBuffer *buf;
11939               gint len;
11940
11941               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11942               data = prefix->data;
11943               len = QT_UINT32 (data);
11944               if (len > 0x8) {
11945                 len -= 0x8;
11946                 buf = gst_buffer_new_and_alloc (len);
11947                 gst_buffer_fill (buf, 0, data + 8, len);
11948                 gst_caps_set_simple (entry->caps,
11949                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11950                 gst_buffer_unref (buf);
11951               }
11952             }
11953             break;
11954           }
11955           case FOURCC_SVQ3:
11956           case FOURCC_VP31:
11957           {
11958             GstBuffer *buf;
11959             GstBuffer *seqh = NULL;
11960             const guint8 *gamma_data = NULL;
11961             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11962
11963             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11964                 &seqh);
11965             if (gamma_data) {
11966               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11967                   QT_FP32 (gamma_data), NULL);
11968             }
11969             if (seqh) {
11970               /* sorry for the bad name, but we don't know what this is, other
11971                * than its own fourcc */
11972               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11973                   NULL);
11974               gst_buffer_unref (seqh);
11975             }
11976
11977             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11978             buf = gst_buffer_new_and_alloc (len);
11979             gst_buffer_fill (buf, 0, stsd_data, len);
11980             gst_caps_set_simple (entry->caps,
11981                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11982             gst_buffer_unref (buf);
11983             break;
11984           }
11985           case FOURCC_jpeg:
11986           {
11987             /* https://developer.apple.com/standards/qtff-2001.pdf,
11988              * page 92, "Video Sample Description", under table 3.1 */
11989             GstByteReader br;
11990
11991             const gint compressor_offset =
11992                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11993             const gint min_size = compressor_offset + 32 + 2 + 2;
11994             GNode *jpeg;
11995             guint32 len;
11996             guint16 color_table_id = 0;
11997             gboolean ok;
11998
11999             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
12000
12001             /* recover information on interlaced/progressive */
12002             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
12003             if (!jpeg)
12004               break;
12005
12006             len = QT_UINT32 (jpeg->data);
12007             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
12008                 min_size);
12009             if (len >= min_size) {
12010               gst_byte_reader_init (&br, jpeg->data, len);
12011
12012               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
12013               gst_byte_reader_get_uint16_le (&br, &color_table_id);
12014               if (color_table_id != 0) {
12015                 /* the spec says there can be concatenated chunks in the data, and we want
12016                  * to find one called field. Walk through them. */
12017                 gint offset = min_size;
12018                 while (offset + 8 < len) {
12019                   guint32 size = 0, tag;
12020                   ok = gst_byte_reader_get_uint32_le (&br, &size);
12021                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12022                   if (!ok || size < 8) {
12023                     GST_WARNING_OBJECT (qtdemux,
12024                         "Failed to walk optional chunk list");
12025                     break;
12026                   }
12027                   GST_DEBUG_OBJECT (qtdemux,
12028                       "Found optional %4.4s chunk, size %u",
12029                       (const char *) &tag, size);
12030                   if (tag == FOURCC_fiel) {
12031                     guint8 n_fields = 0, ordering = 0;
12032                     gst_byte_reader_get_uint8 (&br, &n_fields);
12033                     gst_byte_reader_get_uint8 (&br, &ordering);
12034                     if (n_fields == 1 || n_fields == 2) {
12035                       GST_DEBUG_OBJECT (qtdemux,
12036                           "Found fiel tag with %u fields, ordering %u",
12037                           n_fields, ordering);
12038                       if (n_fields == 2)
12039                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
12040                             "interlace-mode", G_TYPE_STRING, "interleaved",
12041                             NULL);
12042                     } else {
12043                       GST_WARNING_OBJECT (qtdemux,
12044                           "Found fiel tag with invalid fields (%u)", n_fields);
12045                     }
12046                   }
12047                   offset += size;
12048                 }
12049               } else {
12050                 GST_DEBUG_OBJECT (qtdemux,
12051                     "Color table ID is 0, not trying to get interlacedness");
12052               }
12053             } else {
12054               GST_WARNING_OBJECT (qtdemux,
12055                   "Length of jpeg chunk is too small, not trying to get interlacedness");
12056             }
12057
12058             break;
12059           }
12060           case FOURCC_rle_:
12061           case FOURCC_WRLE:
12062           {
12063             gst_caps_set_simple (entry->caps,
12064                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12065                 NULL);
12066             break;
12067           }
12068           case FOURCC_XiTh:
12069           {
12070             GNode *xith, *xdxt;
12071
12072             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12073             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12074             if (!xith)
12075               break;
12076
12077             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12078             if (!xdxt)
12079               break;
12080
12081             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12082             /* collect the headers and store them in a stream list so that we can
12083              * send them out first */
12084             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12085             break;
12086           }
12087           case FOURCC_ovc1:
12088           {
12089             GNode *ovc1;
12090             guint8 *ovc1_data;
12091             guint ovc1_len;
12092             GstBuffer *buf;
12093
12094             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12095             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12096             if (!ovc1)
12097               break;
12098             ovc1_data = ovc1->data;
12099             ovc1_len = QT_UINT32 (ovc1_data);
12100             if (ovc1_len <= 198) {
12101               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12102               break;
12103             }
12104             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12105             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12106             gst_caps_set_simple (entry->caps,
12107                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12108             gst_buffer_unref (buf);
12109             break;
12110           }
12111           case FOURCC_vc_1:
12112           {
12113             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12114             const guint8 *vc1_data = stsd_entry_data + 0x56;
12115
12116             /* find dvc1 */
12117             while (len >= 8) {
12118               gint size;
12119
12120               if (QT_UINT32 (vc1_data) <= len)
12121                 size = QT_UINT32 (vc1_data) - 8;
12122               else
12123                 size = len - 8;
12124
12125               if (size < 1)
12126                 /* No real data, so break out */
12127                 break;
12128
12129               switch (QT_FOURCC (vc1_data + 0x4)) {
12130                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12131                 {
12132                   GstBuffer *buf;
12133
12134                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12135                   buf = gst_buffer_new_and_alloc (size);
12136                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
12137                   gst_caps_set_simple (entry->caps,
12138                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12139                   gst_buffer_unref (buf);
12140                   break;
12141                 }
12142                 default:
12143                   break;
12144               }
12145               len -= size + 8;
12146               vc1_data += size + 8;
12147             }
12148             break;
12149           }
12150           case FOURCC_av01:
12151           {
12152             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12153             const guint8 *av1_data = stsd_entry_data + 0x56;
12154
12155             /* find av1C */
12156             while (len >= 0x8) {
12157               gint size;
12158
12159               if (QT_UINT32 (av1_data) <= len)
12160                 size = QT_UINT32 (av1_data) - 0x8;
12161               else
12162                 size = len - 0x8;
12163
12164               if (size < 1)
12165                 /* No real data, so break out */
12166                 break;
12167
12168               switch (QT_FOURCC (av1_data + 0x4)) {
12169                 case FOURCC_av1C:
12170                 {
12171                   /* parse, if found */
12172                   GstBuffer *buf;
12173                   guint8 pres_delay_field;
12174
12175                   GST_DEBUG_OBJECT (qtdemux,
12176                       "found av1C codec_data in stsd of size %d", size);
12177
12178                   /* not enough data, just ignore and hope for the best */
12179                   if (size < 5)
12180                     break;
12181
12182                   /* Content is:
12183                    * 4 bytes: atom length
12184                    * 4 bytes: fourcc
12185                    * 1 byte: version
12186                    * 3 bytes: flags
12187                    * 3 bits: reserved
12188                    * 1 bits:  initial_presentation_delay_present
12189                    * 4 bits: initial_presentation_delay (if present else reserved
12190                    * rest: OBUs.
12191                    */
12192
12193                   if (av1_data[9] != 0) {
12194                     GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12195                     break;
12196                   }
12197
12198                   /* We skip initial_presentation_delay* for now */
12199                   pres_delay_field = *(av1_data + 12);
12200                   if (pres_delay_field & (1 << 5)) {
12201                     gst_caps_set_simple (entry->caps,
12202                         "presentation-delay", G_TYPE_INT,
12203                         (gint) (pres_delay_field & 0x0F) + 1, NULL);
12204                   }
12205                   if (size > 5) {
12206                     buf = gst_buffer_new_and_alloc (size - 5);
12207                     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12208                     gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12209                     gst_caps_set_simple (entry->caps,
12210                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
12211                     gst_buffer_unref (buf);
12212                   }
12213                   break;
12214                 }
12215                 default:
12216                   break;
12217               }
12218
12219               len -= size + 8;
12220               av1_data += size + 8;
12221             }
12222
12223             break;
12224           }
12225           default:
12226             break;
12227         }
12228       }
12229
12230       GST_INFO_OBJECT (qtdemux,
12231           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12232           GST_FOURCC_ARGS (fourcc), entry->caps);
12233
12234     } else if (stream->subtype == FOURCC_soun) {
12235       GNode *wave;
12236       int version, samplesize;
12237       guint16 compression_id;
12238       gboolean amrwb = FALSE;
12239
12240       offset = 16;
12241       /* sample description entry (16) + sound sample description v0 (20) */
12242       if (len < 36)
12243         goto corrupt_file;
12244
12245       version = QT_UINT32 (stsd_entry_data + offset);
12246       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12247       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12248       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12249       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12250
12251       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
12252       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
12253           QT_UINT32 (stsd_entry_data + offset + 4));
12254       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
12255       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
12256       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
12257       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
12258           QT_UINT16 (stsd_entry_data + offset + 14));
12259       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
12260
12261       if (compression_id == 0xfffe)
12262         entry->sampled = TRUE;
12263
12264       /* first assume uncompressed audio */
12265       entry->bytes_per_sample = samplesize / 8;
12266       entry->samples_per_frame = entry->n_channels;
12267       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12268       entry->samples_per_packet = entry->samples_per_frame;
12269       entry->bytes_per_packet = entry->bytes_per_sample;
12270
12271       offset = 36;
12272       switch (fourcc) {
12273           /* Yes, these have to be hard-coded */
12274         case FOURCC_MAC6:
12275         {
12276           entry->samples_per_packet = 6;
12277           entry->bytes_per_packet = 1;
12278           entry->bytes_per_frame = 1 * entry->n_channels;
12279           entry->bytes_per_sample = 1;
12280           entry->samples_per_frame = 6 * entry->n_channels;
12281           break;
12282         }
12283         case FOURCC_MAC3:
12284         {
12285           entry->samples_per_packet = 3;
12286           entry->bytes_per_packet = 1;
12287           entry->bytes_per_frame = 1 * entry->n_channels;
12288           entry->bytes_per_sample = 1;
12289           entry->samples_per_frame = 3 * entry->n_channels;
12290           break;
12291         }
12292         case FOURCC_ima4:
12293         {
12294           entry->samples_per_packet = 64;
12295           entry->bytes_per_packet = 34;
12296           entry->bytes_per_frame = 34 * entry->n_channels;
12297           entry->bytes_per_sample = 2;
12298           entry->samples_per_frame = 64 * entry->n_channels;
12299           break;
12300         }
12301         case FOURCC_ulaw:
12302         case FOURCC_alaw:
12303         {
12304           entry->samples_per_packet = 1;
12305           entry->bytes_per_packet = 1;
12306           entry->bytes_per_frame = 1 * entry->n_channels;
12307           entry->bytes_per_sample = 1;
12308           entry->samples_per_frame = 1 * entry->n_channels;
12309           break;
12310         }
12311         case FOURCC_agsm:
12312         {
12313           entry->samples_per_packet = 160;
12314           entry->bytes_per_packet = 33;
12315           entry->bytes_per_frame = 33 * entry->n_channels;
12316           entry->bytes_per_sample = 2;
12317           entry->samples_per_frame = 160 * entry->n_channels;
12318           break;
12319         }
12320         default:
12321           break;
12322       }
12323
12324       if (version == 0x00010000) {
12325         /* sample description entry (16) + sound sample description v1 (20+16) */
12326         if (len < 52)
12327           goto corrupt_file;
12328
12329         switch (fourcc) {
12330           case FOURCC_twos:
12331           case FOURCC_sowt:
12332           case FOURCC_raw_:
12333           case FOURCC_lpcm:
12334             break;
12335           default:
12336           {
12337             /* only parse extra decoding config for non-pcm audio */
12338             entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12339             entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12340             entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12341             entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12342
12343             GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
12344                 entry->samples_per_packet);
12345             GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
12346                 entry->bytes_per_packet);
12347             GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
12348                 entry->bytes_per_frame);
12349             GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
12350                 entry->bytes_per_sample);
12351
12352             if (!entry->sampled && entry->bytes_per_packet) {
12353               entry->samples_per_frame = (entry->bytes_per_frame /
12354                   entry->bytes_per_packet) * entry->samples_per_packet;
12355               GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
12356                   entry->samples_per_frame);
12357             }
12358             break;
12359           }
12360         }
12361       } else if (version == 0x00020000) {
12362         union
12363         {
12364           gdouble fp;
12365           guint64 val;
12366         } qtfp;
12367
12368         /* sample description entry (16) + sound sample description v2 (56) */
12369         if (len < 72)
12370           goto corrupt_file;
12371
12372         qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
12373         entry->rate = qtfp.fp;
12374         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12375
12376         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12377         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
12378         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
12379         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
12380             QT_UINT32 (stsd_entry_data + offset + 20));
12381         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
12382             QT_UINT32 (stsd_entry_data + offset + 24));
12383         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
12384             QT_UINT32 (stsd_entry_data + offset + 28));
12385         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12386             QT_UINT32 (stsd_entry_data + offset + 32));
12387       } else if (version != 0x00000) {
12388         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12389             version);
12390       }
12391
12392       if (entry->caps)
12393         gst_caps_unref (entry->caps);
12394
12395       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12396           stsd_entry_data + 32, len - 16, &codec);
12397
12398       switch (fourcc) {
12399         case FOURCC_in24:
12400         {
12401           GNode *enda;
12402           GNode *in24;
12403
12404           in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
12405
12406           enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
12407           if (!enda) {
12408             wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
12409             if (wave)
12410               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12411           }
12412           if (enda) {
12413             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12414             gst_caps_set_simple (entry->caps,
12415                 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
12416                 NULL);
12417           }
12418           break;
12419         }
12420         case FOURCC_owma:
12421         {
12422           const guint8 *owma_data;
12423           const gchar *codec_name = NULL;
12424           guint owma_len;
12425           GstBuffer *buf;
12426           gint version = 1;
12427           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12428           /* FIXME this should also be gst_riff_strf_auds,
12429            * but the latter one is actually missing bits-per-sample :( */
12430           typedef struct
12431           {
12432             gint16 wFormatTag;
12433             gint16 nChannels;
12434             gint32 nSamplesPerSec;
12435             gint32 nAvgBytesPerSec;
12436             gint16 nBlockAlign;
12437             gint16 wBitsPerSample;
12438             gint16 cbSize;
12439           } WAVEFORMATEX;
12440           WAVEFORMATEX *wfex;
12441
12442           GST_DEBUG_OBJECT (qtdemux, "parse owma");
12443           owma_data = stsd_entry_data;
12444           owma_len = QT_UINT32 (owma_data);
12445           if (owma_len <= 54) {
12446             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12447             break;
12448           }
12449           wfex = (WAVEFORMATEX *) (owma_data + 36);
12450           buf = gst_buffer_new_and_alloc (owma_len - 54);
12451           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12452           if (wfex->wFormatTag == 0x0161) {
12453             codec_name = "Windows Media Audio";
12454             version = 2;
12455           } else if (wfex->wFormatTag == 0x0162) {
12456             codec_name = "Windows Media Audio 9 Pro";
12457             version = 3;
12458           } else if (wfex->wFormatTag == 0x0163) {
12459             codec_name = "Windows Media Audio 9 Lossless";
12460             /* is that correct? gstffmpegcodecmap.c is missing it, but
12461              * fluendo codec seems to support it */
12462             version = 4;
12463           }
12464
12465           gst_caps_set_simple (entry->caps,
12466               "codec_data", GST_TYPE_BUFFER, buf,
12467               "wmaversion", G_TYPE_INT, version,
12468               "block_align", G_TYPE_INT,
12469               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12470               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12471               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12472               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12473           gst_buffer_unref (buf);
12474
12475           if (codec_name) {
12476             g_free (codec);
12477             codec = g_strdup (codec_name);
12478           }
12479           break;
12480         }
12481         case FOURCC_wma_:
12482         {
12483           gint len = QT_UINT32 (stsd_entry_data) - offset;
12484           const guint8 *wfex_data = stsd_entry_data + offset;
12485           const gchar *codec_name = NULL;
12486           gint version = 1;
12487           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12488           /* FIXME this should also be gst_riff_strf_auds,
12489            * but the latter one is actually missing bits-per-sample :( */
12490           typedef struct
12491           {
12492             gint16 wFormatTag;
12493             gint16 nChannels;
12494             gint32 nSamplesPerSec;
12495             gint32 nAvgBytesPerSec;
12496             gint16 nBlockAlign;
12497             gint16 wBitsPerSample;
12498             gint16 cbSize;
12499           } WAVEFORMATEX;
12500           WAVEFORMATEX wfex;
12501
12502           /* FIXME: unify with similar wavformatex parsing code above */
12503           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12504
12505           /* find wfex */
12506           while (len >= 8) {
12507             gint size;
12508
12509             if (QT_UINT32 (wfex_data) <= len)
12510               size = QT_UINT32 (wfex_data) - 8;
12511             else
12512               size = len - 8;
12513
12514             if (size < 1)
12515               /* No real data, so break out */
12516               break;
12517
12518             switch (QT_FOURCC (wfex_data + 4)) {
12519               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12520               {
12521                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12522
12523                 if (size < 8 + 18)
12524                   break;
12525
12526                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12527                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12528                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12529                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12530                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12531                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12532                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12533
12534                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12535                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12536                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12537                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12538                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12539                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12540
12541                 if (wfex.wFormatTag == 0x0161) {
12542                   codec_name = "Windows Media Audio";
12543                   version = 2;
12544                 } else if (wfex.wFormatTag == 0x0162) {
12545                   codec_name = "Windows Media Audio 9 Pro";
12546                   version = 3;
12547                 } else if (wfex.wFormatTag == 0x0163) {
12548                   codec_name = "Windows Media Audio 9 Lossless";
12549                   /* is that correct? gstffmpegcodecmap.c is missing it, but
12550                    * fluendo codec seems to support it */
12551                   version = 4;
12552                 }
12553
12554                 gst_caps_set_simple (entry->caps,
12555                     "wmaversion", G_TYPE_INT, version,
12556                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
12557                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12558                     "width", G_TYPE_INT, wfex.wBitsPerSample,
12559                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12560
12561                 if (size > wfex.cbSize) {
12562                   GstBuffer *buf;
12563
12564                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12565                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12566                       size - wfex.cbSize);
12567                   gst_caps_set_simple (entry->caps,
12568                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12569                   gst_buffer_unref (buf);
12570                 } else {
12571                   GST_WARNING_OBJECT (qtdemux, "no codec data");
12572                 }
12573
12574                 if (codec_name) {
12575                   g_free (codec);
12576                   codec = g_strdup (codec_name);
12577                 }
12578                 break;
12579               }
12580               default:
12581                 break;
12582             }
12583             len -= size + 8;
12584             wfex_data += size + 8;
12585           }
12586           break;
12587         }
12588         case FOURCC_opus:
12589         {
12590           const guint8 *opus_data;
12591           guint8 *channel_mapping = NULL;
12592           guint32 rate;
12593           guint8 channels;
12594           guint8 channel_mapping_family;
12595           guint8 stream_count;
12596           guint8 coupled_count;
12597           guint8 i;
12598
12599           opus_data = stsd_entry_data;
12600
12601           channels = GST_READ_UINT8 (opus_data + 45);
12602           rate = GST_READ_UINT32_LE (opus_data + 48);
12603           channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12604           stream_count = GST_READ_UINT8 (opus_data + 55);
12605           coupled_count = GST_READ_UINT8 (opus_data + 56);
12606
12607           if (channels > 0) {
12608             channel_mapping = g_malloc (channels * sizeof (guint8));
12609             for (i = 0; i < channels; i++)
12610               channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12611           }
12612
12613           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12614               channel_mapping_family, stream_count, coupled_count,
12615               channel_mapping);
12616           break;
12617         }
12618         default:
12619           break;
12620       }
12621
12622       if (codec) {
12623         GstStructure *s;
12624         gint bitrate = 0;
12625
12626         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12627             GST_TAG_AUDIO_CODEC, codec, NULL);
12628         g_free (codec);
12629         codec = NULL;
12630
12631         /* some bitrate info may have ended up in caps */
12632         s = gst_caps_get_structure (entry->caps, 0);
12633         gst_structure_get_int (s, "bitrate", &bitrate);
12634         if (bitrate > 0)
12635           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12636               GST_TAG_BITRATE, bitrate, NULL);
12637       }
12638
12639       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12640       if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12641         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca)
12642           mp4a = NULL;
12643         else if (!stream->protected)
12644           mp4a = NULL;
12645       }
12646
12647       wave = NULL;
12648       esds = NULL;
12649       if (mp4a) {
12650         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12651         if (wave)
12652           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12653         if (!esds)
12654           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12655       }
12656
12657
12658       /* If the fourcc's bottom 16 bits gives 'sm', then the top
12659          16 bits is a byte-swapped wave-style codec identifier,
12660          and we can find a WAVE header internally to a 'wave' atom here.
12661          This can more clearly be thought of as 'ms' as the top 16 bits, and a
12662          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12663          is big-endian).
12664        */
12665       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12666         if (len < offset + 20) {
12667           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12668         } else {
12669           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12670           const guint8 *data = stsd_entry_data + offset + 16;
12671           GNode *wavenode;
12672           GNode *waveheadernode;
12673
12674           wavenode = g_node_new ((guint8 *) data);
12675           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12676             const guint8 *waveheader;
12677             guint32 headerlen;
12678
12679             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12680             if (waveheadernode) {
12681               waveheader = (const guint8 *) waveheadernode->data;
12682               headerlen = QT_UINT32 (waveheader);
12683
12684               if (headerlen > 8) {
12685                 gst_riff_strf_auds *header = NULL;
12686                 GstBuffer *headerbuf;
12687                 GstBuffer *extra;
12688
12689                 waveheader += 8;
12690                 headerlen -= 8;
12691
12692                 headerbuf = gst_buffer_new_and_alloc (headerlen);
12693                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12694
12695                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12696                         headerbuf, &header, &extra)) {
12697                   gst_caps_unref (entry->caps);
12698                   /* FIXME: Need to do something with the channel reorder map */
12699                   entry->caps =
12700                       gst_riff_create_audio_caps (header->format, NULL, header,
12701                       extra, NULL, NULL, NULL);
12702
12703                   if (extra)
12704                     gst_buffer_unref (extra);
12705                   g_free (header);
12706                 }
12707               }
12708             } else
12709               GST_DEBUG ("Didn't find waveheadernode for this codec");
12710           }
12711           g_node_destroy (wavenode);
12712         }
12713       } else if (esds) {
12714         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12715             stream->stream_tags);
12716       } else {
12717         switch (fourcc) {
12718 #if 0
12719             /* FIXME: what is in the chunk? */
12720           case FOURCC_QDMC:
12721           {
12722             gint len = QT_UINT32 (stsd_data);
12723
12724             /* seems to be always = 116 = 0x74 */
12725             break;
12726           }
12727 #endif
12728           case FOURCC_QDM2:
12729           {
12730             gint len = QT_UINT32 (stsd_entry_data);
12731
12732             if (len > 0x3C) {
12733               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12734
12735               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12736               gst_caps_set_simple (entry->caps,
12737                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12738               gst_buffer_unref (buf);
12739             }
12740             gst_caps_set_simple (entry->caps,
12741                 "samplesize", G_TYPE_INT, samplesize, NULL);
12742             break;
12743           }
12744           case FOURCC_alac:
12745           {
12746             GNode *alac, *wave = NULL;
12747
12748             /* apparently, m4a has this atom appended directly in the stsd entry,
12749              * while mov has it in a wave atom */
12750             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12751             if (alac) {
12752               /* alac now refers to stsd entry atom */
12753               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12754               if (wave)
12755                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12756               else
12757                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12758             }
12759             if (alac) {
12760               const guint8 *alac_data = alac->data;
12761               gint len = QT_UINT32 (alac->data);
12762               GstBuffer *buf;
12763
12764               if (len < 36) {
12765                 GST_DEBUG_OBJECT (qtdemux,
12766                     "discarding alac atom with unexpected len %d", len);
12767               } else {
12768                 /* codec-data contains alac atom size and prefix,
12769                  * ffmpeg likes it that way, not quite gst-ish though ...*/
12770                 buf = gst_buffer_new_and_alloc (len);
12771                 gst_buffer_fill (buf, 0, alac->data, len);
12772                 gst_caps_set_simple (entry->caps,
12773                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12774                 gst_buffer_unref (buf);
12775
12776                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12777                 entry->n_channels = QT_UINT8 (alac_data + 21);
12778                 entry->rate = QT_UINT32 (alac_data + 32);
12779               }
12780             }
12781             gst_caps_set_simple (entry->caps,
12782                 "samplesize", G_TYPE_INT, samplesize, NULL);
12783             break;
12784           }
12785           case FOURCC_fLaC:
12786           {
12787             /* The codingname of the sample entry is 'fLaC' */
12788             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12789
12790             if (flac) {
12791               /* The 'dfLa' box is added to the sample entry to convey
12792                  initializing information for the decoder. */
12793               const GNode *dfla =
12794                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12795
12796               if (dfla) {
12797                 const guint32 len = QT_UINT32 (dfla->data);
12798
12799                 /* Must contain at least dfLa box header (12),
12800                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12801                 if (len < 50) {
12802                   GST_DEBUG_OBJECT (qtdemux,
12803                       "discarding dfla atom with unexpected len %d", len);
12804                 } else {
12805                   /* skip dfLa header to get the METADATA_BLOCKs */
12806                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12807                   const guint32 metadata_blocks_len = len - 12;
12808
12809                   gchar *stream_marker = g_strdup ("fLaC");
12810                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12811                       strlen (stream_marker));
12812
12813                   guint32 index = 0;
12814                   guint32 remainder = 0;
12815                   guint32 block_size = 0;
12816                   gboolean is_last = FALSE;
12817
12818                   GValue array = G_VALUE_INIT;
12819                   GValue value = G_VALUE_INIT;
12820
12821                   g_value_init (&array, GST_TYPE_ARRAY);
12822                   g_value_init (&value, GST_TYPE_BUFFER);
12823
12824                   gst_value_set_buffer (&value, block);
12825                   gst_value_array_append_value (&array, &value);
12826                   g_value_reset (&value);
12827
12828                   gst_buffer_unref (block);
12829
12830                   /* check there's at least one METADATA_BLOCK_HEADER's worth
12831                    * of data, and we haven't already finished parsing */
12832                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
12833                     remainder = metadata_blocks_len - index;
12834
12835                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
12836                     block_size = 4 +
12837                         (metadata_blocks[index + 1] << 16) +
12838                         (metadata_blocks[index + 2] << 8) +
12839                         metadata_blocks[index + 3];
12840
12841                     /* be careful not to read off end of box */
12842                     if (block_size > remainder) {
12843                       break;
12844                     }
12845
12846                     is_last = metadata_blocks[index] >> 7;
12847
12848                     block = gst_buffer_new_and_alloc (block_size);
12849
12850                     gst_buffer_fill (block, 0, &metadata_blocks[index],
12851                         block_size);
12852
12853                     gst_value_set_buffer (&value, block);
12854                     gst_value_array_append_value (&array, &value);
12855                     g_value_reset (&value);
12856
12857                     gst_buffer_unref (block);
12858
12859                     index += block_size;
12860                   }
12861
12862                   /* only append the metadata if we successfully read all of it */
12863                   if (is_last) {
12864                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12865                             (stream)->caps, 0), "streamheader", &array);
12866                   } else {
12867                     GST_WARNING_OBJECT (qtdemux,
12868                         "discarding all METADATA_BLOCKs due to invalid "
12869                         "block_size %d at idx %d, rem %d", block_size, index,
12870                         remainder);
12871                   }
12872
12873                   g_value_unset (&value);
12874                   g_value_unset (&array);
12875
12876                   /* The sample rate obtained from the stsd may not be accurate
12877                    * since it cannot represent rates greater than 65535Hz, so
12878                    * override that value with the sample rate from the
12879                    * METADATA_BLOCK_STREAMINFO block */
12880                   CUR_STREAM (stream)->rate =
12881                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12882                 }
12883               }
12884             }
12885             break;
12886           }
12887           case FOURCC_sawb:
12888             /* Fallthrough! */
12889             amrwb = TRUE;
12890           case FOURCC_samr:
12891           {
12892             gint len = QT_UINT32 (stsd_entry_data);
12893
12894             if (len > 0x24) {
12895               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12896               guint bitrate;
12897
12898               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12899
12900               /* If we have enough data, let's try to get the 'damr' atom. See
12901                * the 3GPP container spec (26.244) for more details. */
12902               if ((len - 0x34) > 8 &&
12903                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12904                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12905                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12906               }
12907
12908               gst_caps_set_simple (entry->caps,
12909                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12910               gst_buffer_unref (buf);
12911             }
12912             break;
12913           }
12914           case FOURCC_mp4a:
12915           {
12916             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12917             gint len = QT_UINT32 (stsd_entry_data);
12918
12919             if (len >= 34) {
12920               guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12921
12922               if (sound_version == 1) {
12923                 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12924                 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12925                 guint8 codec_data[2];
12926                 GstBuffer *buf;
12927                 gint profile = 2;       /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12928
12929                 gint sample_rate_index =
12930                     gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12931
12932                 /* build AAC codec data */
12933                 codec_data[0] = profile << 3;
12934                 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12935                 codec_data[1] = (sample_rate_index & 0x01) << 7;
12936                 codec_data[1] |= (channels & 0xF) << 3;
12937
12938                 buf = gst_buffer_new_and_alloc (2);
12939                 gst_buffer_fill (buf, 0, codec_data, 2);
12940                 gst_caps_set_simple (entry->caps,
12941                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12942                 gst_buffer_unref (buf);
12943               }
12944             }
12945             break;
12946           }
12947           case FOURCC_lpcm:
12948             /* Fully handled elsewhere */
12949             break;
12950           default:
12951             GST_INFO_OBJECT (qtdemux,
12952                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12953             break;
12954         }
12955       }
12956       GST_INFO_OBJECT (qtdemux,
12957           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12958           GST_FOURCC_ARGS (fourcc), entry->caps);
12959
12960     } else if (stream->subtype == FOURCC_strm) {
12961       if (fourcc == FOURCC_rtsp) {
12962         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12963       } else {
12964         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12965             GST_FOURCC_ARGS (fourcc));
12966         goto unknown_stream;
12967       }
12968       entry->sampled = TRUE;
12969     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12970         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12971         || stream->subtype == FOURCC_clcp) {
12972
12973       entry->sampled = TRUE;
12974       entry->sparse = TRUE;
12975
12976       entry->caps =
12977           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12978           &codec);
12979       if (codec) {
12980         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12981             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12982         g_free (codec);
12983         codec = NULL;
12984       }
12985
12986       /* hunt for sort-of codec data */
12987       switch (fourcc) {
12988         case FOURCC_mp4s:
12989         {
12990           GNode *mp4s = NULL;
12991           GNode *esds = NULL;
12992
12993           /* look for palette in a stsd->mp4s->esds sub-atom */
12994           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12995           if (mp4s)
12996             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12997           if (esds == NULL) {
12998             /* Invalid STSD */
12999             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13000             break;
13001           }
13002
13003           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13004               stream->stream_tags);
13005           break;
13006         }
13007         default:
13008           GST_INFO_OBJECT (qtdemux,
13009               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13010           break;
13011       }
13012       GST_INFO_OBJECT (qtdemux,
13013           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13014           GST_FOURCC_ARGS (fourcc), entry->caps);
13015     } else {
13016       /* everything in 1 sample */
13017       entry->sampled = TRUE;
13018
13019       entry->caps =
13020           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13021           &codec);
13022
13023       if (entry->caps == NULL)
13024         goto unknown_stream;
13025
13026       if (codec) {
13027         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13028             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13029         g_free (codec);
13030         codec = NULL;
13031       }
13032     }
13033
13034     /* promote to sampled format */
13035     if (entry->fourcc == FOURCC_samr) {
13036       /* force mono 8000 Hz for AMR */
13037       entry->sampled = TRUE;
13038       entry->n_channels = 1;
13039       entry->rate = 8000;
13040     } else if (entry->fourcc == FOURCC_sawb) {
13041       /* force mono 16000 Hz for AMR-WB */
13042       entry->sampled = TRUE;
13043       entry->n_channels = 1;
13044       entry->rate = 16000;
13045     } else if (entry->fourcc == FOURCC_mp4a) {
13046       entry->sampled = TRUE;
13047     }
13048
13049
13050     stsd_entry_data += len;
13051     remaining_stsd_len -= len;
13052
13053   }
13054
13055   /* collect sample information */
13056   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13057     goto samples_failed;
13058
13059   if (qtdemux->fragmented) {
13060     guint64 offset;
13061
13062     /* need all moov samples as basis; probably not many if any at all */
13063     /* prevent moof parsing taking of at this time */
13064     offset = qtdemux->moof_offset;
13065     qtdemux->moof_offset = 0;
13066     if (stream->n_samples &&
13067         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13068       qtdemux->moof_offset = offset;
13069       goto samples_failed;
13070     }
13071     qtdemux->moof_offset = 0;
13072     /* movie duration more reliable in this case (e.g. mehd) */
13073     if (qtdemux->segment.duration &&
13074         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13075       stream->duration =
13076           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13077   }
13078
13079   /* configure segments */
13080   if (!qtdemux_parse_segments (qtdemux, stream, trak))
13081     goto segments_failed;
13082
13083   /* add some language tag, if useful */
13084   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13085       strcmp (stream->lang_id, "und")) {
13086     const gchar *lang_code;
13087
13088     /* convert ISO 639-2 code to ISO 639-1 */
13089     lang_code = gst_tag_get_language_code (stream->lang_id);
13090     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13091         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13092   }
13093
13094   /* Check for UDTA tags */
13095   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13096     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13097   }
13098
13099   /* Insert and sort new stream in track-id order.
13100    * This will help in comparing old/new streams during stream update check */
13101   g_ptr_array_add (qtdemux->active_streams, stream);
13102   g_ptr_array_sort (qtdemux->active_streams,
13103       (GCompareFunc) qtdemux_track_id_compare_func);
13104   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13105       QTDEMUX_N_STREAMS (qtdemux));
13106
13107   return TRUE;
13108
13109 /* ERRORS */
13110 corrupt_file:
13111   {
13112     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13113         (_("This file is corrupt and cannot be played.")), (NULL));
13114     if (stream)
13115       gst_qtdemux_stream_unref (stream);
13116     return FALSE;
13117   }
13118 error_encrypted:
13119   {
13120     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13121     gst_qtdemux_stream_unref (stream);
13122     return FALSE;
13123   }
13124 samples_failed:
13125 segments_failed:
13126   {
13127     /* we posted an error already */
13128     /* free stbl sub-atoms */
13129     gst_qtdemux_stbl_free (stream);
13130     gst_qtdemux_stream_unref (stream);
13131     return FALSE;
13132   }
13133 existing_stream:
13134   {
13135     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13136         track_id);
13137     return TRUE;
13138   }
13139 unknown_stream:
13140   {
13141     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13142         GST_FOURCC_ARGS (stream->subtype));
13143     gst_qtdemux_stream_unref (stream);
13144     return TRUE;
13145   }
13146 }
13147
13148 /* If we can estimate the overall bitrate, and don't have information about the
13149  * stream bitrate for exactly one stream, this guesses the stream bitrate as
13150  * the overall bitrate minus the sum of the bitrates of all other streams. This
13151  * should be useful for the common case where we have one audio and one video
13152  * stream and can estimate the bitrate of one, but not the other. */
13153 static void
13154 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13155 {
13156   QtDemuxStream *stream = NULL;
13157   gint64 size, sys_bitrate, sum_bitrate = 0;
13158   GstClockTime duration;
13159   guint bitrate;
13160   gint i;
13161
13162   if (qtdemux->fragmented)
13163     return;
13164
13165   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13166
13167   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13168       || size <= 0) {
13169     GST_DEBUG_OBJECT (qtdemux,
13170         "Size in bytes of the stream not known - bailing");
13171     return;
13172   }
13173
13174   /* Subtract the header size */
13175   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13176       size, qtdemux->header_size);
13177
13178   if (size < qtdemux->header_size)
13179     return;
13180
13181   size = size - qtdemux->header_size;
13182
13183   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13184     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13185     return;
13186   }
13187
13188   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13189     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13190     switch (str->subtype) {
13191       case FOURCC_soun:
13192       case FOURCC_vide:
13193         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13194             CUR_STREAM (str)->caps);
13195         /* retrieve bitrate, prefer avg then max */
13196         bitrate = 0;
13197         if (str->stream_tags) {
13198           if (gst_tag_list_get_uint (str->stream_tags,
13199                   GST_TAG_MAXIMUM_BITRATE, &bitrate))
13200             GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13201           if (gst_tag_list_get_uint (str->stream_tags,
13202                   GST_TAG_NOMINAL_BITRATE, &bitrate))
13203             GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13204           if (gst_tag_list_get_uint (str->stream_tags,
13205                   GST_TAG_BITRATE, &bitrate))
13206             GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13207         }
13208         if (bitrate)
13209           sum_bitrate += bitrate;
13210         else {
13211           if (stream) {
13212             GST_DEBUG_OBJECT (qtdemux,
13213                 ">1 stream with unknown bitrate - bailing");
13214             return;
13215           } else
13216             stream = str;
13217         }
13218
13219       default:
13220         /* For other subtypes, we assume no significant impact on bitrate */
13221         break;
13222     }
13223   }
13224
13225   if (!stream) {
13226     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13227     return;
13228   }
13229
13230   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13231
13232   if (sys_bitrate < sum_bitrate) {
13233     /* This can happen, since sum_bitrate might be derived from maximum
13234      * bitrates and not average bitrates */
13235     GST_DEBUG_OBJECT (qtdemux,
13236         "System bitrate less than sum bitrate - bailing");
13237     return;
13238   }
13239
13240   bitrate = sys_bitrate - sum_bitrate;
13241   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13242       ", Stream bitrate = %u", sys_bitrate, bitrate);
13243
13244   if (!stream->stream_tags)
13245     stream->stream_tags = gst_tag_list_new_empty ();
13246   else
13247     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13248
13249   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13250       GST_TAG_BITRATE, bitrate, NULL);
13251 }
13252
13253 static GstFlowReturn
13254 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13255 {
13256   GstFlowReturn ret = GST_FLOW_OK;
13257   gint i;
13258
13259   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
13260
13261   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13262     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13263     guint32 sample_num = 0;
13264
13265     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13266         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13267
13268     if (qtdemux->fragmented) {
13269       /* need all moov samples first */
13270       GST_OBJECT_LOCK (qtdemux);
13271       while (stream->n_samples == 0)
13272         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13273           break;
13274       GST_OBJECT_UNLOCK (qtdemux);
13275     } else {
13276       /* discard any stray moof */
13277       qtdemux->moof_offset = 0;
13278     }
13279
13280     /* prepare braking */
13281     if (ret != GST_FLOW_ERROR)
13282       ret = GST_FLOW_OK;
13283
13284     /* in pull mode, we should have parsed some sample info by now;
13285      * and quite some code will not handle no samples.
13286      * in push mode, we'll just have to deal with it */
13287     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13288       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13289       g_ptr_array_remove_index (qtdemux->active_streams, i);
13290       i--;
13291       continue;
13292     } else if (stream->track_id == qtdemux->chapters_track_id &&
13293         (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13294       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13295          so that it doesn't look like a subtitle track */
13296       g_ptr_array_remove_index (qtdemux->active_streams, i);
13297       i--;
13298       continue;
13299     }
13300
13301     /* parse the initial sample for use in setting the frame rate cap */
13302     while (sample_num == 0 && sample_num < stream->n_samples) {
13303       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13304         break;
13305       ++sample_num;
13306     }
13307   }
13308
13309   return ret;
13310 }
13311
13312 static gboolean
13313 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13314 {
13315   return g_strcmp0 (stream->stream_id, stream_id) == 0;
13316 }
13317
13318 static gboolean
13319 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13320 {
13321   gint i;
13322
13323   /* Different length, updated */
13324   if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13325     return TRUE;
13326
13327   /* streams in list are sorted in track-id order */
13328   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13329     /* Different stream-id, updated */
13330     if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13331             QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13332       return TRUE;
13333   }
13334
13335   return FALSE;
13336 }
13337
13338 static gboolean
13339 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13340     QtDemuxStream * oldstream, QtDemuxStream * newstream)
13341 {
13342   /* Connect old stream's srcpad to new stream */
13343   newstream->pad = oldstream->pad;
13344   oldstream->pad = NULL;
13345
13346   /* unset new_stream to prevent stream-start event */
13347   newstream->new_stream = FALSE;
13348
13349   return gst_qtdemux_configure_stream (qtdemux, newstream);
13350 }
13351
13352 /* g_ptr_array_find_with_equal_func is available since 2.54,
13353  * replacement until we can depend unconditionally on the real one in GLib */
13354 #if !GLIB_CHECK_VERSION(2,54,0)
13355 #define g_ptr_array_find_with_equal_func qtdemux_ptr_array_find_with_equal_func
13356 static gboolean
13357 qtdemux_ptr_array_find_with_equal_func (GPtrArray * haystack,
13358     gconstpointer needle, GEqualFunc equal_func, guint * index_)
13359 {
13360   guint i;
13361
13362   g_return_val_if_fail (haystack != NULL, FALSE);
13363
13364   if (equal_func == NULL)
13365     equal_func = g_direct_equal;
13366
13367   for (i = 0; i < haystack->len; i++) {
13368     if (equal_func (g_ptr_array_index (haystack, i), needle)) {
13369       if (index_ != NULL)
13370         *index_ = i;
13371       return TRUE;
13372     }
13373   }
13374
13375   return FALSE;
13376 }
13377 #endif
13378
13379 static gboolean
13380 qtdemux_update_streams (GstQTDemux * qtdemux)
13381 {
13382   gint i;
13383   g_assert (qtdemux->streams_aware);
13384
13385   /* At below, figure out which stream in active_streams has identical stream-id
13386    * with that of in old_streams. If there is matching stream-id,
13387    * corresponding newstream will not be exposed again,
13388    * but demux will reuse srcpad of matched old stream
13389    *
13390    * active_streams : newly created streams from the latest moov
13391    * old_streams : existing streams (belong to previous moov)
13392    */
13393
13394   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13395     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13396     QtDemuxStream *oldstream = NULL;
13397     guint target;
13398
13399     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13400         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13401
13402     if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13403             stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13404       oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13405
13406       /* null pad stream cannot be reused */
13407       if (oldstream->pad == NULL)
13408         oldstream = NULL;
13409     }
13410
13411     if (oldstream) {
13412       GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13413
13414       if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13415         return FALSE;
13416
13417       /* we don't need to preserve order of old streams */
13418       g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13419     } else {
13420       GstTagList *list;
13421
13422       /* now we have all info and can expose */
13423       list = stream->stream_tags;
13424       stream->stream_tags = NULL;
13425       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13426         return FALSE;
13427     }
13428   }
13429
13430   return TRUE;
13431 }
13432
13433 /* Must be called with expose lock */
13434 static GstFlowReturn
13435 qtdemux_expose_streams (GstQTDemux * qtdemux)
13436 {
13437   gint i;
13438
13439   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13440
13441   if (!qtdemux_is_streams_update (qtdemux)) {
13442     GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13443     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13444       QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13445       QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13446       if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13447         return GST_FLOW_ERROR;
13448     }
13449
13450     g_ptr_array_set_size (qtdemux->old_streams, 0);
13451     qtdemux->need_segment = TRUE;
13452
13453     return GST_FLOW_OK;
13454   }
13455
13456   if (qtdemux->streams_aware) {
13457     if (!qtdemux_update_streams (qtdemux))
13458       return GST_FLOW_ERROR;
13459   } else {
13460     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13461       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13462       GstTagList *list;
13463
13464       /* now we have all info and can expose */
13465       list = stream->stream_tags;
13466       stream->stream_tags = NULL;
13467       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13468         return GST_FLOW_ERROR;
13469
13470     }
13471   }
13472
13473   gst_qtdemux_guess_bitrate (qtdemux);
13474
13475   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13476
13477   /* If we have still old_streams, it's no more used stream */
13478   for (i = 0; i < qtdemux->old_streams->len; i++) {
13479     QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13480
13481     if (stream->pad) {
13482       GstEvent *event;
13483
13484       event = gst_event_new_eos ();
13485       if (qtdemux->segment_seqnum)
13486         gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13487
13488       gst_pad_push_event (stream->pad, event);
13489     }
13490   }
13491
13492   g_ptr_array_set_size (qtdemux->old_streams, 0);
13493
13494   /* check if we should post a redirect in case there is a single trak
13495    * and it is a redirecting trak */
13496   if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13497       QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13498     GstMessage *m;
13499
13500     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13501         "an external content");
13502     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13503         gst_structure_new ("redirect",
13504             "new-location", G_TYPE_STRING,
13505             QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13506     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13507     qtdemux->posted_redirect = TRUE;
13508   }
13509
13510   g_ptr_array_foreach (qtdemux->active_streams,
13511       (GFunc) qtdemux_do_allocation, qtdemux);
13512
13513   qtdemux->need_segment = TRUE;
13514
13515   qtdemux->exposed = TRUE;
13516   return GST_FLOW_OK;
13517 }
13518
13519 /* check if major or compatible brand is 3GP */
13520 static inline gboolean
13521 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
13522 {
13523   if (major) {
13524     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
13525         FOURCC_3g__);
13526   } else if (qtdemux->comp_brands != NULL) {
13527     GstMapInfo map;
13528     guint8 *data;
13529     gsize size;
13530     gboolean res = FALSE;
13531
13532     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
13533     data = map.data;
13534     size = map.size;
13535     while (size >= 4) {
13536       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
13537           FOURCC_3g__);
13538       data += 4;
13539       size -= 4;
13540     }
13541     gst_buffer_unmap (qtdemux->comp_brands, &map);
13542     return res;
13543   } else {
13544     return FALSE;
13545   }
13546 }
13547
13548 /* check if tag is a spec'ed 3GP tag keyword storing a string */
13549 static inline gboolean
13550 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
13551 {
13552   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
13553       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
13554       || fourcc == FOURCC_albm;
13555 }
13556
13557 static void
13558 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
13559     const char *tag, const char *dummy, GNode * node)
13560 {
13561   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13562   int offset;
13563   char *name;
13564   gchar *data;
13565   gdouble longitude, latitude, altitude;
13566   gint len;
13567
13568   len = QT_UINT32 (node->data);
13569   if (len <= 14)
13570     goto short_read;
13571
13572   data = node->data;
13573   offset = 14;
13574
13575   /* TODO: language code skipped */
13576
13577   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
13578
13579   if (!name) {
13580     /* do not alarm in trivial case, but bail out otherwise */
13581     if (*(data + offset) != 0) {
13582       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
13583           "giving up", tag);
13584     }
13585   } else {
13586     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
13587         GST_TAG_GEO_LOCATION_NAME, name, NULL);
13588     offset += strlen (name);
13589     g_free (name);
13590   }
13591
13592   if (len < offset + 2 + 4 + 4 + 4)
13593     goto short_read;
13594
13595   /* +1 +1 = skip null-terminator and location role byte */
13596   offset += 1 + 1;
13597   /* table in spec says unsigned, semantics say negative has meaning ... */
13598   longitude = QT_SFP32 (data + offset);
13599
13600   offset += 4;
13601   latitude = QT_SFP32 (data + offset);
13602
13603   offset += 4;
13604   altitude = QT_SFP32 (data + offset);
13605
13606   /* one invalid means all are invalid */
13607   if (longitude >= -180.0 && longitude <= 180.0 &&
13608       latitude >= -90.0 && latitude <= 90.0) {
13609     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
13610         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
13611         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
13612         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
13613   }
13614
13615   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
13616
13617   return;
13618
13619   /* ERRORS */
13620 short_read:
13621   {
13622     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
13623     return;
13624   }
13625 }
13626
13627
13628 static void
13629 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
13630     const char *tag, const char *dummy, GNode * node)
13631 {
13632   guint16 y;
13633   GDate *date;
13634   gint len;
13635
13636   len = QT_UINT32 (node->data);
13637   if (len < 14)
13638     return;
13639
13640   y = QT_UINT16 ((guint8 *) node->data + 12);
13641   if (y == 0) {
13642     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
13643     return;
13644   }
13645   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
13646
13647   date = g_date_new_dmy (1, 1, y);
13648   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13649   g_date_free (date);
13650 }
13651
13652 static void
13653 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
13654     const char *tag, const char *dummy, GNode * node)
13655 {
13656   int offset;
13657   char *tag_str = NULL;
13658   guint8 *entity;
13659   guint16 table;
13660   gint len;
13661
13662   len = QT_UINT32 (node->data);
13663   if (len <= 20)
13664     goto short_read;
13665
13666   offset = 12;
13667   entity = (guint8 *) node->data + offset;
13668   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
13669     GST_DEBUG_OBJECT (qtdemux,
13670         "classification info: %c%c%c%c invalid classification entity",
13671         entity[0], entity[1], entity[2], entity[3]);
13672     return;
13673   }
13674
13675   offset += 4;
13676   table = QT_UINT16 ((guint8 *) node->data + offset);
13677
13678   /* Language code skipped */
13679
13680   offset += 4;
13681
13682   /* Tag format: "XXXX://Y[YYYY]/classification info string"
13683    * XXXX: classification entity, fixed length 4 chars.
13684    * Y[YYYY]: classification table, max 5 chars.
13685    */
13686   tag_str = g_strdup_printf ("----://%u/%s",
13687       table, (char *) node->data + offset);
13688
13689   /* memcpy To be sure we're preserving byte order */
13690   memcpy (tag_str, entity, 4);
13691   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
13692
13693   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
13694
13695   g_free (tag_str);
13696
13697   return;
13698
13699   /* ERRORS */
13700 short_read:
13701   {
13702     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
13703     return;
13704   }
13705 }
13706
13707 static gboolean
13708 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
13709     const char *tag, const char *dummy, GNode * node)
13710 {
13711   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13712   GNode *data;
13713   char *s;
13714   int len;
13715   guint32 type;
13716   int offset;
13717   gboolean ret = TRUE;
13718   const gchar *charset = NULL;
13719
13720   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13721   if (data) {
13722     len = QT_UINT32 (data->data);
13723     type = QT_UINT32 ((guint8 *) data->data + 8);
13724     if (type == 0x00000001 && len > 16) {
13725       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
13726           env_vars);
13727       if (s) {
13728         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13729         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13730         g_free (s);
13731       } else {
13732         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13733       }
13734     }
13735   } else {
13736     len = QT_UINT32 (node->data);
13737     type = QT_UINT32 ((guint8 *) node->data + 4);
13738     if ((type >> 24) == 0xa9 && len > 8 + 4) {
13739       gint str_len;
13740       gint lang_code;
13741
13742       /* Type starts with the (C) symbol, so the next data is a list
13743        * of (string size(16), language code(16), string) */
13744
13745       str_len = QT_UINT16 ((guint8 *) node->data + 8);
13746       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
13747
13748       /* the string + fourcc + size + 2 16bit fields,
13749        * means that there are more tags in this atom */
13750       if (len > str_len + 8 + 4) {
13751         /* TODO how to represent the same tag in different languages? */
13752         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
13753             "text alternatives, reading only first one");
13754       }
13755
13756       offset = 12;
13757       len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
13758       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
13759
13760       if (lang_code < 0x800) {  /* MAC encoded string */
13761         charset = "mac";
13762       }
13763     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
13764             QT_FOURCC ((guint8 *) node->data + 4))) {
13765       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
13766
13767       /* we go for 3GP style encoding if major brands claims so,
13768        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
13769       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13770           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
13771               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
13772         offset = 14;
13773         /* 16-bit Language code is ignored here as well */
13774         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
13775       } else {
13776         goto normal;
13777       }
13778     } else {
13779     normal:
13780       offset = 8;
13781       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
13782       ret = FALSE;              /* may have to fallback */
13783     }
13784     if (charset) {
13785       GError *err = NULL;
13786
13787       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
13788           charset, NULL, NULL, &err);
13789       if (err) {
13790         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
13791             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
13792             err->message);
13793         g_error_free (err);
13794       }
13795     } else {
13796       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13797           len - offset, env_vars);
13798     }
13799     if (s) {
13800       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13801       gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13802       g_free (s);
13803       ret = TRUE;
13804     } else {
13805       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13806     }
13807   }
13808   return ret;
13809 }
13810
13811 static void
13812 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
13813     const char *tag, const char *dummy, GNode * node)
13814 {
13815   qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
13816 }
13817
13818 static void
13819 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
13820     const char *tag, const char *dummy, GNode * node)
13821 {
13822   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13823   guint8 *data;
13824   char *s, *t, *k = NULL;
13825   int len;
13826   int offset;
13827   int count;
13828
13829   /* first try normal string tag if major brand not 3GP */
13830   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
13831     if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
13832       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
13833        * let's try it 3gpp way after minor safety check */
13834       data = node->data;
13835       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
13836         return;
13837     } else
13838       return;
13839   }
13840
13841   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
13842
13843   data = node->data;
13844
13845   len = QT_UINT32 (data);
13846   if (len < 15)
13847     goto short_read;
13848
13849   count = QT_UINT8 (data + 14);
13850   offset = 15;
13851   for (; count; count--) {
13852     gint slen;
13853
13854     if (offset + 1 > len)
13855       goto short_read;
13856     slen = QT_UINT8 (data + offset);
13857     offset += 1;
13858     if (offset + slen > len)
13859       goto short_read;
13860     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13861         slen, env_vars);
13862     if (s) {
13863       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
13864       if (k) {
13865         t = g_strjoin (",", k, s, NULL);
13866         g_free (s);
13867         g_free (k);
13868         k = t;
13869       } else {
13870         k = s;
13871       }
13872     } else {
13873       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
13874     }
13875     offset += slen;
13876   }
13877
13878 done:
13879   if (k) {
13880     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
13881     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
13882   }
13883   g_free (k);
13884
13885   return;
13886
13887   /* ERRORS */
13888 short_read:
13889   {
13890     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
13891     goto done;
13892   }
13893 }
13894
13895 static void
13896 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
13897     const char *tag1, const char *tag2, GNode * node)
13898 {
13899   GNode *data;
13900   int len;
13901   int type;
13902   int n1, n2;
13903
13904   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13905   if (data) {
13906     len = QT_UINT32 (data->data);
13907     type = QT_UINT32 ((guint8 *) data->data + 8);
13908     if (type == 0x00000000 && len >= 22) {
13909       n1 = QT_UINT16 ((guint8 *) data->data + 18);
13910       n2 = QT_UINT16 ((guint8 *) data->data + 20);
13911       if (n1 > 0) {
13912         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
13913         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
13914       }
13915       if (n2 > 0) {
13916         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
13917         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
13918       }
13919     }
13920   }
13921 }
13922
13923 static void
13924 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
13925     const char *tag1, const char *dummy, GNode * node)
13926 {
13927   GNode *data;
13928   int len;
13929   int type;
13930   int n1;
13931
13932   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13933   if (data) {
13934     len = QT_UINT32 (data->data);
13935     type = QT_UINT32 ((guint8 *) data->data + 8);
13936     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
13937     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13938     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
13939       n1 = QT_UINT16 ((guint8 *) data->data + 16);
13940       if (n1) {
13941         /* do not add bpm=0 */
13942         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
13943         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13944             NULL);
13945       }
13946     }
13947   }
13948 }
13949
13950 static void
13951 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13952     const char *tag1, const char *dummy, GNode * node)
13953 {
13954   GNode *data;
13955   int len;
13956   int type;
13957   guint32 num;
13958
13959   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13960   if (data) {
13961     len = QT_UINT32 (data->data);
13962     type = QT_UINT32 ((guint8 *) data->data + 8);
13963     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13964     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13965     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13966       num = QT_UINT32 ((guint8 *) data->data + 16);
13967       if (num) {
13968         /* do not add num=0 */
13969         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13970         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13971       }
13972     }
13973   }
13974 }
13975
13976 static void
13977 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13978     const char *tag1, const char *dummy, GNode * node)
13979 {
13980   GNode *data;
13981   int len;
13982   int type;
13983   GstSample *sample;
13984
13985   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13986   if (data) {
13987     len = QT_UINT32 (data->data);
13988     type = QT_UINT32 ((guint8 *) data->data + 8);
13989     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13990     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13991       GstTagImageType image_type;
13992
13993       if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13994         image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13995       else
13996         image_type = GST_TAG_IMAGE_TYPE_NONE;
13997
13998       if ((sample =
13999               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
14000                   len - 16, image_type))) {
14001         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
14002         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
14003         gst_sample_unref (sample);
14004       }
14005     }
14006   }
14007 }
14008
14009 static void
14010 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
14011     const char *tag, const char *dummy, GNode * node)
14012 {
14013   GNode *data;
14014   GstDateTime *datetime = NULL;
14015   char *s;
14016   int len;
14017   int type;
14018
14019   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14020   if (data) {
14021     len = QT_UINT32 (data->data);
14022     type = QT_UINT32 ((guint8 *) data->data + 8);
14023     if (type == 0x00000001 && len > 16) {
14024       guint y, m = 1, d = 1;
14025       gint ret;
14026
14027       s = g_strndup ((char *) data->data + 16, len - 16);
14028       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
14029       datetime = gst_date_time_new_from_iso8601_string (s);
14030       if (datetime != NULL) {
14031         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
14032             datetime, NULL);
14033         gst_date_time_unref (datetime);
14034       }
14035
14036       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
14037       if (ret >= 1 && y > 1500 && y < 3000) {
14038         GDate *date;
14039
14040         date = g_date_new_dmy (d, m, y);
14041         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
14042         g_date_free (date);
14043       } else {
14044         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
14045       }
14046       g_free (s);
14047     }
14048   }
14049 }
14050
14051 static void
14052 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
14053     const char *tag, const char *dummy, GNode * node)
14054 {
14055   GNode *data;
14056
14057   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14058
14059   /* re-route to normal string tag if major brand says so
14060    * or no data atom and compatible brand suggests so */
14061   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
14062       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
14063     qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
14064     return;
14065   }
14066
14067   if (data) {
14068     guint len, type, n;
14069
14070     len = QT_UINT32 (data->data);
14071     type = QT_UINT32 ((guint8 *) data->data + 8);
14072     if (type == 0x00000000 && len >= 18) {
14073       n = QT_UINT16 ((guint8 *) data->data + 16);
14074       if (n > 0) {
14075         const gchar *genre;
14076
14077         genre = gst_tag_id3_genre_get (n - 1);
14078         if (genre != NULL) {
14079           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
14080           gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
14081         }
14082       }
14083     }
14084   }
14085 }
14086
14087 static void
14088 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
14089     const gchar * tag, guint8 * data, guint32 datasize)
14090 {
14091   gdouble value;
14092   gchar *datacopy;
14093
14094   /* make a copy to have \0 at the end */
14095   datacopy = g_strndup ((gchar *) data, datasize);
14096
14097   /* convert the str to double */
14098   if (sscanf (datacopy, "%lf", &value) == 1) {
14099     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
14100     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
14101   } else {
14102     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
14103         datacopy);
14104   }
14105   g_free (datacopy);
14106 }
14107
14108
14109 static void
14110 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
14111     const char *tag, const char *tag_bis, GNode * node)
14112 {
14113   GNode *mean;
14114   GNode *name;
14115   GNode *data;
14116   guint32 meansize;
14117   guint32 namesize;
14118   guint32 datatype;
14119   guint32 datasize;
14120   const gchar *meanstr;
14121   const gchar *namestr;
14122
14123   /* checking the whole ---- atom size for consistency */
14124   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
14125     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
14126     return;
14127   }
14128
14129   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
14130   if (!mean) {
14131     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
14132     return;
14133   }
14134
14135   meansize = QT_UINT32 (mean->data);
14136   if (meansize <= 12) {
14137     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
14138     return;
14139   }
14140   meanstr = ((gchar *) mean->data) + 12;
14141   meansize -= 12;
14142
14143   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
14144   if (!name) {
14145     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
14146     return;
14147   }
14148
14149   namesize = QT_UINT32 (name->data);
14150   if (namesize <= 12) {
14151     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
14152     return;
14153   }
14154   namestr = ((gchar *) name->data) + 12;
14155   namesize -= 12;
14156
14157   /*
14158    * Data atom is:
14159    * uint32 - size
14160    * uint32 - name
14161    * uint8  - version
14162    * uint24 - data type
14163    * uint32 - all 0
14164    * rest   - the data
14165    */
14166   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14167   if (!data) {
14168     GST_WARNING_OBJECT (demux, "No data atom in this tag");
14169     return;
14170   }
14171   datasize = QT_UINT32 (data->data);
14172   if (datasize <= 16) {
14173     GST_WARNING_OBJECT (demux, "Data atom too small");
14174     return;
14175   }
14176   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
14177
14178   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
14179       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
14180     static const struct
14181     {
14182       const gchar name[28];
14183       const gchar tag[28];
14184     } tags[] = {
14185       {
14186       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
14187       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
14188       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
14189       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
14190       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
14191       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
14192       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
14193       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
14194     };
14195     int i;
14196
14197     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
14198       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
14199         switch (gst_tag_get_type (tags[i].tag)) {
14200           case G_TYPE_DOUBLE:
14201             qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
14202                 ((guint8 *) data->data) + 16, datasize - 16);
14203             break;
14204           case G_TYPE_STRING:
14205             qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
14206             break;
14207           default:
14208             /* not reached */
14209             break;
14210         }
14211         break;
14212       }
14213     }
14214     if (i == G_N_ELEMENTS (tags))
14215       goto unknown_tag;
14216   } else {
14217     goto unknown_tag;
14218   }
14219
14220   return;
14221
14222 /* errors */
14223 unknown_tag:
14224 #ifndef GST_DISABLE_GST_DEBUG
14225   {
14226     gchar *namestr_dbg;
14227     gchar *meanstr_dbg;
14228
14229     meanstr_dbg = g_strndup (meanstr, meansize);
14230     namestr_dbg = g_strndup (namestr, namesize);
14231
14232     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
14233         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
14234
14235     g_free (namestr_dbg);
14236     g_free (meanstr_dbg);
14237   }
14238 #endif
14239   return;
14240 }
14241
14242 static void
14243 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
14244     const char *tag_bis, GNode * node)
14245 {
14246   guint8 *data;
14247   GstBuffer *buf;
14248   guint len;
14249   GstTagList *id32_taglist = NULL;
14250
14251   GST_LOG_OBJECT (demux, "parsing ID32");
14252
14253   data = node->data;
14254   len = GST_READ_UINT32_BE (data);
14255
14256   /* need at least full box and language tag */
14257   if (len < 12 + 2)
14258     return;
14259
14260   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
14261   gst_buffer_fill (buf, 0, data + 14, len - 14);
14262
14263   id32_taglist = gst_tag_list_from_id3v2_tag (buf);
14264   if (id32_taglist) {
14265     GST_LOG_OBJECT (demux, "parsing ok");
14266     gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
14267     gst_tag_list_unref (id32_taglist);
14268   } else {
14269     GST_LOG_OBJECT (demux, "parsing failed");
14270   }
14271
14272   gst_buffer_unref (buf);
14273 }
14274
14275 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
14276     const char *tag, const char *tag_bis, GNode * node);
14277
14278 /* unmapped tags
14279 FOURCC_pcst -> if media is a podcast -> bool
14280 FOURCC_cpil -> if media is part of a compilation -> bool
14281 FOURCC_pgap -> if media is part of a gapless context -> bool
14282 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
14283 */
14284
14285 static const struct
14286 {
14287   guint32 fourcc;
14288   const gchar *gst_tag;
14289   const gchar *gst_tag_bis;
14290   const GstQTDemuxAddTagFunc func;
14291 } add_funcs[] = {
14292   {
14293   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
14294   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
14295   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
14296   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
14297   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
14298   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
14299   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
14300   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
14301   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
14302   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
14303   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
14304   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
14305   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
14306   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14307   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14308   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14309   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
14310   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
14311   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
14312   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
14313   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
14314   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
14315   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
14316         qtdemux_tag_add_num}, {
14317   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
14318         qtdemux_tag_add_num}, {
14319   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
14320   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
14321   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
14322   FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
14323   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
14324   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
14325   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
14326   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
14327   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
14328   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
14329   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
14330   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
14331   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
14332   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
14333   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
14334   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
14335   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
14336   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
14337         qtdemux_tag_add_classification}, {
14338   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
14339   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
14340   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
14341
14342     /* This is a special case, some tags are stored in this
14343      * 'reverse dns naming', according to:
14344      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
14345      * bug #614471
14346      */
14347   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
14348     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
14349   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
14350 };
14351
14352 struct _GstQtDemuxTagList
14353 {
14354   GstQTDemux *demux;
14355   GstTagList *taglist;
14356 };
14357 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
14358
14359 static void
14360 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
14361 {
14362   gint len;
14363   guint8 *data;
14364   GstBuffer *buf;
14365   gchar *media_type;
14366   const gchar *style;
14367   GstSample *sample;
14368   GstStructure *s;
14369   guint i;
14370   guint8 ndata[4];
14371   GstQTDemux *demux = qtdemuxtaglist->demux;
14372   GstTagList *taglist = qtdemuxtaglist->taglist;
14373
14374   data = node->data;
14375   len = QT_UINT32 (data);
14376   buf = gst_buffer_new_and_alloc (len);
14377   gst_buffer_fill (buf, 0, data, len);
14378
14379   /* heuristic to determine style of tag */
14380   if (QT_FOURCC (data + 4) == FOURCC_____ ||
14381       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
14382     style = "itunes";
14383   else if (demux->major_brand == FOURCC_qt__)
14384     style = "quicktime";
14385   /* fall back to assuming iso/3gp tag style */
14386   else
14387     style = "iso";
14388
14389   /* santize the name for the caps. */
14390   for (i = 0; i < 4; i++) {
14391     guint8 d = data[4 + i];
14392     if (g_ascii_isalnum (d))
14393       ndata[i] = g_ascii_tolower (d);
14394     else
14395       ndata[i] = '_';
14396   }
14397
14398   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
14399       ndata[0], ndata[1], ndata[2], ndata[3]);
14400   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
14401
14402   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
14403   sample = gst_sample_new (buf, NULL, NULL, s);
14404   gst_buffer_unref (buf);
14405   g_free (media_type);
14406
14407   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
14408       len, s);
14409
14410   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
14411       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
14412
14413   gst_sample_unref (sample);
14414 }
14415
14416 static void
14417 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
14418 {
14419   GNode *meta;
14420   GNode *ilst;
14421   GNode *xmp_;
14422   GNode *node;
14423   gint i;
14424   GstQtDemuxTagList demuxtaglist;
14425
14426   demuxtaglist.demux = qtdemux;
14427   demuxtaglist.taglist = taglist;
14428
14429   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
14430   if (meta != NULL) {
14431     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
14432     if (ilst == NULL) {
14433       GST_LOG_OBJECT (qtdemux, "no ilst");
14434       return;
14435     }
14436   } else {
14437     ilst = udta;
14438     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
14439   }
14440
14441   i = 0;
14442   while (i < G_N_ELEMENTS (add_funcs)) {
14443     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
14444     if (node) {
14445       gint len;
14446
14447       len = QT_UINT32 (node->data);
14448       if (len < 12) {
14449         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
14450             GST_FOURCC_ARGS (add_funcs[i].fourcc));
14451       } else {
14452         add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
14453             add_funcs[i].gst_tag_bis, node);
14454       }
14455       g_node_destroy (node);
14456     } else {
14457       i++;
14458     }
14459   }
14460
14461   /* parsed nodes have been removed, pass along remainder as blob */
14462   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
14463       (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
14464
14465   /* parse up XMP_ node if existing */
14466   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
14467   if (xmp_ != NULL) {
14468     GstBuffer *buf;
14469     GstTagList *xmptaglist;
14470
14471     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
14472         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
14473     xmptaglist = gst_tag_list_from_xmp_buffer (buf);
14474     gst_buffer_unref (buf);
14475
14476     qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
14477   } else {
14478     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
14479   }
14480 }
14481
14482 typedef struct
14483 {
14484   GstStructure *structure;      /* helper for sort function */
14485   gchar *location;
14486   guint min_req_bitrate;
14487   guint min_req_qt_version;
14488 } GstQtReference;
14489
14490 static gint
14491 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
14492 {
14493   GstQtReference *ref_a = (GstQtReference *) a;
14494   GstQtReference *ref_b = (GstQtReference *) b;
14495
14496   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
14497     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
14498
14499   /* known bitrates go before unknown; higher bitrates go first */
14500   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
14501 }
14502
14503 /* sort the redirects and post a message for the application.
14504  */
14505 static void
14506 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
14507 {
14508   GstQtReference *best;
14509   GstStructure *s;
14510   GstMessage *msg;
14511   GValue list_val = { 0, };
14512   GList *l;
14513
14514   g_assert (references != NULL);
14515
14516   references = g_list_sort (references, qtdemux_redirects_sort_func);
14517
14518   best = (GstQtReference *) references->data;
14519
14520   g_value_init (&list_val, GST_TYPE_LIST);
14521
14522   for (l = references; l != NULL; l = l->next) {
14523     GstQtReference *ref = (GstQtReference *) l->data;
14524     GValue struct_val = { 0, };
14525
14526     ref->structure = gst_structure_new ("redirect",
14527         "new-location", G_TYPE_STRING, ref->location, NULL);
14528
14529     if (ref->min_req_bitrate > 0) {
14530       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
14531           ref->min_req_bitrate, NULL);
14532     }
14533
14534     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
14535     g_value_set_boxed (&struct_val, ref->structure);
14536     gst_value_list_append_value (&list_val, &struct_val);
14537     g_value_unset (&struct_val);
14538     /* don't free anything here yet, since we need best->structure below */
14539   }
14540
14541   g_assert (best != NULL);
14542   s = gst_structure_copy (best->structure);
14543
14544   if (g_list_length (references) > 1) {
14545     gst_structure_set_value (s, "locations", &list_val);
14546   }
14547
14548   g_value_unset (&list_val);
14549
14550   for (l = references; l != NULL; l = l->next) {
14551     GstQtReference *ref = (GstQtReference *) l->data;
14552
14553     gst_structure_free (ref->structure);
14554     g_free (ref->location);
14555     g_free (ref);
14556   }
14557   g_list_free (references);
14558
14559   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
14560   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
14561   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
14562   qtdemux->posted_redirect = TRUE;
14563 }
14564
14565 /* look for redirect nodes, collect all redirect information and
14566  * process it.
14567  */
14568 static gboolean
14569 qtdemux_parse_redirects (GstQTDemux * qtdemux)
14570 {
14571   GNode *rmra, *rmda, *rdrf;
14572
14573   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
14574   if (rmra) {
14575     GList *redirects = NULL;
14576
14577     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
14578     while (rmda) {
14579       GstQtReference ref = { NULL, NULL, 0, 0 };
14580       GNode *rmdr, *rmvc;
14581
14582       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
14583         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
14584         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
14585             ref.min_req_bitrate);
14586       }
14587
14588       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
14589         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
14590         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
14591
14592 #ifndef GST_DISABLE_GST_DEBUG
14593         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
14594 #endif
14595         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
14596
14597         GST_LOG_OBJECT (qtdemux,
14598             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
14599             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
14600             bitmask, check_type);
14601         if (package == FOURCC_qtim && check_type == 0) {
14602           ref.min_req_qt_version = version;
14603         }
14604       }
14605
14606       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
14607       if (rdrf) {
14608         guint32 ref_type;
14609         guint8 *ref_data;
14610         guint ref_len;
14611
14612         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
14613         if (ref_len > 20) {
14614           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
14615           ref_data = (guint8 *) rdrf->data + 20;
14616           if (ref_type == FOURCC_alis) {
14617             guint record_len, record_version, fn_len;
14618
14619             if (ref_len > 70) {
14620               /* MacOSX alias record, google for alias-layout.txt */
14621               record_len = QT_UINT16 (ref_data + 4);
14622               record_version = QT_UINT16 (ref_data + 4 + 2);
14623               fn_len = QT_UINT8 (ref_data + 50);
14624               if (record_len > 50 && record_version == 2 && fn_len > 0) {
14625                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
14626               }
14627             } else {
14628               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
14629                   ref_len);
14630             }
14631           } else if (ref_type == FOURCC_url_) {
14632             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
14633           } else {
14634             GST_DEBUG_OBJECT (qtdemux,
14635                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
14636                 GST_FOURCC_ARGS (ref_type));
14637           }
14638           if (ref.location != NULL) {
14639             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
14640             redirects =
14641                 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
14642           } else {
14643             GST_WARNING_OBJECT (qtdemux,
14644                 "Failed to extract redirect location from rdrf atom");
14645           }
14646         } else {
14647           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
14648         }
14649       }
14650
14651       /* look for others */
14652       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
14653     }
14654
14655     if (redirects != NULL) {
14656       qtdemux_process_redirects (qtdemux, redirects);
14657     }
14658   }
14659   return TRUE;
14660 }
14661
14662 static GstTagList *
14663 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
14664 {
14665   const gchar *fmt;
14666
14667   if (tags == NULL) {
14668     tags = gst_tag_list_new_empty ();
14669     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
14670   }
14671
14672   if (qtdemux->major_brand == FOURCC_mjp2)
14673     fmt = "Motion JPEG 2000";
14674   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
14675     fmt = "3GP";
14676   else if (qtdemux->major_brand == FOURCC_qt__)
14677     fmt = "Quicktime";
14678   else if (qtdemux->fragmented)
14679     fmt = "ISO fMP4";
14680   else
14681     fmt = "ISO MP4/M4A";
14682
14683   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
14684       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
14685
14686   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
14687       fmt, NULL);
14688
14689   return tags;
14690 }
14691
14692 /* we have read the complete moov node now.
14693  * This function parses all of the relevant info, creates the traks and
14694  * prepares all data structures for playback
14695  */
14696 static gboolean
14697 qtdemux_parse_tree (GstQTDemux * qtdemux)
14698 {
14699   GNode *mvhd;
14700   GNode *trak;
14701   GNode *udta;
14702   GNode *mvex;
14703   GNode *pssh;
14704   guint64 creation_time;
14705   GstDateTime *datetime = NULL;
14706   gint version;
14707
14708   /* make sure we have a usable taglist */
14709   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14710
14711   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14712   if (mvhd == NULL) {
14713     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14714     return qtdemux_parse_redirects (qtdemux);
14715   }
14716
14717   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14718   if (version == 1) {
14719     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14720     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14721     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14722   } else if (version == 0) {
14723     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14724     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14725     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14726   } else {
14727     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14728     return FALSE;
14729   }
14730
14731   /* Moving qt creation time (secs since 1904) to unix time */
14732   if (creation_time != 0) {
14733     /* Try to use epoch first as it should be faster and more commonly found */
14734     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14735       GTimeVal now;
14736
14737       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14738       /* some data cleansing sanity */
14739       g_get_current_time (&now);
14740       if (now.tv_sec + 24 * 3600 < creation_time) {
14741         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14742       } else {
14743         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14744       }
14745     } else {
14746       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14747       GDateTime *dt, *dt_local;
14748
14749       dt = g_date_time_add_seconds (base_dt, creation_time);
14750       dt_local = g_date_time_to_local (dt);
14751       datetime = gst_date_time_new_from_g_date_time (dt_local);
14752
14753       g_date_time_unref (base_dt);
14754       g_date_time_unref (dt);
14755     }
14756   }
14757   if (datetime) {
14758     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14759     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14760         datetime, NULL);
14761     gst_date_time_unref (datetime);
14762   }
14763
14764   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14765   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14766
14767   /* check for fragmented file and get some (default) data */
14768   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14769   if (mvex) {
14770     GNode *mehd;
14771     GstByteReader mehd_data;
14772
14773     /* let track parsing or anyone know weird stuff might happen ... */
14774     qtdemux->fragmented = TRUE;
14775
14776     /* compensate for total duration */
14777     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14778     if (mehd)
14779       qtdemux_parse_mehd (qtdemux, &mehd_data);
14780   }
14781
14782   /* Update the movie segment duration, unless it was directly given to us
14783    * by upstream. Otherwise let it as is, as we don't want to mangle the
14784    * duration provided by upstream that may come e.g. from a MPD file. */
14785   if (!qtdemux->upstream_format_is_time) {
14786     GstClockTime duration;
14787     /* set duration in the segment info */
14788     gst_qtdemux_get_duration (qtdemux, &duration);
14789     qtdemux->segment.duration = duration;
14790     /* also do not exceed duration; stop is set that way post seek anyway,
14791      * and segment activation falls back to duration,
14792      * whereas loop only checks stop, so let's align this here as well */
14793     qtdemux->segment.stop = duration;
14794   }
14795
14796   /* parse all traks */
14797   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14798   while (trak) {
14799     qtdemux_parse_trak (qtdemux, trak);
14800     /* iterate all siblings */
14801     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14802   }
14803
14804   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14805
14806   /* find tags */
14807   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14808   if (udta) {
14809     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14810   } else {
14811     GST_LOG_OBJECT (qtdemux, "No udta node found.");
14812   }
14813
14814   /* maybe also some tags in meta box */
14815   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14816   if (udta) {
14817     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14818     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14819   } else {
14820     GST_LOG_OBJECT (qtdemux, "No meta node found.");
14821   }
14822
14823   /* parse any protection system info */
14824   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14825   while (pssh) {
14826     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14827     qtdemux_parse_pssh (qtdemux, pssh);
14828     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14829   }
14830
14831   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14832
14833   return TRUE;
14834 }
14835
14836 /* taken from ffmpeg */
14837 static int
14838 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14839 {
14840   int count = 4;
14841   int len = 0;
14842
14843   while (count--) {
14844     int c;
14845
14846     if (ptr >= end)
14847       return -1;
14848
14849     c = *ptr++;
14850     len = (len << 7) | (c & 0x7f);
14851     if (!(c & 0x80))
14852       break;
14853   }
14854   *end_out = ptr;
14855   return len;
14856 }
14857
14858 static GList *
14859 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14860     gsize codec_data_size)
14861 {
14862   GList *list = NULL;
14863   guint8 *p = codec_data;
14864   gint i, offset, num_packets;
14865   guint *length, last;
14866
14867   GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14868
14869   if (codec_data == NULL || codec_data_size == 0)
14870     goto error;
14871
14872   /* start of the stream and vorbis audio or theora video, need to
14873    * send the codec_priv data as first three packets */
14874   num_packets = p[0] + 1;
14875   GST_DEBUG_OBJECT (qtdemux,
14876       "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14877       (guint) num_packets, codec_data_size);
14878
14879   /* Let's put some limits, Don't think there even is a xiph codec
14880    * with more than 3-4 headers */
14881   if (G_UNLIKELY (num_packets > 16)) {
14882     GST_WARNING_OBJECT (qtdemux,
14883         "Unlikely number of xiph headers, most likely not valid");
14884     goto error;
14885   }
14886
14887   length = g_alloca (num_packets * sizeof (guint));
14888   last = 0;
14889   offset = 1;
14890
14891   /* first packets, read length values */
14892   for (i = 0; i < num_packets - 1; i++) {
14893     length[i] = 0;
14894     while (offset < codec_data_size) {
14895       length[i] += p[offset];
14896       if (p[offset++] != 0xff)
14897         break;
14898     }
14899     last += length[i];
14900   }
14901   if (offset + last > codec_data_size)
14902     goto error;
14903
14904   /* last packet is the remaining size */
14905   length[i] = codec_data_size - offset - last;
14906
14907   for (i = 0; i < num_packets; i++) {
14908     GstBuffer *hdr;
14909
14910     GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14911
14912     if (offset + length[i] > codec_data_size)
14913       goto error;
14914
14915     hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
14916     list = g_list_append (list, hdr);
14917
14918     offset += length[i];
14919   }
14920
14921   return list;
14922
14923   /* ERRORS */
14924 error:
14925   {
14926     if (list != NULL)
14927       g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14928     return NULL;
14929   }
14930
14931 }
14932
14933 /* this can change the codec originally present in @list */
14934 static void
14935 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14936     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14937 {
14938   int len = QT_UINT32 (esds->data);
14939   guint8 *ptr = esds->data;
14940   guint8 *end = ptr + len;
14941   int tag;
14942   guint8 *data_ptr = NULL;
14943   int data_len = 0;
14944   guint8 object_type_id = 0;
14945   guint8 stream_type = 0;
14946   const char *codec_name = NULL;
14947   GstCaps *caps = NULL;
14948
14949   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14950   ptr += 8;
14951   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14952   ptr += 4;
14953   while (ptr + 1 < end) {
14954     tag = QT_UINT8 (ptr);
14955     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14956     ptr++;
14957     len = read_descr_size (ptr, end, &ptr);
14958     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14959
14960     /* Check the stated amount of data is available for reading */
14961     if (len < 0 || ptr + len > end)
14962       break;
14963
14964     switch (tag) {
14965       case ES_DESCRIPTOR_TAG:
14966         GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14967         GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14968         ptr += 3;
14969         break;
14970       case DECODER_CONFIG_DESC_TAG:{
14971         guint max_bitrate, avg_bitrate;
14972
14973         object_type_id = QT_UINT8 (ptr);
14974         stream_type = QT_UINT8 (ptr + 1) >> 2;
14975         max_bitrate = QT_UINT32 (ptr + 5);
14976         avg_bitrate = QT_UINT32 (ptr + 9);
14977         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14978         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14979         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14980         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14981         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14982         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14983           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14984               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14985         }
14986         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14987           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14988               avg_bitrate, NULL);
14989         }
14990         ptr += 13;
14991         break;
14992       }
14993       case DECODER_SPECIFIC_INFO_TAG:
14994         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14995         if (object_type_id == 0xe0 && len == 0x40) {
14996           guint8 *data;
14997           GstStructure *s;
14998           guint32 clut[16];
14999           gint i;
15000
15001           GST_DEBUG_OBJECT (qtdemux,
15002               "Have VOBSUB palette. Creating palette event");
15003           /* move to decConfigDescr data and read palette */
15004           data = ptr;
15005           for (i = 0; i < 16; i++) {
15006             clut[i] = QT_UINT32 (data);
15007             data += 4;
15008           }
15009
15010           s = gst_structure_new ("application/x-gst-dvd", "event",
15011               G_TYPE_STRING, "dvd-spu-clut-change",
15012               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
15013               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
15014               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
15015               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
15016               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
15017               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
15018               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
15019               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
15020               NULL);
15021
15022           /* store event and trigger custom processing */
15023           stream->pending_event =
15024               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
15025         } else {
15026           /* Generic codec_data handler puts it on the caps */
15027           data_ptr = ptr;
15028           data_len = len;
15029         }
15030
15031         ptr += len;
15032         break;
15033       case SL_CONFIG_DESC_TAG:
15034         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
15035         ptr += 1;
15036         break;
15037       default:
15038         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
15039             tag);
15040         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
15041         ptr += len;
15042         break;
15043     }
15044   }
15045
15046   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
15047    * in use, and should also be used to override some other parameters for some
15048    * codecs. */
15049   switch (object_type_id) {
15050     case 0x20:                 /* MPEG-4 */
15051       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
15052        * profile_and_level_indication */
15053       if (data_ptr != NULL && data_len >= 5 &&
15054           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
15055         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
15056             data_ptr + 4, data_len - 4);
15057       }
15058       break;                    /* Nothing special needed here */
15059     case 0x21:                 /* H.264 */
15060       codec_name = "H.264 / AVC";
15061       caps = gst_caps_new_simple ("video/x-h264",
15062           "stream-format", G_TYPE_STRING, "avc",
15063           "alignment", G_TYPE_STRING, "au", NULL);
15064       break;
15065     case 0x40:                 /* AAC (any) */
15066     case 0x66:                 /* AAC Main */
15067     case 0x67:                 /* AAC LC */
15068     case 0x68:                 /* AAC SSR */
15069       /* Override channels and rate based on the codec_data, as it's often
15070        * wrong. */
15071       /* Only do so for basic setup without HE-AAC extension */
15072       if (data_ptr && data_len == 2) {
15073         guint channels, rate;
15074
15075         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
15076         if (channels > 0)
15077           entry->n_channels = channels;
15078
15079         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
15080         if (rate > 0)
15081           entry->rate = rate;
15082       }
15083
15084       /* Set level and profile if possible */
15085       if (data_ptr != NULL && data_len >= 2) {
15086         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
15087             data_ptr, data_len);
15088       } else {
15089         const gchar *profile_str = NULL;
15090         GstBuffer *buffer;
15091         GstMapInfo map;
15092         guint8 *codec_data;
15093         gint rate_idx, profile;
15094
15095         /* No codec_data, let's invent something.
15096          * FIXME: This is wrong for SBR! */
15097
15098         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
15099
15100         buffer = gst_buffer_new_and_alloc (2);
15101         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
15102         codec_data = map.data;
15103
15104         rate_idx =
15105             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
15106             (stream)->rate);
15107
15108         switch (object_type_id) {
15109           case 0x66:
15110             profile_str = "main";
15111             profile = 0;
15112             break;
15113           case 0x67:
15114             profile_str = "lc";
15115             profile = 1;
15116             break;
15117           case 0x68:
15118             profile_str = "ssr";
15119             profile = 2;
15120             break;
15121           default:
15122             profile = 3;
15123             break;
15124         }
15125
15126         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
15127         codec_data[1] =
15128             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
15129
15130         gst_buffer_unmap (buffer, &map);
15131         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
15132             GST_TYPE_BUFFER, buffer, NULL);
15133         gst_buffer_unref (buffer);
15134
15135         if (profile_str) {
15136           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
15137               G_TYPE_STRING, profile_str, NULL);
15138         }
15139       }
15140       break;
15141     case 0x60:                 /* MPEG-2, various profiles */
15142     case 0x61:
15143     case 0x62:
15144     case 0x63:
15145     case 0x64:
15146     case 0x65:
15147       codec_name = "MPEG-2 video";
15148       caps = gst_caps_new_simple ("video/mpeg",
15149           "mpegversion", G_TYPE_INT, 2,
15150           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15151       break;
15152     case 0x69:                 /* MPEG-2 BC audio */
15153     case 0x6B:                 /* MPEG-1 audio */
15154       caps = gst_caps_new_simple ("audio/mpeg",
15155           "mpegversion", G_TYPE_INT, 1, NULL);
15156       codec_name = "MPEG-1 audio";
15157       break;
15158     case 0x6A:                 /* MPEG-1 */
15159       codec_name = "MPEG-1 video";
15160       caps = gst_caps_new_simple ("video/mpeg",
15161           "mpegversion", G_TYPE_INT, 1,
15162           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15163       break;
15164     case 0x6C:                 /* MJPEG */
15165       caps =
15166           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15167           NULL);
15168       codec_name = "Motion-JPEG";
15169       break;
15170     case 0x6D:                 /* PNG */
15171       caps =
15172           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
15173           NULL);
15174       codec_name = "PNG still images";
15175       break;
15176     case 0x6E:                 /* JPEG2000 */
15177       codec_name = "JPEG-2000";
15178       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15179       break;
15180     case 0xA4:                 /* Dirac */
15181       codec_name = "Dirac";
15182       caps = gst_caps_new_empty_simple ("video/x-dirac");
15183       break;
15184     case 0xA5:                 /* AC3 */
15185       codec_name = "AC-3 audio";
15186       caps = gst_caps_new_simple ("audio/x-ac3",
15187           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15188       break;
15189     case 0xA9:                 /* AC3 */
15190       codec_name = "DTS audio";
15191       caps = gst_caps_new_simple ("audio/x-dts",
15192           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15193       break;
15194     case 0xDD:
15195       if (stream_type == 0x05 && data_ptr) {
15196         GList *headers =
15197             parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
15198         if (headers) {
15199           GList *tmp;
15200           GValue arr_val = G_VALUE_INIT;
15201           GValue buf_val = G_VALUE_INIT;
15202           GstStructure *s;
15203
15204           /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
15205           codec_name = "Vorbis";
15206           caps = gst_caps_new_empty_simple ("audio/x-vorbis");
15207           g_value_init (&arr_val, GST_TYPE_ARRAY);
15208           g_value_init (&buf_val, GST_TYPE_BUFFER);
15209           for (tmp = headers; tmp; tmp = tmp->next) {
15210             g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
15211             gst_value_array_append_value (&arr_val, &buf_val);
15212           }
15213           s = gst_caps_get_structure (caps, 0);
15214           gst_structure_take_value (s, "streamheader", &arr_val);
15215           g_value_unset (&buf_val);
15216           g_list_free (headers);
15217
15218           data_ptr = NULL;
15219           data_len = 0;
15220         }
15221       }
15222       break;
15223     case 0xE1:                 /* QCELP */
15224       /* QCELP, the codec_data is a riff tag (little endian) with
15225        * 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). */
15226       caps = gst_caps_new_empty_simple ("audio/qcelp");
15227       codec_name = "QCELP";
15228       break;
15229     default:
15230       break;
15231   }
15232
15233   /* If we have a replacement caps, then change our caps for this stream */
15234   if (caps) {
15235     gst_caps_unref (entry->caps);
15236     entry->caps = caps;
15237   }
15238
15239   if (codec_name && list)
15240     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
15241         GST_TAG_AUDIO_CODEC, codec_name, NULL);
15242
15243   /* Add the codec_data attribute to caps, if we have it */
15244   if (data_ptr) {
15245     GstBuffer *buffer;
15246
15247     buffer = gst_buffer_new_and_alloc (data_len);
15248     gst_buffer_fill (buffer, 0, data_ptr, data_len);
15249
15250     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
15251     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
15252
15253     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
15254         buffer, NULL);
15255     gst_buffer_unref (buffer);
15256   }
15257
15258 }
15259
15260 static inline GstCaps *
15261 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
15262 {
15263   GstCaps *caps;
15264   guint i;
15265   char *s, fourstr[5];
15266
15267   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
15268   for (i = 0; i < 4; i++) {
15269     if (!g_ascii_isalnum (fourstr[i]))
15270       fourstr[i] = '_';
15271   }
15272   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
15273   caps = gst_caps_new_empty_simple (s);
15274   g_free (s);
15275   return caps;
15276 }
15277
15278 #define _codec(name) \
15279   do { \
15280     if (codec_name) { \
15281       *codec_name = g_strdup (name); \
15282     } \
15283   } while (0)
15284
15285 static GstCaps *
15286 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15287     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15288     const guint8 * stsd_entry_data, gchar ** codec_name)
15289 {
15290   GstCaps *caps = NULL;
15291   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
15292
15293   switch (fourcc) {
15294     case FOURCC_png:
15295       _codec ("PNG still images");
15296       caps = gst_caps_new_empty_simple ("image/png");
15297       break;
15298     case FOURCC_jpeg:
15299       _codec ("JPEG still images");
15300       caps =
15301           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15302           NULL);
15303       break;
15304     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
15305     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
15306     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
15307     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
15308       _codec ("Motion-JPEG");
15309       caps =
15310           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15311           NULL);
15312       break;
15313     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
15314       _codec ("Motion-JPEG format B");
15315       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
15316       break;
15317     case FOURCC_mjp2:
15318       _codec ("JPEG-2000");
15319       /* override to what it should be according to spec, avoid palette_data */
15320       entry->bits_per_sample = 24;
15321       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15322       break;
15323     case FOURCC_SVQ3:
15324       _codec ("Sorensen video v.3");
15325       caps = gst_caps_new_simple ("video/x-svq",
15326           "svqversion", G_TYPE_INT, 3, NULL);
15327       break;
15328     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
15329     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
15330       _codec ("Sorensen video v.1");
15331       caps = gst_caps_new_simple ("video/x-svq",
15332           "svqversion", G_TYPE_INT, 1, NULL);
15333       break;
15334     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
15335       caps = gst_caps_new_empty_simple ("video/x-raw");
15336       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
15337       _codec ("Windows Raw RGB");
15338       stream->alignment = 32;
15339       break;
15340     case FOURCC_raw_:
15341     {
15342       guint16 bps;
15343
15344       bps = QT_UINT16 (stsd_entry_data + 82);
15345       switch (bps) {
15346         case 15:
15347           format = GST_VIDEO_FORMAT_RGB15;
15348           break;
15349         case 16:
15350           format = GST_VIDEO_FORMAT_RGB16;
15351           break;
15352         case 24:
15353           format = GST_VIDEO_FORMAT_RGB;
15354           break;
15355         case 32:
15356           format = GST_VIDEO_FORMAT_ARGB;
15357           break;
15358         default:
15359           /* unknown */
15360           break;
15361       }
15362       break;
15363     }
15364     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
15365       format = GST_VIDEO_FORMAT_I420;
15366       break;
15367     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
15368     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
15369       format = GST_VIDEO_FORMAT_I420;
15370       break;
15371     case FOURCC_2vuy:
15372     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
15373       format = GST_VIDEO_FORMAT_UYVY;
15374       break;
15375     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
15376       format = GST_VIDEO_FORMAT_v308;
15377       break;
15378     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
15379       format = GST_VIDEO_FORMAT_v216;
15380       break;
15381     case FOURCC_v210:
15382       format = GST_VIDEO_FORMAT_v210;
15383       break;
15384     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
15385       format = GST_VIDEO_FORMAT_r210;
15386       break;
15387       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
15388          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
15389          format = GST_VIDEO_FORMAT_v410;
15390          break;
15391        */
15392       /* Packed YUV 4:4:4:4 8 bit in 32 bits
15393        * but different order than AYUV
15394        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
15395        format = GST_VIDEO_FORMAT_v408;
15396        break;
15397        */
15398     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
15399     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
15400       _codec ("MPEG-1 video");
15401       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15402           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15403       break;
15404     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
15405     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
15406     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
15407     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
15408     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
15409     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
15410     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
15411     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
15412     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
15413     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
15414     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
15415     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
15416     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
15417     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
15418     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
15419     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
15420     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
15421     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
15422     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
15423     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
15424     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
15425     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
15426     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
15427     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
15428     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
15429     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
15430     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
15431     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
15432     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
15433     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
15434     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
15435     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
15436     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
15437     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
15438     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
15439     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
15440     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15441     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15442     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
15443     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
15444     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
15445     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
15446     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
15447     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
15448     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
15449     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
15450     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
15451       _codec ("MPEG-2 video");
15452       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
15453           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15454       break;
15455     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
15456       _codec ("GIF still images");
15457       caps = gst_caps_new_empty_simple ("image/gif");
15458       break;
15459     case FOURCC_h263:
15460     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
15461     case FOURCC_s263:
15462     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
15463       _codec ("H.263");
15464       /* ffmpeg uses the height/width props, don't know why */
15465       caps = gst_caps_new_simple ("video/x-h263",
15466           "variant", G_TYPE_STRING, "itu", NULL);
15467       break;
15468     case FOURCC_mp4v:
15469     case FOURCC_MP4V:
15470       _codec ("MPEG-4 video");
15471       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15472           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15473       break;
15474     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
15475     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
15476       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
15477       caps = gst_caps_new_simple ("video/x-msmpeg",
15478           "msmpegversion", G_TYPE_INT, 43, NULL);
15479       break;
15480     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
15481       _codec ("DivX 3");
15482       caps = gst_caps_new_simple ("video/x-divx",
15483           "divxversion", G_TYPE_INT, 3, NULL);
15484       break;
15485     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
15486     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
15487       _codec ("DivX 4");
15488       caps = gst_caps_new_simple ("video/x-divx",
15489           "divxversion", G_TYPE_INT, 4, NULL);
15490       break;
15491     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
15492       _codec ("DivX 5");
15493       caps = gst_caps_new_simple ("video/x-divx",
15494           "divxversion", G_TYPE_INT, 5, NULL);
15495       break;
15496
15497     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
15498       _codec ("FFV1");
15499       caps = gst_caps_new_simple ("video/x-ffv",
15500           "ffvversion", G_TYPE_INT, 1, NULL);
15501       break;
15502
15503     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
15504     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
15505     case FOURCC_XVID:
15506     case FOURCC_xvid:
15507     case FOURCC_FMP4:
15508     case FOURCC_fmp4:
15509     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
15510       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15511           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15512       _codec ("MPEG-4");
15513       break;
15514
15515     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
15516       _codec ("Cinepak");
15517       caps = gst_caps_new_empty_simple ("video/x-cinepak");
15518       break;
15519     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
15520       _codec ("Apple QuickDraw");
15521       caps = gst_caps_new_empty_simple ("video/x-qdrw");
15522       break;
15523     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
15524       _codec ("Apple video");
15525       caps = gst_caps_new_empty_simple ("video/x-apple-video");
15526       break;
15527     case FOURCC_H264:
15528     case FOURCC_avc1:
15529       _codec ("H.264 / AVC");
15530       caps = gst_caps_new_simple ("video/x-h264",
15531           "stream-format", G_TYPE_STRING, "avc",
15532           "alignment", G_TYPE_STRING, "au", NULL);
15533       break;
15534     case FOURCC_avc3:
15535       _codec ("H.264 / AVC");
15536       caps = gst_caps_new_simple ("video/x-h264",
15537           "stream-format", G_TYPE_STRING, "avc3",
15538           "alignment", G_TYPE_STRING, "au", NULL);
15539       break;
15540     case FOURCC_H265:
15541     case FOURCC_hvc1:
15542       _codec ("H.265 / HEVC");
15543       caps = gst_caps_new_simple ("video/x-h265",
15544           "stream-format", G_TYPE_STRING, "hvc1",
15545           "alignment", G_TYPE_STRING, "au", NULL);
15546       break;
15547     case FOURCC_hev1:
15548       _codec ("H.265 / HEVC");
15549       caps = gst_caps_new_simple ("video/x-h265",
15550           "stream-format", G_TYPE_STRING, "hev1",
15551           "alignment", G_TYPE_STRING, "au", NULL);
15552       break;
15553     case FOURCC_rle_:
15554       _codec ("Run-length encoding");
15555       caps = gst_caps_new_simple ("video/x-rle",
15556           "layout", G_TYPE_STRING, "quicktime", NULL);
15557       break;
15558     case FOURCC_WRLE:
15559       _codec ("Run-length encoding");
15560       caps = gst_caps_new_simple ("video/x-rle",
15561           "layout", G_TYPE_STRING, "microsoft", NULL);
15562       break;
15563     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
15564     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
15565       _codec ("Indeo Video 3");
15566       caps = gst_caps_new_simple ("video/x-indeo",
15567           "indeoversion", G_TYPE_INT, 3, NULL);
15568       break;
15569     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
15570     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
15571       _codec ("Intel Video 4");
15572       caps = gst_caps_new_simple ("video/x-indeo",
15573           "indeoversion", G_TYPE_INT, 4, NULL);
15574       break;
15575     case FOURCC_dvcp:
15576     case FOURCC_dvc_:
15577     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
15578     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
15579     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
15580     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
15581     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
15582     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
15583       _codec ("DV Video");
15584       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
15585           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15586       break;
15587     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
15588     case FOURCC_dv5p:          /* DVCPRO50 PAL */
15589       _codec ("DVCPro50 Video");
15590       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
15591           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15592       break;
15593     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
15594     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
15595       _codec ("DVCProHD Video");
15596       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
15597           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15598       break;
15599     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
15600       _codec ("Apple Graphics (SMC)");
15601       caps = gst_caps_new_empty_simple ("video/x-smc");
15602       break;
15603     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
15604       _codec ("VP3");
15605       caps = gst_caps_new_empty_simple ("video/x-vp3");
15606       break;
15607     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
15608       _codec ("VP6 Flash");
15609       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
15610       break;
15611     case FOURCC_XiTh:
15612       _codec ("Theora");
15613       caps = gst_caps_new_empty_simple ("video/x-theora");
15614       /* theora uses one byte of padding in the data stream because it does not
15615        * allow 0 sized packets while theora does */
15616       entry->padding = 1;
15617       break;
15618     case FOURCC_drac:
15619       _codec ("Dirac");
15620       caps = gst_caps_new_empty_simple ("video/x-dirac");
15621       break;
15622     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
15623       _codec ("TIFF still images");
15624       caps = gst_caps_new_empty_simple ("image/tiff");
15625       break;
15626     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
15627       _codec ("Apple Intermediate Codec");
15628       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
15629       break;
15630     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
15631       _codec ("AVID DNxHD");
15632       caps = gst_caps_from_string ("video/x-dnxhd");
15633       break;
15634     case FOURCC_VP80:
15635     case FOURCC_vp08:
15636       _codec ("On2 VP8");
15637       caps = gst_caps_from_string ("video/x-vp8");
15638       break;
15639     case FOURCC_vp09:
15640       _codec ("Google VP9");
15641       caps = gst_caps_from_string ("video/x-vp9");
15642       break;
15643     case FOURCC_apcs:
15644       _codec ("Apple ProRes LT");
15645       caps =
15646           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
15647           NULL);
15648       break;
15649     case FOURCC_apch:
15650       _codec ("Apple ProRes HQ");
15651       caps =
15652           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
15653           NULL);
15654       break;
15655     case FOURCC_apcn:
15656       _codec ("Apple ProRes");
15657       caps =
15658           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15659           "standard", NULL);
15660       break;
15661     case FOURCC_apco:
15662       _codec ("Apple ProRes Proxy");
15663       caps =
15664           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15665           "proxy", NULL);
15666       break;
15667     case FOURCC_ap4h:
15668       _codec ("Apple ProRes 4444");
15669       caps =
15670           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15671           "4444", NULL);
15672       break;
15673     case FOURCC_ap4x:
15674       _codec ("Apple ProRes 4444 XQ");
15675       caps =
15676           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15677           "4444xq", NULL);
15678       break;
15679     case FOURCC_cfhd:
15680       _codec ("GoPro CineForm");
15681       caps = gst_caps_from_string ("video/x-cineform");
15682       break;
15683     case FOURCC_vc_1:
15684     case FOURCC_ovc1:
15685       _codec ("VC-1");
15686       caps = gst_caps_new_simple ("video/x-wmv",
15687           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
15688       break;
15689     case FOURCC_av01:
15690       _codec ("AV1");
15691       caps = gst_caps_new_empty_simple ("video/x-av1");
15692       break;
15693     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15694     default:
15695     {
15696       caps = _get_unknown_codec_name ("video", fourcc);
15697       break;
15698     }
15699   }
15700
15701   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15702     GstVideoInfo info;
15703
15704     gst_video_info_init (&info);
15705     gst_video_info_set_format (&info, format, entry->width, entry->height);
15706
15707     caps = gst_video_info_to_caps (&info);
15708     *codec_name = gst_pb_utils_get_codec_description (caps);
15709
15710     /* enable clipping for raw video streams */
15711     stream->need_clip = TRUE;
15712     stream->alignment = 32;
15713   }
15714
15715   return caps;
15716 }
15717
15718 static guint
15719 round_up_pow2 (guint n)
15720 {
15721   n = n - 1;
15722   n = n | (n >> 1);
15723   n = n | (n >> 2);
15724   n = n | (n >> 4);
15725   n = n | (n >> 8);
15726   n = n | (n >> 16);
15727   return n + 1;
15728 }
15729
15730 static GstCaps *
15731 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15732     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15733     int len, gchar ** codec_name)
15734 {
15735   GstCaps *caps;
15736   const GstStructure *s;
15737   const gchar *name;
15738   gint endian = 0;
15739   GstAudioFormat format = 0;
15740   gint depth;
15741
15742   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15743
15744   depth = entry->bytes_per_packet * 8;
15745
15746   switch (fourcc) {
15747     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15748     case FOURCC_raw_:
15749       /* 8-bit audio is unsigned */
15750       if (depth == 8)
15751         format = GST_AUDIO_FORMAT_U8;
15752       /* otherwise it's signed and big-endian just like 'twos' */
15753     case FOURCC_twos:
15754       endian = G_BIG_ENDIAN;
15755       /* fall-through */
15756     case FOURCC_sowt:
15757     {
15758       gchar *str;
15759
15760       if (!endian)
15761         endian = G_LITTLE_ENDIAN;
15762
15763       if (!format)
15764         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15765
15766       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15767       _codec (str);
15768       g_free (str);
15769
15770       caps = gst_caps_new_simple ("audio/x-raw",
15771           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15772           "layout", G_TYPE_STRING, "interleaved", NULL);
15773       stream->alignment = GST_ROUND_UP_8 (depth);
15774       stream->alignment = round_up_pow2 (stream->alignment);
15775       break;
15776     }
15777     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
15778       _codec ("Raw 64-bit floating-point audio");
15779       caps = gst_caps_new_simple ("audio/x-raw",
15780           "format", G_TYPE_STRING, "F64BE",
15781           "layout", G_TYPE_STRING, "interleaved", NULL);
15782       stream->alignment = 8;
15783       break;
15784     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
15785       _codec ("Raw 32-bit floating-point audio");
15786       caps = gst_caps_new_simple ("audio/x-raw",
15787           "format", G_TYPE_STRING, "F32BE",
15788           "layout", G_TYPE_STRING, "interleaved", NULL);
15789       stream->alignment = 4;
15790       break;
15791     case FOURCC_in24:
15792       _codec ("Raw 24-bit PCM audio");
15793       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15794        * endian later */
15795       caps = gst_caps_new_simple ("audio/x-raw",
15796           "format", G_TYPE_STRING, "S24BE",
15797           "layout", G_TYPE_STRING, "interleaved", NULL);
15798       stream->alignment = 4;
15799       break;
15800     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
15801       _codec ("Raw 32-bit PCM audio");
15802       caps = gst_caps_new_simple ("audio/x-raw",
15803           "format", G_TYPE_STRING, "S32BE",
15804           "layout", G_TYPE_STRING, "interleaved", NULL);
15805       stream->alignment = 4;
15806       break;
15807     case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
15808       _codec ("Raw 16-bit PCM audio");
15809       caps = gst_caps_new_simple ("audio/x-raw",
15810           "format", G_TYPE_STRING, "S16LE",
15811           "layout", G_TYPE_STRING, "interleaved", NULL);
15812       stream->alignment = 2;
15813       break;
15814     case FOURCC_ulaw:
15815       _codec ("Mu-law audio");
15816       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15817       break;
15818     case FOURCC_alaw:
15819       _codec ("A-law audio");
15820       caps = gst_caps_new_empty_simple ("audio/x-alaw");
15821       break;
15822     case 0x0200736d:
15823     case 0x6d730002:
15824       _codec ("Microsoft ADPCM");
15825       /* Microsoft ADPCM-ACM code 2 */
15826       caps = gst_caps_new_simple ("audio/x-adpcm",
15827           "layout", G_TYPE_STRING, "microsoft", NULL);
15828       break;
15829     case 0x1100736d:
15830     case 0x6d730011:
15831       _codec ("DVI/IMA ADPCM");
15832       caps = gst_caps_new_simple ("audio/x-adpcm",
15833           "layout", G_TYPE_STRING, "dvi", NULL);
15834       break;
15835     case 0x1700736d:
15836     case 0x6d730017:
15837       _codec ("DVI/Intel IMA ADPCM");
15838       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15839       caps = gst_caps_new_simple ("audio/x-adpcm",
15840           "layout", G_TYPE_STRING, "quicktime", NULL);
15841       break;
15842     case 0x5500736d:
15843     case 0x6d730055:
15844       /* MPEG layer 3, CBR only (pre QT4.1) */
15845     case FOURCC__mp3:
15846       _codec ("MPEG-1 layer 3");
15847       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15848       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15849           "mpegversion", G_TYPE_INT, 1, NULL);
15850       break;
15851     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15852       _codec ("MPEG-1 layer 2");
15853       /* MPEG layer 2 */
15854       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15855           "mpegversion", G_TYPE_INT, 1, NULL);
15856       break;
15857     case 0x20736d:
15858     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15859       _codec ("EAC-3 audio");
15860       caps = gst_caps_new_simple ("audio/x-eac3",
15861           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15862       entry->sampled = TRUE;
15863       break;
15864     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15865     case FOURCC_ac_3:
15866       _codec ("AC-3 audio");
15867       caps = gst_caps_new_simple ("audio/x-ac3",
15868           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15869       entry->sampled = TRUE;
15870       break;
15871     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15872     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15873       _codec ("DTS audio");
15874       caps = gst_caps_new_simple ("audio/x-dts",
15875           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15876       entry->sampled = TRUE;
15877       break;
15878     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15879     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15880       _codec ("DTS-HD audio");
15881       caps = gst_caps_new_simple ("audio/x-dts",
15882           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15883       entry->sampled = TRUE;
15884       break;
15885     case FOURCC_MAC3:
15886       _codec ("MACE-3");
15887       caps = gst_caps_new_simple ("audio/x-mace",
15888           "maceversion", G_TYPE_INT, 3, NULL);
15889       break;
15890     case FOURCC_MAC6:
15891       _codec ("MACE-6");
15892       caps = gst_caps_new_simple ("audio/x-mace",
15893           "maceversion", G_TYPE_INT, 6, NULL);
15894       break;
15895     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15896       /* ogg/vorbis */
15897       caps = gst_caps_new_empty_simple ("application/ogg");
15898       break;
15899     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15900       _codec ("DV audio");
15901       caps = gst_caps_new_empty_simple ("audio/x-dv");
15902       break;
15903     case FOURCC_mp4a:
15904       _codec ("MPEG-4 AAC audio");
15905       caps = gst_caps_new_simple ("audio/mpeg",
15906           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15907           "stream-format", G_TYPE_STRING, "raw", NULL);
15908       break;
15909     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15910       _codec ("QDesign Music");
15911       caps = gst_caps_new_empty_simple ("audio/x-qdm");
15912       break;
15913     case FOURCC_QDM2:
15914       _codec ("QDesign Music v.2");
15915       /* FIXME: QDesign music version 2 (no constant) */
15916       if (FALSE && data) {
15917         caps = gst_caps_new_simple ("audio/x-qdm2",
15918             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15919             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15920             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15921       } else {
15922         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15923       }
15924       break;
15925     case FOURCC_agsm:
15926       _codec ("GSM audio");
15927       caps = gst_caps_new_empty_simple ("audio/x-gsm");
15928       break;
15929     case FOURCC_samr:
15930       _codec ("AMR audio");
15931       caps = gst_caps_new_empty_simple ("audio/AMR");
15932       break;
15933     case FOURCC_sawb:
15934       _codec ("AMR-WB audio");
15935       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15936       break;
15937     case FOURCC_ima4:
15938       _codec ("Quicktime IMA ADPCM");
15939       caps = gst_caps_new_simple ("audio/x-adpcm",
15940           "layout", G_TYPE_STRING, "quicktime", NULL);
15941       break;
15942     case FOURCC_alac:
15943       _codec ("Apple lossless audio");
15944       caps = gst_caps_new_empty_simple ("audio/x-alac");
15945       break;
15946     case FOURCC_fLaC:
15947       _codec ("Free Lossless Audio Codec");
15948       caps = gst_caps_new_simple ("audio/x-flac",
15949           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15950       break;
15951     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15952       _codec ("QualComm PureVoice");
15953       caps = gst_caps_from_string ("audio/qcelp");
15954       break;
15955     case FOURCC_wma_:
15956     case FOURCC_owma:
15957       _codec ("WMA");
15958       caps = gst_caps_new_empty_simple ("audio/x-wma");
15959       break;
15960     case FOURCC_opus:
15961       _codec ("Opus");
15962       caps = gst_caps_new_empty_simple ("audio/x-opus");
15963       break;
15964     case FOURCC_lpcm:
15965     {
15966       guint32 flags = 0;
15967       guint32 depth = 0;
15968       guint32 width = 0;
15969       GstAudioFormat format;
15970       enum
15971       {
15972         FLAG_IS_FLOAT = 0x1,
15973         FLAG_IS_BIG_ENDIAN = 0x2,
15974         FLAG_IS_SIGNED = 0x4,
15975         FLAG_IS_PACKED = 0x8,
15976         FLAG_IS_ALIGNED_HIGH = 0x10,
15977         FLAG_IS_NON_INTERLEAVED = 0x20
15978       };
15979       _codec ("Raw LPCM audio");
15980
15981       if (data && len >= 36) {
15982         depth = QT_UINT32 (data + 24);
15983         flags = QT_UINT32 (data + 28);
15984         width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15985       }
15986       if ((flags & FLAG_IS_FLOAT) == 0) {
15987         if (depth == 0)
15988           depth = 16;
15989         if (width == 0)
15990           width = 16;
15991         if ((flags & FLAG_IS_ALIGNED_HIGH))
15992           depth = width;
15993
15994         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15995             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15996             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15997         caps = gst_caps_new_simple ("audio/x-raw",
15998             "format", G_TYPE_STRING,
15999             format !=
16000             GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
16001             "UNKNOWN", "layout", G_TYPE_STRING,
16002             (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
16003             "interleaved", NULL);
16004         stream->alignment = GST_ROUND_UP_8 (depth);
16005         stream->alignment = round_up_pow2 (stream->alignment);
16006       } else {
16007         if (width == 0)
16008           width = 32;
16009         if (width == 64) {
16010           if (flags & FLAG_IS_BIG_ENDIAN)
16011             format = GST_AUDIO_FORMAT_F64BE;
16012           else
16013             format = GST_AUDIO_FORMAT_F64LE;
16014         } else {
16015           if (flags & FLAG_IS_BIG_ENDIAN)
16016             format = GST_AUDIO_FORMAT_F32BE;
16017           else
16018             format = GST_AUDIO_FORMAT_F32LE;
16019         }
16020         caps = gst_caps_new_simple ("audio/x-raw",
16021             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
16022             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
16023             "non-interleaved" : "interleaved", NULL);
16024         stream->alignment = width / 8;
16025       }
16026       break;
16027     }
16028     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
16029       /* ? */
16030     default:
16031     {
16032       caps = _get_unknown_codec_name ("audio", fourcc);
16033       break;
16034     }
16035   }
16036
16037   if (caps) {
16038     GstCaps *templ_caps =
16039         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
16040     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
16041     gst_caps_unref (caps);
16042     gst_caps_unref (templ_caps);
16043     caps = intersection;
16044   }
16045
16046   /* enable clipping for raw audio streams */
16047   s = gst_caps_get_structure (caps, 0);
16048   name = gst_structure_get_name (s);
16049   if (g_str_has_prefix (name, "audio/x-raw")) {
16050     stream->need_clip = TRUE;
16051     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
16052     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
16053   }
16054   return caps;
16055 }
16056
16057 static GstCaps *
16058 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16059     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16060     const guint8 * stsd_entry_data, gchar ** codec_name)
16061 {
16062   GstCaps *caps;
16063
16064   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
16065
16066   switch (fourcc) {
16067     case FOURCC_mp4s:
16068       _codec ("DVD subtitle");
16069       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
16070       stream->need_process = TRUE;
16071       break;
16072     case FOURCC_text:
16073       _codec ("Quicktime timed text");
16074       goto text;
16075     case FOURCC_tx3g:
16076       _codec ("3GPP timed text");
16077     text:
16078       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
16079           "utf8", NULL);
16080       /* actual text piece needs to be extracted */
16081       stream->need_process = TRUE;
16082       break;
16083     case FOURCC_stpp:
16084       _codec ("XML subtitles");
16085       caps = gst_caps_new_empty_simple ("application/ttml+xml");
16086       break;
16087     case FOURCC_c608:
16088       _codec ("CEA 608 Closed Caption");
16089       caps =
16090           gst_caps_new_simple ("closedcaption/x-cea-608", "format",
16091           G_TYPE_STRING, "s334-1a", NULL);
16092       stream->need_process = TRUE;
16093       stream->need_split = TRUE;
16094       break;
16095     case FOURCC_c708:
16096       _codec ("CEA 708 Closed Caption");
16097       caps =
16098           gst_caps_new_simple ("closedcaption/x-cea-708", "format",
16099           G_TYPE_STRING, "cdp", NULL);
16100       stream->need_process = TRUE;
16101       break;
16102
16103     default:
16104     {
16105       caps = _get_unknown_codec_name ("text", fourcc);
16106       break;
16107     }
16108   }
16109   return caps;
16110 }
16111
16112 static GstCaps *
16113 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16114     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16115     const guint8 * stsd_entry_data, gchar ** codec_name)
16116 {
16117   GstCaps *caps;
16118
16119   switch (fourcc) {
16120     case FOURCC_m1v:
16121       _codec ("MPEG 1 video");
16122       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
16123           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
16124       break;
16125     default:
16126       caps = NULL;
16127       break;
16128   }
16129   return caps;
16130 }
16131
16132 static void
16133 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
16134     const gchar * system_id)
16135 {
16136   gint i;
16137
16138   if (!qtdemux->protection_system_ids)
16139     qtdemux->protection_system_ids =
16140         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
16141   /* Check whether we already have an entry for this system ID. */
16142   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
16143     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
16144     if (g_ascii_strcasecmp (system_id, id) == 0) {
16145       return;
16146     }
16147   }
16148   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
16149   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
16150           -1));
16151 }