6e4b71c4b4e522086965b5c5c042c90504cfa4cf
[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       fps_available =
9109           gst_video_guess_framerate (avg_duration,
9110           &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
9111
9112       GST_DEBUG_OBJECT (qtdemux,
9113           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
9114           stream->timescale, CUR_STREAM (stream)->fps_n,
9115           CUR_STREAM (stream)->fps_d);
9116     }
9117   }
9118
9119   return fps_available;
9120 }
9121
9122 static gboolean
9123 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
9124 {
9125   if (stream->subtype == FOURCC_vide) {
9126     gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9127
9128     if (CUR_STREAM (stream)->caps) {
9129       CUR_STREAM (stream)->caps =
9130           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9131
9132       if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
9133         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9134             "width", G_TYPE_INT, CUR_STREAM (stream)->width,
9135             "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
9136
9137       /* set framerate if calculated framerate is reliable */
9138       if (fps_available) {
9139         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9140             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9141             CUR_STREAM (stream)->fps_d, NULL);
9142       }
9143
9144       /* calculate pixel-aspect-ratio using display width and height */
9145       GST_DEBUG_OBJECT (qtdemux,
9146           "video size %dx%d, target display size %dx%d",
9147           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
9148           stream->display_width, stream->display_height);
9149       /* qt file might have pasp atom */
9150       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9151         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
9152             CUR_STREAM (stream)->par_h);
9153         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9154             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9155             CUR_STREAM (stream)->par_h, NULL);
9156       } else if (stream->display_width > 0 && stream->display_height > 0
9157           && CUR_STREAM (stream)->width > 0
9158           && CUR_STREAM (stream)->height > 0) {
9159         gint n, d;
9160
9161         /* calculate the pixel aspect ratio using the display and pixel w/h */
9162         n = stream->display_width * CUR_STREAM (stream)->height;
9163         d = stream->display_height * CUR_STREAM (stream)->width;
9164         if (n == d)
9165           n = d = 1;
9166         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
9167         CUR_STREAM (stream)->par_w = n;
9168         CUR_STREAM (stream)->par_h = d;
9169         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9170             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9171             CUR_STREAM (stream)->par_h, NULL);
9172       }
9173
9174       if (CUR_STREAM (stream)->interlace_mode > 0) {
9175         if (CUR_STREAM (stream)->interlace_mode == 1) {
9176           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9177               G_TYPE_STRING, "progressive", NULL);
9178         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
9179           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9180               G_TYPE_STRING, "interleaved", NULL);
9181           if (CUR_STREAM (stream)->field_order == 9) {
9182             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9183                 G_TYPE_STRING, "top-field-first", NULL);
9184           } else if (CUR_STREAM (stream)->field_order == 14) {
9185             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9186                 G_TYPE_STRING, "bottom-field-first", NULL);
9187           }
9188         }
9189       }
9190
9191       /* Create incomplete colorimetry here if needed */
9192       if (CUR_STREAM (stream)->colorimetry.range ||
9193           CUR_STREAM (stream)->colorimetry.matrix ||
9194           CUR_STREAM (stream)->colorimetry.transfer
9195           || CUR_STREAM (stream)->colorimetry.primaries) {
9196         gchar *colorimetry =
9197             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
9198         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
9199             G_TYPE_STRING, colorimetry, NULL);
9200         g_free (colorimetry);
9201       }
9202
9203       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
9204         guint par_w = 1, par_h = 1;
9205
9206         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9207           par_w = CUR_STREAM (stream)->par_w;
9208           par_h = CUR_STREAM (stream)->par_h;
9209         }
9210
9211         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
9212                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
9213                 par_h)) {
9214           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
9215         }
9216
9217         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9218             "multiview-mode", G_TYPE_STRING,
9219             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
9220             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
9221             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
9222       }
9223     }
9224   }
9225
9226   else if (stream->subtype == FOURCC_soun) {
9227     if (CUR_STREAM (stream)->caps) {
9228       CUR_STREAM (stream)->caps =
9229           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9230       if (CUR_STREAM (stream)->rate > 0)
9231         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9232             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
9233       if (CUR_STREAM (stream)->n_channels > 0)
9234         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9235             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
9236       if (CUR_STREAM (stream)->n_channels > 2) {
9237         /* FIXME: Need to parse the 'chan' atom to get channel layouts
9238          * correctly; this is just the minimum we can do - assume
9239          * we don't actually have any channel positions. */
9240         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9241             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
9242       }
9243     }
9244   }
9245
9246   else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
9247     const GstStructure *s;
9248     QtDemuxStream *fps_stream = NULL;
9249     gboolean fps_available = FALSE;
9250
9251     /* CEA608 closed caption tracks are a bit special in that each sample
9252      * can contain CCs for multiple frames, and CCs can be omitted and have to
9253      * be inferred from the duration of the sample then.
9254      *
9255      * As such we take the framerate from the (first) video track here for
9256      * CEA608 as there must be one CC byte pair for every video frame
9257      * according to the spec.
9258      *
9259      * For CEA708 all is fine and there is one sample per frame.
9260      */
9261
9262     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9263     if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
9264       gint i;
9265
9266       for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
9267         QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
9268
9269         if (tmp->subtype == FOURCC_vide) {
9270           fps_stream = tmp;
9271           break;
9272         }
9273       }
9274
9275       if (fps_stream) {
9276         fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
9277         CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
9278         CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
9279       }
9280     } else {
9281       fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9282       fps_stream = stream;
9283     }
9284
9285     CUR_STREAM (stream)->caps =
9286         gst_caps_make_writable (CUR_STREAM (stream)->caps);
9287
9288     /* set framerate if calculated framerate is reliable */
9289     if (fps_available) {
9290       gst_caps_set_simple (CUR_STREAM (stream)->caps,
9291           "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9292           CUR_STREAM (stream)->fps_d, NULL);
9293     }
9294   }
9295
9296   if (stream->pad) {
9297     GstCaps *prev_caps = NULL;
9298
9299     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9300     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9301     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9302     gst_pad_set_active (stream->pad, TRUE);
9303
9304     gst_pad_use_fixed_caps (stream->pad);
9305
9306     if (stream->protected) {
9307       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9308         GST_ERROR_OBJECT (qtdemux,
9309             "Failed to configure protected stream caps.");
9310         return FALSE;
9311       }
9312     }
9313
9314     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9315         CUR_STREAM (stream)->caps);
9316     if (stream->new_stream) {
9317       GstEvent *event;
9318       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9319
9320       event =
9321           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9322           0);
9323       if (event) {
9324         gst_event_parse_stream_flags (event, &stream_flags);
9325         if (gst_event_parse_group_id (event, &qtdemux->group_id))
9326           qtdemux->have_group_id = TRUE;
9327         else
9328           qtdemux->have_group_id = FALSE;
9329         gst_event_unref (event);
9330       } else if (!qtdemux->have_group_id) {
9331         qtdemux->have_group_id = TRUE;
9332         qtdemux->group_id = gst_util_group_id_next ();
9333       }
9334
9335       stream->new_stream = FALSE;
9336       event = gst_event_new_stream_start (stream->stream_id);
9337       if (qtdemux->have_group_id)
9338         gst_event_set_group_id (event, qtdemux->group_id);
9339       if (stream->disabled)
9340         stream_flags |= GST_STREAM_FLAG_UNSELECT;
9341       if (CUR_STREAM (stream)->sparse) {
9342         stream_flags |= GST_STREAM_FLAG_SPARSE;
9343       } else {
9344         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9345       }
9346       gst_event_set_stream_flags (event, stream_flags);
9347       gst_pad_push_event (stream->pad, event);
9348     }
9349
9350     prev_caps = gst_pad_get_current_caps (stream->pad);
9351
9352     if (CUR_STREAM (stream)->caps) {
9353       if (!prev_caps
9354           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9355         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9356             CUR_STREAM (stream)->caps);
9357         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9358       } else {
9359         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9360       }
9361     } else {
9362       GST_WARNING_OBJECT (qtdemux, "stream without caps");
9363     }
9364
9365     if (prev_caps)
9366       gst_caps_unref (prev_caps);
9367     stream->new_caps = FALSE;
9368   }
9369   return TRUE;
9370 }
9371
9372 static void
9373 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9374     QtDemuxStream * stream)
9375 {
9376   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9377     return;
9378
9379   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9380       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9381   if (G_UNLIKELY (stream->stsd_sample_description_id >=
9382           stream->stsd_entries_length)) {
9383     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9384         (_("This file is invalid and cannot be played.")),
9385         ("New sample description id is out of bounds (%d >= %d)",
9386             stream->stsd_sample_description_id, stream->stsd_entries_length));
9387   } else {
9388     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9389     stream->new_caps = TRUE;
9390   }
9391 }
9392
9393 static gboolean
9394 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9395     QtDemuxStream * stream, GstTagList * list)
9396 {
9397   gboolean ret = TRUE;
9398
9399   if (stream->subtype == FOURCC_vide) {
9400     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9401
9402     stream->pad =
9403         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9404     g_free (name);
9405
9406     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9407       gst_object_unref (stream->pad);
9408       stream->pad = NULL;
9409       ret = FALSE;
9410       goto done;
9411     }
9412
9413     qtdemux->n_video_streams++;
9414   } else if (stream->subtype == FOURCC_soun) {
9415     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9416
9417     stream->pad =
9418         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9419     g_free (name);
9420     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9421       gst_object_unref (stream->pad);
9422       stream->pad = NULL;
9423       ret = FALSE;
9424       goto done;
9425     }
9426     qtdemux->n_audio_streams++;
9427   } else if (stream->subtype == FOURCC_strm) {
9428     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9429   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9430       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9431       || stream->subtype == FOURCC_clcp) {
9432     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9433
9434     stream->pad =
9435         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9436     g_free (name);
9437     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9438       gst_object_unref (stream->pad);
9439       stream->pad = NULL;
9440       ret = FALSE;
9441       goto done;
9442     }
9443     qtdemux->n_sub_streams++;
9444   } else if (CUR_STREAM (stream)->caps) {
9445     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9446
9447     stream->pad =
9448         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9449     g_free (name);
9450     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9451       gst_object_unref (stream->pad);
9452       stream->pad = NULL;
9453       ret = FALSE;
9454       goto done;
9455     }
9456     qtdemux->n_video_streams++;
9457   } else {
9458     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9459     goto done;
9460   }
9461
9462   if (stream->pad) {
9463     GList *l;
9464
9465     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9466         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9467     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9468     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9469
9470     if (stream->stream_tags)
9471       gst_tag_list_unref (stream->stream_tags);
9472     stream->stream_tags = list;
9473     list = NULL;
9474     /* global tags go on each pad anyway */
9475     stream->send_global_tags = TRUE;
9476     /* send upstream GST_EVENT_PROTECTION events that were received before
9477        this source pad was created */
9478     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9479       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9480   }
9481 done:
9482   if (list)
9483     gst_tag_list_unref (list);
9484   return ret;
9485 }
9486
9487 /* find next atom with @fourcc starting at @offset */
9488 static GstFlowReturn
9489 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9490     guint64 * length, guint32 fourcc)
9491 {
9492   GstFlowReturn ret;
9493   guint32 lfourcc;
9494   GstBuffer *buf;
9495
9496   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9497       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9498
9499   while (TRUE) {
9500     GstMapInfo map;
9501
9502     buf = NULL;
9503     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9504     if (G_UNLIKELY (ret != GST_FLOW_OK))
9505       goto locate_failed;
9506     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9507       /* likely EOF */
9508       ret = GST_FLOW_EOS;
9509       gst_buffer_unref (buf);
9510       goto locate_failed;
9511     }
9512     gst_buffer_map (buf, &map, GST_MAP_READ);
9513     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9514     gst_buffer_unmap (buf, &map);
9515     gst_buffer_unref (buf);
9516
9517     if (G_UNLIKELY (*length == 0)) {
9518       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9519       ret = GST_FLOW_ERROR;
9520       goto locate_failed;
9521     }
9522
9523     if (lfourcc == fourcc) {
9524       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
9525           *offset);
9526       break;
9527     } else {
9528       GST_LOG_OBJECT (qtdemux,
9529           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9530           GST_FOURCC_ARGS (fourcc), *offset);
9531       *offset += *length;
9532     }
9533   }
9534
9535   return GST_FLOW_OK;
9536
9537 locate_failed:
9538   {
9539     /* might simply have had last one */
9540     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9541     return ret;
9542   }
9543 }
9544
9545 /* should only do something in pull mode */
9546 /* call with OBJECT lock */
9547 static GstFlowReturn
9548 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9549 {
9550   guint64 length, offset;
9551   GstBuffer *buf = NULL;
9552   GstFlowReturn ret = GST_FLOW_OK;
9553   GstFlowReturn res = GST_FLOW_OK;
9554   GstMapInfo map;
9555
9556   offset = qtdemux->moof_offset;
9557   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9558
9559   if (!offset) {
9560     GST_DEBUG_OBJECT (qtdemux, "no next moof");
9561     return GST_FLOW_EOS;
9562   }
9563
9564   /* best not do pull etc with lock held */
9565   GST_OBJECT_UNLOCK (qtdemux);
9566
9567   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9568   if (ret != GST_FLOW_OK)
9569     goto flow_failed;
9570
9571   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9572   if (G_UNLIKELY (ret != GST_FLOW_OK))
9573     goto flow_failed;
9574   gst_buffer_map (buf, &map, GST_MAP_READ);
9575   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9576     gst_buffer_unmap (buf, &map);
9577     gst_buffer_unref (buf);
9578     buf = NULL;
9579     goto parse_failed;
9580   }
9581
9582   gst_buffer_unmap (buf, &map);
9583   gst_buffer_unref (buf);
9584   buf = NULL;
9585
9586   offset += length;
9587   /* look for next moof */
9588   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9589   if (G_UNLIKELY (ret != GST_FLOW_OK))
9590     goto flow_failed;
9591
9592 exit:
9593   GST_OBJECT_LOCK (qtdemux);
9594
9595   qtdemux->moof_offset = offset;
9596
9597   return res;
9598
9599 parse_failed:
9600   {
9601     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9602     offset = 0;
9603     res = GST_FLOW_ERROR;
9604     goto exit;
9605   }
9606 flow_failed:
9607   {
9608     /* maybe upstream temporarily flushing */
9609     if (ret != GST_FLOW_FLUSHING) {
9610       GST_DEBUG_OBJECT (qtdemux, "no next moof");
9611       offset = 0;
9612     } else {
9613       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9614       /* resume at current position next time */
9615     }
9616     res = ret;
9617     goto exit;
9618   }
9619 }
9620
9621 /* initialise bytereaders for stbl sub-atoms */
9622 static gboolean
9623 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9624 {
9625   stream->stbl_index = -1;      /* no samples have yet been parsed */
9626   stream->sample_index = -1;
9627
9628   /* time-to-sample atom */
9629   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9630     goto corrupt_file;
9631
9632   /* copy atom data into a new buffer for later use */
9633   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
9634
9635   /* skip version + flags */
9636   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9637       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9638     goto corrupt_file;
9639   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9640
9641   /* make sure there's enough data */
9642   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9643     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9644     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9645         stream->n_sample_times);
9646     if (!stream->n_sample_times)
9647       goto corrupt_file;
9648   }
9649
9650   /* sync sample atom */
9651   stream->stps_present = FALSE;
9652   if ((stream->stss_present =
9653           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9654               &stream->stss) ? TRUE : FALSE) == TRUE) {
9655     /* copy atom data into a new buffer for later use */
9656     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
9657
9658     /* skip version + flags */
9659     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9660         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9661       goto corrupt_file;
9662
9663     if (stream->n_sample_syncs) {
9664       /* make sure there's enough data */
9665       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9666         goto corrupt_file;
9667     }
9668
9669     /* partial sync sample atom */
9670     if ((stream->stps_present =
9671             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9672                 &stream->stps) ? TRUE : FALSE) == TRUE) {
9673       /* copy atom data into a new buffer for later use */
9674       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
9675
9676       /* skip version + flags */
9677       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9678           !gst_byte_reader_get_uint32_be (&stream->stps,
9679               &stream->n_sample_partial_syncs))
9680         goto corrupt_file;
9681
9682       /* if there are no entries, the stss table contains the real
9683        * sync samples */
9684       if (stream->n_sample_partial_syncs) {
9685         /* make sure there's enough data */
9686         if (!qt_atom_parser_has_chunks (&stream->stps,
9687                 stream->n_sample_partial_syncs, 4))
9688           goto corrupt_file;
9689       }
9690     }
9691   }
9692
9693   /* sample size */
9694   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9695     goto no_samples;
9696
9697   /* copy atom data into a new buffer for later use */
9698   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
9699
9700   /* skip version + flags */
9701   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9702       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9703     goto corrupt_file;
9704
9705   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9706     goto corrupt_file;
9707
9708   if (!stream->n_samples)
9709     goto no_samples;
9710
9711   /* sample-to-chunk atom */
9712   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9713     goto corrupt_file;
9714
9715   /* copy atom data into a new buffer for later use */
9716   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
9717
9718   /* skip version + flags */
9719   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9720       !gst_byte_reader_get_uint32_be (&stream->stsc,
9721           &stream->n_samples_per_chunk))
9722     goto corrupt_file;
9723
9724   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9725       stream->n_samples_per_chunk);
9726
9727   /* make sure there's enough data */
9728   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9729           12))
9730     goto corrupt_file;
9731
9732
9733   /* chunk offset */
9734   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9735     stream->co_size = sizeof (guint32);
9736   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9737           &stream->stco))
9738     stream->co_size = sizeof (guint64);
9739   else
9740     goto corrupt_file;
9741
9742   /* copy atom data into a new buffer for later use */
9743   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
9744
9745   /* skip version + flags */
9746   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9747     goto corrupt_file;
9748
9749   /* chunks_are_samples == TRUE means treat chunks as samples */
9750   stream->chunks_are_samples = stream->sample_size
9751       && !CUR_STREAM (stream)->sampled;
9752   if (stream->chunks_are_samples) {
9753     /* treat chunks as samples */
9754     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9755       goto corrupt_file;
9756   } else {
9757     /* skip number of entries */
9758     if (!gst_byte_reader_skip (&stream->stco, 4))
9759       goto corrupt_file;
9760
9761     /* make sure there are enough data in the stsz atom */
9762     if (!stream->sample_size) {
9763       /* different sizes for each sample */
9764       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9765         goto corrupt_file;
9766     }
9767   }
9768
9769   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9770       stream->n_samples, (guint) sizeof (QtDemuxSample),
9771       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9772
9773   if (stream->n_samples >=
9774       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9775     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9776         "be larger than %uMB (broken file?)", stream->n_samples,
9777         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9778     return FALSE;
9779   }
9780
9781   g_assert (stream->samples == NULL);
9782   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9783   if (!stream->samples) {
9784     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9785         stream->n_samples);
9786     return FALSE;
9787   }
9788
9789   /* composition time-to-sample */
9790   if ((stream->ctts_present =
9791           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9792               &stream->ctts) ? TRUE : FALSE) == TRUE) {
9793     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9794
9795     /* copy atom data into a new buffer for later use */
9796     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
9797
9798     /* skip version + flags */
9799     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9800         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9801             &stream->n_composition_times))
9802       goto corrupt_file;
9803
9804     /* make sure there's enough data */
9805     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9806             4 + 4))
9807       goto corrupt_file;
9808
9809     /* This is optional, if missing we iterate the ctts */
9810     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9811       if (!gst_byte_reader_skip (&cslg, 1 + 3)
9812           || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9813         g_free ((gpointer) cslg.data);
9814         goto corrupt_file;
9815       }
9816     } else {
9817       gint32 cslg_least = 0;
9818       guint num_entries, pos;
9819       gint i;
9820
9821       pos = gst_byte_reader_get_pos (&stream->ctts);
9822       num_entries = stream->n_composition_times;
9823
9824       stream->cslg_shift = 0;
9825
9826       for (i = 0; i < num_entries; i++) {
9827         gint32 offset;
9828
9829         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9830         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9831         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9832          * slightly inaccurate PTS could be more usable than corrupted one */
9833         if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9834           GST_WARNING_OBJECT (qtdemux,
9835               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9836               " larger than duration %" G_GUINT64_FORMAT,
9837               offset, stream->duration);
9838
9839           stream->cslg_shift = 0;
9840           stream->ctts_present = FALSE;
9841           return TRUE;
9842         }
9843
9844         if (offset < cslg_least)
9845           cslg_least = offset;
9846       }
9847
9848       if (cslg_least < 0)
9849         stream->cslg_shift = ABS (cslg_least);
9850       else
9851         stream->cslg_shift = 0;
9852
9853       /* reset the reader so we can generate sample table */
9854       gst_byte_reader_set_pos (&stream->ctts, pos);
9855     }
9856   } else {
9857     /* Ensure the cslg_shift value is consistent so we can use it
9858      * unconditionnally to produce TS and Segment */
9859     stream->cslg_shift = 0;
9860   }
9861
9862   return TRUE;
9863
9864 corrupt_file:
9865   {
9866     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9867         (_("This file is corrupt and cannot be played.")), (NULL));
9868     return FALSE;
9869   }
9870 no_samples:
9871   {
9872     gst_qtdemux_stbl_free (stream);
9873     if (!qtdemux->fragmented) {
9874       /* not quite good */
9875       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9876       return FALSE;
9877     } else {
9878       /* may pick up samples elsewhere */
9879       return TRUE;
9880     }
9881   }
9882 }
9883
9884 /* collect samples from the next sample to be parsed up to sample @n for @stream
9885  * by reading the info from @stbl
9886  *
9887  * This code can be executed from both the streaming thread and the seeking
9888  * thread so it takes the object lock to protect itself
9889  */
9890 static gboolean
9891 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9892 {
9893   gint i, j, k;
9894   QtDemuxSample *samples, *first, *cur, *last;
9895   guint32 n_samples_per_chunk;
9896   guint32 n_samples;
9897
9898   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9899       GST_FOURCC_FORMAT ", pad %s",
9900       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9901       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9902
9903   n_samples = stream->n_samples;
9904
9905   if (n >= n_samples)
9906     goto out_of_samples;
9907
9908   GST_OBJECT_LOCK (qtdemux);
9909   if (n <= stream->stbl_index)
9910     goto already_parsed;
9911
9912   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9913
9914   if (!stream->stsz.data) {
9915     /* so we already parsed and passed all the moov samples;
9916      * onto fragmented ones */
9917     g_assert (qtdemux->fragmented);
9918     goto done;
9919   }
9920
9921   /* pointer to the sample table */
9922   samples = stream->samples;
9923
9924   /* starts from -1, moves to the next sample index to parse */
9925   stream->stbl_index++;
9926
9927   /* keep track of the first and last sample to fill */
9928   first = &samples[stream->stbl_index];
9929   last = &samples[n];
9930
9931   if (!stream->chunks_are_samples) {
9932     /* set the sample sizes */
9933     if (stream->sample_size == 0) {
9934       /* different sizes for each sample */
9935       for (cur = first; cur <= last; cur++) {
9936         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9937         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9938             (guint) (cur - samples), cur->size);
9939       }
9940     } else {
9941       /* samples have the same size */
9942       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9943       for (cur = first; cur <= last; cur++)
9944         cur->size = stream->sample_size;
9945     }
9946   }
9947
9948   n_samples_per_chunk = stream->n_samples_per_chunk;
9949   cur = first;
9950
9951   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9952     guint32 last_chunk;
9953
9954     if (stream->stsc_chunk_index >= stream->last_chunk
9955         || stream->stsc_chunk_index < stream->first_chunk) {
9956       stream->first_chunk =
9957           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9958       stream->samples_per_chunk =
9959           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9960       /* starts from 1 */
9961       stream->stsd_sample_description_id =
9962           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9963
9964       /* chunk numbers are counted from 1 it seems */
9965       if (G_UNLIKELY (stream->first_chunk == 0))
9966         goto corrupt_file;
9967
9968       --stream->first_chunk;
9969
9970       /* the last chunk of each entry is calculated by taking the first chunk
9971        * of the next entry; except if there is no next, where we fake it with
9972        * INT_MAX */
9973       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9974         stream->last_chunk = G_MAXUINT32;
9975       } else {
9976         stream->last_chunk =
9977             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9978         if (G_UNLIKELY (stream->last_chunk == 0))
9979           goto corrupt_file;
9980
9981         --stream->last_chunk;
9982       }
9983
9984       GST_LOG_OBJECT (qtdemux,
9985           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9986           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9987           stream->samples_per_chunk, stream->stsd_sample_description_id);
9988
9989       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9990         goto corrupt_file;
9991
9992       if (stream->last_chunk != G_MAXUINT32) {
9993         if (!qt_atom_parser_peek_sub (&stream->stco,
9994                 stream->first_chunk * stream->co_size,
9995                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9996                 &stream->co_chunk))
9997           goto corrupt_file;
9998
9999       } else {
10000         stream->co_chunk = stream->stco;
10001         if (!gst_byte_reader_skip (&stream->co_chunk,
10002                 stream->first_chunk * stream->co_size))
10003           goto corrupt_file;
10004       }
10005
10006       stream->stsc_chunk_index = stream->first_chunk;
10007     }
10008
10009     last_chunk = stream->last_chunk;
10010
10011     if (stream->chunks_are_samples) {
10012       cur = &samples[stream->stsc_chunk_index];
10013
10014       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10015         if (j > n) {
10016           /* save state */
10017           stream->stsc_chunk_index = j;
10018           goto done;
10019         }
10020
10021         cur->offset =
10022             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
10023             stream->co_size);
10024
10025         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
10026             "%" G_GUINT64_FORMAT, j, cur->offset);
10027
10028         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
10029             CUR_STREAM (stream)->bytes_per_frame > 0) {
10030           cur->size =
10031               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
10032               CUR_STREAM (stream)->samples_per_frame *
10033               CUR_STREAM (stream)->bytes_per_frame;
10034         } else {
10035           cur->size = stream->samples_per_chunk;
10036         }
10037
10038         GST_DEBUG_OBJECT (qtdemux,
10039             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
10040             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
10041                     stream->stco_sample_index)), cur->size);
10042
10043         cur->timestamp = stream->stco_sample_index;
10044         cur->duration = stream->samples_per_chunk;
10045         cur->keyframe = TRUE;
10046         cur++;
10047
10048         stream->stco_sample_index += stream->samples_per_chunk;
10049       }
10050       stream->stsc_chunk_index = j;
10051     } else {
10052       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10053         guint32 samples_per_chunk;
10054         guint64 chunk_offset;
10055
10056         if (!stream->stsc_sample_index
10057             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
10058                 &stream->chunk_offset))
10059           goto corrupt_file;
10060
10061         samples_per_chunk = stream->samples_per_chunk;
10062         chunk_offset = stream->chunk_offset;
10063
10064         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
10065           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
10066               G_GUINT64_FORMAT " and size %d",
10067               (guint) (cur - samples), chunk_offset, cur->size);
10068
10069           cur->offset = chunk_offset;
10070           chunk_offset += cur->size;
10071           cur++;
10072
10073           if (G_UNLIKELY (cur > last)) {
10074             /* save state */
10075             stream->stsc_sample_index = k + 1;
10076             stream->chunk_offset = chunk_offset;
10077             stream->stsc_chunk_index = j;
10078             goto done2;
10079           }
10080         }
10081         stream->stsc_sample_index = 0;
10082       }
10083       stream->stsc_chunk_index = j;
10084     }
10085     stream->stsc_index++;
10086   }
10087
10088   if (stream->chunks_are_samples)
10089     goto ctts;
10090 done2:
10091   {
10092     guint32 n_sample_times;
10093
10094     n_sample_times = stream->n_sample_times;
10095     cur = first;
10096
10097     for (i = stream->stts_index; i < n_sample_times; i++) {
10098       guint32 stts_samples;
10099       gint32 stts_duration;
10100       gint64 stts_time;
10101
10102       if (stream->stts_sample_index >= stream->stts_samples
10103           || !stream->stts_sample_index) {
10104
10105         stream->stts_samples =
10106             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10107         stream->stts_duration =
10108             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10109
10110         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10111             i, stream->stts_samples, stream->stts_duration);
10112
10113         stream->stts_sample_index = 0;
10114       }
10115
10116       stts_samples = stream->stts_samples;
10117       stts_duration = stream->stts_duration;
10118       stts_time = stream->stts_time;
10119
10120       for (j = stream->stts_sample_index; j < stts_samples; j++) {
10121         GST_DEBUG_OBJECT (qtdemux,
10122             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10123             (guint) (cur - samples), j,
10124             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10125
10126         cur->timestamp = stts_time;
10127         cur->duration = stts_duration;
10128
10129         /* avoid 32-bit wrap-around,
10130          * but still mind possible 'negative' duration */
10131         stts_time += (gint64) stts_duration;
10132         cur++;
10133
10134         if (G_UNLIKELY (cur > last)) {
10135           /* save values */
10136           stream->stts_time = stts_time;
10137           stream->stts_sample_index = j + 1;
10138           if (stream->stts_sample_index >= stream->stts_samples)
10139             stream->stts_index++;
10140           goto done3;
10141         }
10142       }
10143       stream->stts_sample_index = 0;
10144       stream->stts_time = stts_time;
10145       stream->stts_index++;
10146     }
10147     /* fill up empty timestamps with the last timestamp, this can happen when
10148      * the last samples do not decode and so we don't have timestamps for them.
10149      * We however look at the last timestamp to estimate the track length so we
10150      * need something in here. */
10151     for (; cur < last; cur++) {
10152       GST_DEBUG_OBJECT (qtdemux,
10153           "fill sample %d: timestamp %" GST_TIME_FORMAT,
10154           (guint) (cur - samples),
10155           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10156       cur->timestamp = stream->stts_time;
10157       cur->duration = -1;
10158     }
10159   }
10160 done3:
10161   {
10162     /* sample sync, can be NULL */
10163     if (stream->stss_present == TRUE) {
10164       guint32 n_sample_syncs;
10165
10166       n_sample_syncs = stream->n_sample_syncs;
10167
10168       if (!n_sample_syncs) {
10169         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10170         stream->all_keyframe = TRUE;
10171       } else {
10172         for (i = stream->stss_index; i < n_sample_syncs; i++) {
10173           /* note that the first sample is index 1, not 0 */
10174           guint32 index;
10175
10176           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10177
10178           if (G_LIKELY (index > 0 && index <= n_samples)) {
10179             index -= 1;
10180             samples[index].keyframe = TRUE;
10181             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10182             /* and exit if we have enough samples */
10183             if (G_UNLIKELY (index >= n)) {
10184               i++;
10185               break;
10186             }
10187           }
10188         }
10189         /* save state */
10190         stream->stss_index = i;
10191       }
10192
10193       /* stps marks partial sync frames like open GOP I-Frames */
10194       if (stream->stps_present == TRUE) {
10195         guint32 n_sample_partial_syncs;
10196
10197         n_sample_partial_syncs = stream->n_sample_partial_syncs;
10198
10199         /* if there are no entries, the stss table contains the real
10200          * sync samples */
10201         if (n_sample_partial_syncs) {
10202           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10203             /* note that the first sample is index 1, not 0 */
10204             guint32 index;
10205
10206             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10207
10208             if (G_LIKELY (index > 0 && index <= n_samples)) {
10209               index -= 1;
10210               samples[index].keyframe = TRUE;
10211               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10212               /* and exit if we have enough samples */
10213               if (G_UNLIKELY (index >= n)) {
10214                 i++;
10215                 break;
10216               }
10217             }
10218           }
10219           /* save state */
10220           stream->stps_index = i;
10221         }
10222       }
10223     } else {
10224       /* no stss, all samples are keyframes */
10225       stream->all_keyframe = TRUE;
10226       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10227     }
10228   }
10229
10230 ctts:
10231   /* composition time to sample */
10232   if (stream->ctts_present == TRUE) {
10233     guint32 n_composition_times;
10234     guint32 ctts_count;
10235     gint32 ctts_soffset;
10236
10237     /* Fill in the pts_offsets */
10238     cur = first;
10239     n_composition_times = stream->n_composition_times;
10240
10241     for (i = stream->ctts_index; i < n_composition_times; i++) {
10242       if (stream->ctts_sample_index >= stream->ctts_count
10243           || !stream->ctts_sample_index) {
10244         stream->ctts_count =
10245             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10246         stream->ctts_soffset =
10247             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10248         stream->ctts_sample_index = 0;
10249       }
10250
10251       ctts_count = stream->ctts_count;
10252       ctts_soffset = stream->ctts_soffset;
10253
10254       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10255         cur->pts_offset = ctts_soffset;
10256         cur++;
10257
10258         if (G_UNLIKELY (cur > last)) {
10259           /* save state */
10260           stream->ctts_sample_index = j + 1;
10261           goto done;
10262         }
10263       }
10264       stream->ctts_sample_index = 0;
10265       stream->ctts_index++;
10266     }
10267   }
10268 done:
10269   stream->stbl_index = n;
10270   /* if index has been completely parsed, free data that is no-longer needed */
10271   if (n + 1 == stream->n_samples) {
10272     gst_qtdemux_stbl_free (stream);
10273     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10274     if (qtdemux->pullbased) {
10275       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10276       while (n + 1 == stream->n_samples)
10277         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10278           break;
10279     }
10280   }
10281   GST_OBJECT_UNLOCK (qtdemux);
10282
10283   return TRUE;
10284
10285   /* SUCCESS */
10286 already_parsed:
10287   {
10288     GST_LOG_OBJECT (qtdemux,
10289         "Tried to parse up to sample %u but this sample has already been parsed",
10290         n);
10291     /* if fragmented, there may be more */
10292     if (qtdemux->fragmented && n == stream->stbl_index)
10293       goto done;
10294     GST_OBJECT_UNLOCK (qtdemux);
10295     return TRUE;
10296   }
10297   /* ERRORS */
10298 out_of_samples:
10299   {
10300     GST_LOG_OBJECT (qtdemux,
10301         "Tried to parse up to sample %u but there are only %u samples", n + 1,
10302         stream->n_samples);
10303     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10304         (_("This file is corrupt and cannot be played.")), (NULL));
10305     return FALSE;
10306   }
10307 corrupt_file:
10308   {
10309     GST_OBJECT_UNLOCK (qtdemux);
10310     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10311         (_("This file is corrupt and cannot be played.")), (NULL));
10312     return FALSE;
10313   }
10314 }
10315
10316 /* collect all segment info for @stream.
10317  */
10318 static gboolean
10319 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10320     GNode * trak)
10321 {
10322   GNode *edts;
10323   /* accept edts if they contain gaps at start and there is only
10324    * one media segment */
10325   gboolean allow_pushbased_edts = TRUE;
10326   gint media_segments_count = 0;
10327
10328   /* parse and prepare segment info from the edit list */
10329   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10330   stream->n_segments = 0;
10331   stream->segments = NULL;
10332   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10333     GNode *elst;
10334     gint n_segments;
10335     gint segment_number, entry_size;
10336     guint64 time;
10337     GstClockTime stime;
10338     const guint8 *buffer;
10339     guint8 version;
10340     guint32 size;
10341
10342     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10343     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10344       goto done;
10345
10346     buffer = elst->data;
10347
10348     size = QT_UINT32 (buffer);
10349     /* version, flags, n_segments */
10350     if (size < 16) {
10351       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10352       goto done;
10353     }
10354     version = QT_UINT8 (buffer + 8);
10355     entry_size = (version == 1) ? 20 : 12;
10356
10357     n_segments = QT_UINT32 (buffer + 12);
10358
10359     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10360       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10361       goto done;
10362     }
10363
10364     /* we might allocate a bit too much, at least allocate 1 segment */
10365     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10366
10367     /* segments always start from 0 */
10368     time = 0;
10369     stime = 0;
10370     buffer += 16;
10371     for (segment_number = 0; segment_number < n_segments; segment_number++) {
10372       guint64 duration;
10373       guint64 media_time;
10374       gboolean empty_edit = FALSE;
10375       QtDemuxSegment *segment;
10376       guint32 rate_int;
10377       GstClockTime media_start = GST_CLOCK_TIME_NONE;
10378
10379       if (version == 1) {
10380         media_time = QT_UINT64 (buffer + 8);
10381         duration = QT_UINT64 (buffer);
10382         if (media_time == G_MAXUINT64)
10383           empty_edit = TRUE;
10384       } else {
10385         media_time = QT_UINT32 (buffer + 4);
10386         duration = QT_UINT32 (buffer);
10387         if (media_time == G_MAXUINT32)
10388           empty_edit = TRUE;
10389       }
10390
10391       if (!empty_edit)
10392         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10393
10394       segment = &stream->segments[segment_number];
10395
10396       /* time and duration expressed in global timescale */
10397       segment->time = stime;
10398       if (duration != 0 || empty_edit) {
10399         /* edge case: empty edits with duration=zero are treated here.
10400          * (files should not have these anyway). */
10401
10402         /* add non scaled values so we don't cause roundoff errors */
10403         time += duration;
10404         stime = QTTIME_TO_GSTTIME (qtdemux, time);
10405         segment->duration = stime - segment->time;
10406       } else {
10407         /* zero duration does not imply media_start == media_stop
10408          * but, only specify media_start. The edit ends with the track. */
10409         stime = segment->duration = GST_CLOCK_TIME_NONE;
10410         /* Don't allow more edits after this one. */
10411         n_segments = segment_number + 1;
10412       }
10413       segment->stop_time = stime;
10414
10415       segment->trak_media_start = media_time;
10416       /* media_time expressed in stream timescale */
10417       if (!empty_edit) {
10418         segment->media_start = media_start;
10419         segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10420             ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10421         media_segments_count++;
10422       } else {
10423         segment->media_start = GST_CLOCK_TIME_NONE;
10424         segment->media_stop = GST_CLOCK_TIME_NONE;
10425       }
10426       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10427
10428       if (rate_int <= 1) {
10429         /* 0 is not allowed, some programs write 1 instead of the floating point
10430          * value */
10431         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10432             rate_int);
10433         segment->rate = 1;
10434       } else {
10435         segment->rate = rate_int / 65536.0;
10436       }
10437
10438       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10439           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10440           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10441           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10442           segment_number, GST_TIME_ARGS (segment->time),
10443           GST_TIME_ARGS (segment->duration),
10444           GST_TIME_ARGS (segment->media_start), media_time,
10445           GST_TIME_ARGS (segment->media_stop),
10446           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10447           stream->timescale);
10448       if (segment->stop_time > qtdemux->segment.stop &&
10449           !qtdemux->upstream_format_is_time) {
10450         GST_WARNING_OBJECT (qtdemux, "Segment %d "
10451             " extends to %" GST_TIME_FORMAT
10452             " past the end of the declared movie duration %" GST_TIME_FORMAT
10453             " movie segment will be extended", segment_number,
10454             GST_TIME_ARGS (segment->stop_time),
10455             GST_TIME_ARGS (qtdemux->segment.stop));
10456         qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10457       }
10458
10459       buffer += entry_size;
10460     }
10461     GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10462     stream->n_segments = n_segments;
10463     if (media_segments_count != 1)
10464       allow_pushbased_edts = FALSE;
10465   }
10466 done:
10467
10468   /* push based does not handle segments, so act accordingly here,
10469    * and warn if applicable */
10470   if (!qtdemux->pullbased && !allow_pushbased_edts) {
10471     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10472     /* remove and use default one below, we stream like it anyway */
10473     g_free (stream->segments);
10474     stream->segments = NULL;
10475     stream->n_segments = 0;
10476   }
10477
10478   /* no segments, create one to play the complete trak */
10479   if (stream->n_segments == 0) {
10480     GstClockTime stream_duration =
10481         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10482
10483     if (stream->segments == NULL)
10484       stream->segments = g_new (QtDemuxSegment, 1);
10485
10486     /* represent unknown our way */
10487     if (stream_duration == 0)
10488       stream_duration = GST_CLOCK_TIME_NONE;
10489
10490     stream->segments[0].time = 0;
10491     stream->segments[0].stop_time = stream_duration;
10492     stream->segments[0].duration = stream_duration;
10493     stream->segments[0].media_start = 0;
10494     stream->segments[0].media_stop = stream_duration;
10495     stream->segments[0].rate = 1.0;
10496     stream->segments[0].trak_media_start = 0;
10497
10498     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10499         GST_TIME_ARGS (stream_duration));
10500     stream->n_segments = 1;
10501     stream->dummy_segment = TRUE;
10502   }
10503   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10504
10505   return TRUE;
10506 }
10507
10508 /*
10509  * Parses the stsd atom of a svq3 trak looking for
10510  * the SMI and gama atoms.
10511  */
10512 static void
10513 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10514     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10515 {
10516   const guint8 *_gamma = NULL;
10517   GstBuffer *_seqh = NULL;
10518   const guint8 *stsd_data = stsd_entry_data;
10519   guint32 length = QT_UINT32 (stsd_data);
10520   guint16 version;
10521
10522   if (length < 32) {
10523     GST_WARNING_OBJECT (qtdemux, "stsd too short");
10524     goto end;
10525   }
10526
10527   stsd_data += 16;
10528   length -= 16;
10529   version = QT_UINT16 (stsd_data);
10530   if (version == 3) {
10531     if (length >= 70) {
10532       length -= 70;
10533       stsd_data += 70;
10534       while (length > 8) {
10535         guint32 fourcc, size;
10536         const guint8 *data;
10537         size = QT_UINT32 (stsd_data);
10538         fourcc = QT_FOURCC (stsd_data + 4);
10539         data = stsd_data + 8;
10540
10541         if (size == 0) {
10542           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10543               "svq3 atom parsing");
10544           goto end;
10545         }
10546
10547         switch (fourcc) {
10548           case FOURCC_gama:{
10549             if (size == 12) {
10550               _gamma = data;
10551             } else {
10552               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10553                   " for gama atom, expected 12", size);
10554             }
10555             break;
10556           }
10557           case FOURCC_SMI_:{
10558             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10559               guint32 seqh_size;
10560               if (_seqh != NULL) {
10561                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10562                     " found, ignoring");
10563               } else {
10564                 seqh_size = QT_UINT32 (data + 4);
10565                 if (seqh_size > 0) {
10566                   _seqh = gst_buffer_new_and_alloc (seqh_size);
10567                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10568                 }
10569               }
10570             }
10571             break;
10572           }
10573           default:{
10574             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10575                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10576           }
10577         }
10578
10579         if (size <= length) {
10580           length -= size;
10581           stsd_data += size;
10582         }
10583       }
10584     } else {
10585       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10586     }
10587   } else {
10588     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10589         G_GUINT16_FORMAT, version);
10590     goto end;
10591   }
10592
10593 end:
10594   if (gamma) {
10595     *gamma = _gamma;
10596   }
10597   if (seqh) {
10598     *seqh = _seqh;
10599   } else if (_seqh) {
10600     gst_buffer_unref (_seqh);
10601   }
10602 }
10603
10604 static gchar *
10605 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10606 {
10607   GNode *dinf;
10608   GstByteReader dref;
10609   gchar *uri = NULL;
10610
10611   /*
10612    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10613    * atom that might contain a 'data' atom with the rtsp uri.
10614    * This case was reported in bug #597497, some info about
10615    * the hndl atom can be found in TN1195
10616    */
10617   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10618   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10619
10620   if (dinf) {
10621     guint32 dref_num_entries = 0;
10622     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10623         gst_byte_reader_skip (&dref, 4) &&
10624         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10625       gint i;
10626
10627       /* search dref entries for hndl atom */
10628       for (i = 0; i < dref_num_entries; i++) {
10629         guint32 size = 0, type;
10630         guint8 string_len = 0;
10631         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10632             qt_atom_parser_get_fourcc (&dref, &type)) {
10633           if (type == FOURCC_hndl) {
10634             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10635
10636             /* skip data reference handle bytes and the
10637              * following pascal string and some extra 4
10638              * bytes I have no idea what are */
10639             if (!gst_byte_reader_skip (&dref, 4) ||
10640                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10641                 !gst_byte_reader_skip (&dref, string_len + 4)) {
10642               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10643               break;
10644             }
10645
10646             /* iterate over the atoms to find the data atom */
10647             while (gst_byte_reader_get_remaining (&dref) >= 8) {
10648               guint32 atom_size;
10649               guint32 atom_type;
10650
10651               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10652                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10653                 if (atom_type == FOURCC_data) {
10654                   const guint8 *uri_aux = NULL;
10655
10656                   /* found the data atom that might contain the rtsp uri */
10657                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10658                       "hndl atom, interpreting it as an URI");
10659                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10660                           &uri_aux)) {
10661                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10662                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10663                     else
10664                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10665                           "didn't contain a rtsp address");
10666                   } else {
10667                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10668                         "atom contents");
10669                   }
10670                   break;
10671                 }
10672                 /* skipping to the next entry */
10673                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10674                   break;
10675               } else {
10676                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10677                     "atom header");
10678                 break;
10679               }
10680             }
10681             break;
10682           }
10683           /* skip to the next entry */
10684           if (!gst_byte_reader_skip (&dref, size - 8))
10685             break;
10686         } else {
10687           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10688         }
10689       }
10690       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10691     }
10692   }
10693   return uri;
10694 }
10695
10696 #define AMR_NB_ALL_MODES        0x81ff
10697 #define AMR_WB_ALL_MODES        0x83ff
10698 static guint
10699 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10700 {
10701   /* The 'damr' atom is of the form:
10702    *
10703    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10704    *    32 b       8 b          16 b           8 b                 8 b
10705    *
10706    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10707    * represents the highest mode used in the stream (and thus the maximum
10708    * bitrate), with a couple of special cases as seen below.
10709    */
10710
10711   /* Map of frame type ID -> bitrate */
10712   static const guint nb_bitrates[] = {
10713     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10714   };
10715   static const guint wb_bitrates[] = {
10716     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10717   };
10718   GstMapInfo map;
10719   gsize max_mode;
10720   guint16 mode_set;
10721
10722   gst_buffer_map (buf, &map, GST_MAP_READ);
10723
10724   if (map.size != 0x11) {
10725     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10726     goto bad_data;
10727   }
10728
10729   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10730     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10731         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10732     goto bad_data;
10733   }
10734
10735   mode_set = QT_UINT16 (map.data + 13);
10736
10737   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10738     max_mode = 7 + (wb ? 1 : 0);
10739   else
10740     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10741     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10742
10743   if (max_mode == -1) {
10744     GST_DEBUG ("No mode indication was found (mode set) = %x",
10745         (guint) mode_set);
10746     goto bad_data;
10747   }
10748
10749   gst_buffer_unmap (buf, &map);
10750   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10751
10752 bad_data:
10753   gst_buffer_unmap (buf, &map);
10754   return 0;
10755 }
10756
10757 static gboolean
10758 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10759     GstByteReader * reader, guint32 * matrix, const gchar * atom)
10760 {
10761   /*
10762    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10763    * [0 1 2]
10764    * [3 4 5]
10765    * [6 7 8]
10766    */
10767
10768   if (gst_byte_reader_get_remaining (reader) < 36)
10769     return FALSE;
10770
10771   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10772   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10773   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10774   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10775   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10776   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10777   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10778   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10779   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10780
10781   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10782   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10783       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10784       matrix[2] & 0xFF);
10785   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10786       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10787       matrix[5] & 0xFF);
10788   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10789       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10790       matrix[8] & 0xFF);
10791
10792   return TRUE;
10793 }
10794
10795 static void
10796 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10797     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10798 {
10799
10800 /* [a b c]
10801  * [d e f]
10802  * [g h i]
10803  *
10804  * This macro will only compare value abdegh, it expects cfi to have already
10805  * been checked
10806  */
10807 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10808                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
10809
10810   /* only handle the cases where the last column has standard values */
10811   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10812     const gchar *rotation_tag = NULL;
10813
10814     /* no rotation needed */
10815     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10816       /* NOP */
10817     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10818       rotation_tag = "rotate-90";
10819     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10820       rotation_tag = "rotate-180";
10821     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10822       rotation_tag = "rotate-270";
10823     } else {
10824       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10825     }
10826
10827     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10828         rotation_tag);
10829     if (rotation_tag != NULL) {
10830       if (*taglist == NULL)
10831         *taglist = gst_tag_list_new_empty ();
10832       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10833           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10834     }
10835   } else {
10836     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10837   }
10838 }
10839
10840 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10841  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10842  * Common Encryption (cenc), the function will also parse the tenc box (defined
10843  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10844  * (typically an enc[v|a|t|s] sample entry); the function will set
10845  * @original_fmt to the fourcc of the original unencrypted stream format.
10846  * Returns TRUE if successful; FALSE otherwise. */
10847 static gboolean
10848 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10849     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10850 {
10851   GNode *sinf;
10852   GNode *frma;
10853   GNode *schm;
10854   GNode *schi;
10855   QtDemuxCencSampleSetInfo *info;
10856   GNode *tenc;
10857   const guint8 *tenc_data;
10858
10859   g_return_val_if_fail (qtdemux != NULL, FALSE);
10860   g_return_val_if_fail (stream != NULL, FALSE);
10861   g_return_val_if_fail (container != NULL, FALSE);
10862   g_return_val_if_fail (original_fmt != NULL, FALSE);
10863
10864   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10865   if (G_UNLIKELY (!sinf)) {
10866     if (stream->protection_scheme_type == FOURCC_cenc) {
10867       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10868           "mandatory for Common Encryption");
10869       return FALSE;
10870     }
10871     return TRUE;
10872   }
10873
10874   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10875   if (G_UNLIKELY (!frma)) {
10876     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10877     return FALSE;
10878   }
10879
10880   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10881   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10882       GST_FOURCC_ARGS (*original_fmt));
10883
10884   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10885   if (!schm) {
10886     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10887     return FALSE;
10888   }
10889   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10890   stream->protection_scheme_version =
10891       QT_UINT32 ((const guint8 *) schm->data + 16);
10892
10893   GST_DEBUG_OBJECT (qtdemux,
10894       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10895       "protection_scheme_version: %#010x",
10896       GST_FOURCC_ARGS (stream->protection_scheme_type),
10897       stream->protection_scheme_version);
10898
10899   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10900   if (!schi) {
10901     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10902     return FALSE;
10903   }
10904   if (stream->protection_scheme_type != FOURCC_cenc &&
10905       stream->protection_scheme_type != FOURCC_piff) {
10906     GST_ERROR_OBJECT (qtdemux,
10907         "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10908         GST_FOURCC_ARGS (stream->protection_scheme_type));
10909     return FALSE;
10910   }
10911
10912   if (G_UNLIKELY (!stream->protection_scheme_info))
10913     stream->protection_scheme_info =
10914         g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10915
10916   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10917
10918   if (stream->protection_scheme_type == FOURCC_cenc) {
10919     guint32 is_encrypted;
10920     guint8 iv_size;
10921     const guint8 *default_kid;
10922
10923     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10924     if (!tenc) {
10925       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10926           "which is mandatory for Common Encryption");
10927       return FALSE;
10928     }
10929     tenc_data = (const guint8 *) tenc->data + 12;
10930     is_encrypted = QT_UINT24 (tenc_data);
10931     iv_size = QT_UINT8 (tenc_data + 3);
10932     default_kid = (tenc_data + 4);
10933     qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10934         is_encrypted, iv_size, default_kid);
10935   } else if (stream->protection_scheme_type == FOURCC_piff) {
10936     GstByteReader br;
10937     static const guint8 piff_track_encryption_uuid[] = {
10938       0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10939       0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10940     };
10941
10942     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10943     if (!tenc) {
10944       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10945           "which is mandatory for Common Encryption");
10946       return FALSE;
10947     }
10948
10949     tenc_data = (const guint8 *) tenc->data + 8;
10950     if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10951       gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10952       GST_ERROR_OBJECT (qtdemux,
10953           "Unsupported track encryption box with uuid: %s", box_uuid);
10954       g_free (box_uuid);
10955       return FALSE;
10956     }
10957     tenc_data = (const guint8 *) tenc->data + 16 + 12;
10958     gst_byte_reader_init (&br, tenc_data, 20);
10959     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10960       GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10961       return FALSE;
10962     }
10963     stream->protection_scheme_type = FOURCC_cenc;
10964   }
10965
10966   return TRUE;
10967 }
10968
10969 static gint
10970 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10971     QtDemuxStream ** stream2)
10972 {
10973   return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10974 }
10975
10976 /* parse the traks.
10977  * With each track we associate a new QtDemuxStream that contains all the info
10978  * about the trak.
10979  * traks that do not decode to something (like strm traks) will not have a pad.
10980  */
10981 static gboolean
10982 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10983 {
10984   GstByteReader tkhd;
10985   int offset;
10986   GNode *mdia;
10987   GNode *mdhd;
10988   GNode *hdlr;
10989   GNode *minf;
10990   GNode *stbl;
10991   GNode *stsd;
10992   GNode *mp4a;
10993   GNode *mp4v;
10994   GNode *esds;
10995   GNode *tref;
10996   GNode *udta;
10997   GNode *svmi;
10998
10999   QtDemuxStream *stream = NULL;
11000   const guint8 *stsd_data;
11001   const guint8 *stsd_entry_data;
11002   guint remaining_stsd_len;
11003   guint stsd_entry_count;
11004   guint stsd_index;
11005   guint16 lang_code;            /* quicktime lang code or packed iso code */
11006   guint32 version;
11007   guint32 tkhd_flags = 0;
11008   guint8 tkhd_version = 0;
11009   guint32 w = 0, h = 0;
11010   guint value_size, stsd_len, len;
11011   guint32 track_id;
11012   guint32 dummy;
11013
11014   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11015
11016   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11017       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11018       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11019     goto corrupt_file;
11020
11021   /* pick between 64 or 32 bits */
11022   value_size = tkhd_version == 1 ? 8 : 4;
11023   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11024       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11025     goto corrupt_file;
11026
11027   /* Check if current moov has duplicated track_id */
11028   if (qtdemux_find_stream (qtdemux, track_id))
11029     goto existing_stream;
11030
11031   stream = _create_stream (qtdemux, track_id);
11032   stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11033
11034   /* need defaults for fragments */
11035   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11036
11037   if ((tkhd_flags & 1) == 0)
11038     stream->disabled = TRUE;
11039
11040   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11041       tkhd_version, tkhd_flags, stream->track_id);
11042
11043   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11044     goto corrupt_file;
11045
11046   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11047     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11048     if (qtdemux->major_brand != FOURCC_mjp2 ||
11049         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11050       goto corrupt_file;
11051   }
11052
11053   len = QT_UINT32 ((guint8 *) mdhd->data);
11054   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11055   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11056   if (version == 0x01000000) {
11057     if (len < 42)
11058       goto corrupt_file;
11059     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11060     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11061     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11062   } else {
11063     if (len < 30)
11064       goto corrupt_file;
11065     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11066     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11067     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11068   }
11069
11070   if (lang_code < 0x400) {
11071     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11072   } else if (lang_code == 0x7fff) {
11073     stream->lang_id[0] = 0;     /* unspecified */
11074   } else {
11075     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11076     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11077     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11078     stream->lang_id[3] = 0;
11079   }
11080
11081   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11082       stream->timescale);
11083   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11084       stream->duration);
11085   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11086       lang_code, stream->lang_id);
11087
11088   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11089     goto corrupt_file;
11090
11091   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11092     /* chapters track reference */
11093     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11094     if (chap) {
11095       gsize length = GST_READ_UINT32_BE (chap->data);
11096       if (qtdemux->chapters_track_id)
11097         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11098
11099       if (length >= 12) {
11100         qtdemux->chapters_track_id =
11101             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11102       }
11103     }
11104   }
11105
11106   /* fragmented files may have bogus duration in moov */
11107   if (!qtdemux->fragmented &&
11108       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11109     guint64 tdur1, tdur2;
11110
11111     /* don't overflow */
11112     tdur1 = stream->timescale * (guint64) qtdemux->duration;
11113     tdur2 = qtdemux->timescale * (guint64) stream->duration;
11114
11115     /* HACK:
11116      * some of those trailers, nowadays, have prologue images that are
11117      * themselves video tracks as well. I haven't really found a way to
11118      * identify those yet, except for just looking at their duration. */
11119     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11120       GST_WARNING_OBJECT (qtdemux,
11121           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11122           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11123           "found, assuming preview image or something; skipping track",
11124           stream->duration, stream->timescale, qtdemux->duration,
11125           qtdemux->timescale);
11126       gst_qtdemux_stream_unref (stream);
11127       return TRUE;
11128     }
11129   }
11130
11131   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11132     goto corrupt_file;
11133
11134   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11135       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11136
11137   len = QT_UINT32 ((guint8 *) hdlr->data);
11138   if (len >= 20)
11139     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11140   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11141       GST_FOURCC_ARGS (stream->subtype));
11142
11143   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11144     goto corrupt_file;
11145
11146   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11147     goto corrupt_file;
11148
11149   /*parse svmi header if existing */
11150   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
11151   if (svmi) {
11152     len = QT_UINT32 ((guint8 *) svmi->data);
11153     version = QT_UINT32 ((guint8 *) svmi->data + 8);
11154     if (!version) {
11155       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
11156       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
11157       guint8 frame_type, frame_layout;
11158
11159       /* MPEG-A stereo video */
11160       if (qtdemux->major_brand == FOURCC_ss02)
11161         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
11162
11163       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
11164       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
11165       switch (frame_type) {
11166         case 0:
11167           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11168           break;
11169         case 1:
11170           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11171           break;
11172         case 2:
11173           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11174           break;
11175         case 3:
11176           /* mode 3 is primary/secondary view sequence, ie
11177            * left/right views in separate tracks. See section 7.2
11178            * of ISO/IEC 23000-11:2009 */
11179           GST_FIXME_OBJECT (qtdemux,
11180               "Implement stereo video in separate streams");
11181       }
11182
11183       if ((frame_layout & 0x1) == 0)
11184         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11185
11186       GST_LOG_OBJECT (qtdemux,
11187           "StereoVideo: composition type: %u, is_left_first: %u",
11188           frame_type, frame_layout);
11189       stream->multiview_mode = mode;
11190       stream->multiview_flags = flags;
11191     }
11192   }
11193
11194   /* parse rest of tkhd */
11195   if (stream->subtype == FOURCC_vide) {
11196     guint32 matrix[9];
11197
11198     /* version 1 uses some 64-bit ints */
11199     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11200       goto corrupt_file;
11201
11202     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11203       goto corrupt_file;
11204
11205     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11206         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11207       goto corrupt_file;
11208
11209     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11210         &stream->stream_tags);
11211   }
11212
11213   /* parse stsd */
11214   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11215     goto corrupt_file;
11216   stsd_data = (const guint8 *) stsd->data;
11217
11218   /* stsd should at least have one entry */
11219   stsd_len = QT_UINT32 (stsd_data);
11220   if (stsd_len < 24) {
11221     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11222     if (stream->subtype == FOURCC_vivo) {
11223       gst_qtdemux_stream_unref (stream);
11224       return TRUE;
11225     } else {
11226       goto corrupt_file;
11227     }
11228   }
11229
11230   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11231   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11232   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
11233   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
11234
11235   stsd_entry_data = stsd_data + 16;
11236   remaining_stsd_len = stsd_len - 16;
11237   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11238     guint32 fourcc;
11239     gchar *codec = NULL;
11240     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11241
11242     /* and that entry should fit within stsd */
11243     len = QT_UINT32 (stsd_entry_data);
11244     if (len > remaining_stsd_len)
11245       goto corrupt_file;
11246
11247     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11248     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
11249         GST_FOURCC_ARGS (entry->fourcc));
11250     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
11251
11252     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11253       goto error_encrypted;
11254
11255     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11256       /* FIXME this looks wrong, there might be multiple children
11257        * with the same type */
11258       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11259       stream->protected = TRUE;
11260       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11261         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11262     }
11263
11264     if (stream->subtype == FOURCC_vide) {
11265       GNode *colr;
11266       GNode *fiel;
11267       GNode *pasp;
11268       gboolean gray;
11269       gint depth, palette_size, palette_count;
11270       guint32 *palette_data = NULL;
11271
11272       entry->sampled = TRUE;
11273
11274       stream->display_width = w >> 16;
11275       stream->display_height = h >> 16;
11276
11277       offset = 16;
11278       if (len < 86)             /* TODO verify */
11279         goto corrupt_file;
11280
11281       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11282       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11283       entry->fps_n = 0;         /* this is filled in later */
11284       entry->fps_d = 0;         /* this is filled in later */
11285       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11286       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11287
11288       /* if color_table_id is 0, ctab atom must follow; however some files
11289        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11290        * if color table is not present we'll correct the value */
11291       if (entry->color_table_id == 0 &&
11292           (len < 90
11293               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11294         entry->color_table_id = -1;
11295       }
11296
11297       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11298           entry->width, entry->height, entry->bits_per_sample,
11299           entry->color_table_id);
11300
11301       depth = entry->bits_per_sample;
11302
11303       /* more than 32 bits means grayscale */
11304       gray = (depth > 32);
11305       /* low 32 bits specify the depth  */
11306       depth &= 0x1F;
11307
11308       /* different number of palette entries is determined by depth. */
11309       palette_count = 0;
11310       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11311         palette_count = (1 << depth);
11312       palette_size = palette_count * 4;
11313
11314       if (entry->color_table_id) {
11315         switch (palette_count) {
11316           case 0:
11317             break;
11318           case 2:
11319             palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
11320             break;
11321           case 4:
11322             palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
11323             break;
11324           case 16:
11325             if (gray)
11326               palette_data =
11327                   g_memdup (ff_qt_grayscale_palette_16, palette_size);
11328             else
11329               palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
11330             break;
11331           case 256:
11332             if (gray)
11333               palette_data =
11334                   g_memdup (ff_qt_grayscale_palette_256, palette_size);
11335             else
11336               palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
11337             break;
11338           default:
11339             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11340                 (_("The video in this file might not play correctly.")),
11341                 ("unsupported palette depth %d", depth));
11342             break;
11343         }
11344       } else {
11345         gint i, j, start, end;
11346
11347         if (len < 94)
11348           goto corrupt_file;
11349
11350         /* read table */
11351         start = QT_UINT32 (stsd_entry_data + offset + 70);
11352         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11353         end = QT_UINT16 (stsd_entry_data + offset + 76);
11354
11355         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11356             start, end, palette_count);
11357
11358         if (end > 255)
11359           end = 255;
11360         if (start > end)
11361           start = end;
11362
11363         if (len < 94 + (end - start) * 8)
11364           goto corrupt_file;
11365
11366         /* palette is always the same size */
11367         palette_data = g_malloc0 (256 * 4);
11368         palette_size = 256 * 4;
11369
11370         for (j = 0, i = start; i <= end; j++, i++) {
11371           guint32 a, r, g, b;
11372
11373           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11374           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11375           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11376           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11377
11378           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11379               (g & 0xff00) | (b >> 8);
11380         }
11381       }
11382
11383       if (entry->caps)
11384         gst_caps_unref (entry->caps);
11385
11386       entry->caps =
11387           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11388           &codec);
11389       if (G_UNLIKELY (!entry->caps)) {
11390         g_free (palette_data);
11391         goto unknown_stream;
11392       }
11393
11394       if (codec) {
11395         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11396             GST_TAG_VIDEO_CODEC, codec, NULL);
11397         g_free (codec);
11398         codec = NULL;
11399       }
11400
11401       if (palette_data) {
11402         GstStructure *s;
11403
11404         if (entry->rgb8_palette)
11405           gst_memory_unref (entry->rgb8_palette);
11406         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11407             palette_data, palette_size, 0, palette_size, palette_data, g_free);
11408
11409         s = gst_caps_get_structure (entry->caps, 0);
11410
11411         /* non-raw video has a palette_data property. raw video has the palette as
11412          * an extra plane that we append to the output buffers before we push
11413          * them*/
11414         if (!gst_structure_has_name (s, "video/x-raw")) {
11415           GstBuffer *palette;
11416
11417           palette = gst_buffer_new ();
11418           gst_buffer_append_memory (palette, entry->rgb8_palette);
11419           entry->rgb8_palette = NULL;
11420
11421           gst_caps_set_simple (entry->caps, "palette_data",
11422               GST_TYPE_BUFFER, palette, NULL);
11423           gst_buffer_unref (palette);
11424         }
11425       } else if (palette_count != 0) {
11426         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11427             (NULL), ("Unsupported palette depth %d", depth));
11428       }
11429
11430       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
11431           QT_UINT16 (stsd_entry_data + offset + 32));
11432
11433       esds = NULL;
11434       pasp = NULL;
11435       colr = NULL;
11436       fiel = NULL;
11437       /* pick 'the' stsd child */
11438       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11439       // We should skip parsing the stsd for non-protected streams if
11440       // the entry doesn't match the fourcc, since they don't change
11441       // format. However, for protected streams we can have partial
11442       // encryption, where parts of the stream are encrypted and parts
11443       // not. For both parts of such streams, we should ensure the
11444       // esds overrides are parsed for both from the stsd.
11445       if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11446         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11447           mp4v = NULL;
11448         else if (!stream->protected)
11449           mp4v = NULL;
11450       }
11451
11452       if (mp4v) {
11453         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11454         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11455         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11456         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11457       }
11458
11459       if (pasp) {
11460         const guint8 *pasp_data = (const guint8 *) pasp->data;
11461         gint len = QT_UINT32 (pasp_data);
11462
11463         if (len == 16) {
11464           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11465           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11466         } else {
11467           CUR_STREAM (stream)->par_w = 0;
11468           CUR_STREAM (stream)->par_h = 0;
11469         }
11470       } else {
11471         CUR_STREAM (stream)->par_w = 0;
11472         CUR_STREAM (stream)->par_h = 0;
11473       }
11474
11475       if (fiel) {
11476         const guint8 *fiel_data = (const guint8 *) fiel->data;
11477         gint len = QT_UINT32 (fiel_data);
11478
11479         if (len == 10) {
11480           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11481           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11482         }
11483       }
11484
11485       if (colr) {
11486         const guint8 *colr_data = (const guint8 *) colr->data;
11487         gint len = QT_UINT32 (colr_data);
11488
11489         if (len == 19 || len == 18) {
11490           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11491
11492           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11493             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11494             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11495             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11496             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11497
11498             switch (primaries) {
11499               case 1:
11500                 CUR_STREAM (stream)->colorimetry.primaries =
11501                     GST_VIDEO_COLOR_PRIMARIES_BT709;
11502                 break;
11503               case 5:
11504                 CUR_STREAM (stream)->colorimetry.primaries =
11505                     GST_VIDEO_COLOR_PRIMARIES_BT470BG;
11506                 break;
11507               case 6:
11508                 CUR_STREAM (stream)->colorimetry.primaries =
11509                     GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
11510                 break;
11511               case 9:
11512                 CUR_STREAM (stream)->colorimetry.primaries =
11513                     GST_VIDEO_COLOR_PRIMARIES_BT2020;
11514                 break;
11515               default:
11516                 break;
11517             }
11518
11519             switch (transfer_function) {
11520               case 1:
11521                 CUR_STREAM (stream)->colorimetry.transfer =
11522                     GST_VIDEO_TRANSFER_BT709;
11523                 break;
11524               case 7:
11525                 CUR_STREAM (stream)->colorimetry.transfer =
11526                     GST_VIDEO_TRANSFER_SMPTE240M;
11527                 break;
11528               default:
11529                 break;
11530             }
11531
11532             switch (matrix) {
11533               case 1:
11534                 CUR_STREAM (stream)->colorimetry.matrix =
11535                     GST_VIDEO_COLOR_MATRIX_BT709;
11536                 break;
11537               case 6:
11538                 CUR_STREAM (stream)->colorimetry.matrix =
11539                     GST_VIDEO_COLOR_MATRIX_BT601;
11540                 break;
11541               case 7:
11542                 CUR_STREAM (stream)->colorimetry.matrix =
11543                     GST_VIDEO_COLOR_MATRIX_SMPTE240M;
11544                 break;
11545               case 9:
11546                 CUR_STREAM (stream)->colorimetry.matrix =
11547                     GST_VIDEO_COLOR_MATRIX_BT2020;
11548                 break;
11549               default:
11550                 break;
11551             }
11552
11553             CUR_STREAM (stream)->colorimetry.range =
11554                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11555                 GST_VIDEO_COLOR_RANGE_16_235;
11556           } else {
11557             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11558           }
11559         } else {
11560           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11561         }
11562       }
11563
11564       if (esds) {
11565         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11566             stream->stream_tags);
11567       } else {
11568         switch (fourcc) {
11569           case FOURCC_H264:
11570           case FOURCC_avc1:
11571           case FOURCC_avc3:
11572           {
11573             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11574             const guint8 *avc_data = stsd_entry_data + 0x56;
11575
11576             /* find avcC */
11577             while (len >= 0x8) {
11578               gint size;
11579
11580               if (QT_UINT32 (avc_data) <= len)
11581                 size = QT_UINT32 (avc_data) - 0x8;
11582               else
11583                 size = len - 0x8;
11584
11585               if (size < 1)
11586                 /* No real data, so break out */
11587                 break;
11588
11589               switch (QT_FOURCC (avc_data + 0x4)) {
11590                 case FOURCC_avcC:
11591                 {
11592                   /* parse, if found */
11593                   GstBuffer *buf;
11594
11595                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11596
11597                   /* First 4 bytes are the length of the atom, the next 4 bytes
11598                    * are the fourcc, the next 1 byte is the version, and the
11599                    * subsequent bytes are profile_tier_level structure like data. */
11600                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11601                       avc_data + 8 + 1, size - 1);
11602                   buf = gst_buffer_new_and_alloc (size);
11603                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11604                   gst_caps_set_simple (entry->caps,
11605                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11606                   gst_buffer_unref (buf);
11607
11608                   break;
11609                 }
11610                 case FOURCC_strf:
11611                 {
11612                   GstBuffer *buf;
11613
11614                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11615
11616                   /* First 4 bytes are the length of the atom, the next 4 bytes
11617                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11618                    * next 1 byte is the version, and the
11619                    * subsequent bytes are sequence parameter set like data. */
11620
11621                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
11622                   if (size > 1) {
11623                     gst_codec_utils_h264_caps_set_level_and_profile
11624                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11625
11626                     buf = gst_buffer_new_and_alloc (size);
11627                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11628                     gst_caps_set_simple (entry->caps,
11629                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
11630                     gst_buffer_unref (buf);
11631                   }
11632                   break;
11633                 }
11634                 case FOURCC_btrt:
11635                 {
11636                   guint avg_bitrate, max_bitrate;
11637
11638                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11639                   if (size < 12)
11640                     break;
11641
11642                   max_bitrate = QT_UINT32 (avc_data + 0xc);
11643                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
11644
11645                   if (!max_bitrate && !avg_bitrate)
11646                     break;
11647
11648                   /* Some muxers seem to swap the average and maximum bitrates
11649                    * (I'm looking at you, YouTube), so we swap for sanity. */
11650                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11651                     guint temp = avg_bitrate;
11652
11653                     avg_bitrate = max_bitrate;
11654                     max_bitrate = temp;
11655                   }
11656
11657                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11658                     gst_tag_list_add (stream->stream_tags,
11659                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11660                         max_bitrate, NULL);
11661                   }
11662                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11663                     gst_tag_list_add (stream->stream_tags,
11664                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11665                         NULL);
11666                   }
11667
11668                   break;
11669                 }
11670
11671                 default:
11672                   break;
11673               }
11674
11675               len -= size + 8;
11676               avc_data += size + 8;
11677             }
11678
11679             break;
11680           }
11681           case FOURCC_H265:
11682           case FOURCC_hvc1:
11683           case FOURCC_hev1:
11684           {
11685             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11686             const guint8 *hevc_data = stsd_entry_data + 0x56;
11687
11688             /* find hevc */
11689             while (len >= 0x8) {
11690               gint size;
11691
11692               if (QT_UINT32 (hevc_data) <= len)
11693                 size = QT_UINT32 (hevc_data) - 0x8;
11694               else
11695                 size = len - 0x8;
11696
11697               if (size < 1)
11698                 /* No real data, so break out */
11699                 break;
11700
11701               switch (QT_FOURCC (hevc_data + 0x4)) {
11702                 case FOURCC_hvcC:
11703                 {
11704                   /* parse, if found */
11705                   GstBuffer *buf;
11706
11707                   GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11708
11709                   /* First 4 bytes are the length of the atom, the next 4 bytes
11710                    * are the fourcc, the next 1 byte is the version, and the
11711                    * subsequent bytes are sequence parameter set like data. */
11712                   gst_codec_utils_h265_caps_set_level_tier_and_profile
11713                       (entry->caps, hevc_data + 8 + 1, size - 1);
11714
11715                   buf = gst_buffer_new_and_alloc (size);
11716                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11717                   gst_caps_set_simple (entry->caps,
11718                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11719                   gst_buffer_unref (buf);
11720                   break;
11721                 }
11722                 default:
11723                   break;
11724               }
11725               len -= size + 8;
11726               hevc_data += size + 8;
11727             }
11728             break;
11729           }
11730           case FOURCC_mp4v:
11731           case FOURCC_MP4V:
11732           case FOURCC_fmp4:
11733           case FOURCC_FMP4:
11734           case FOURCC_xvid:
11735           case FOURCC_XVID:
11736           {
11737             GNode *glbl;
11738
11739             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11740                 GST_FOURCC_ARGS (fourcc));
11741
11742             /* codec data might be in glbl extension atom */
11743             glbl = mp4v ?
11744                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11745             if (glbl) {
11746               guint8 *data;
11747               GstBuffer *buf;
11748               gint len;
11749
11750               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11751               data = glbl->data;
11752               len = QT_UINT32 (data);
11753               if (len > 0x8) {
11754                 len -= 0x8;
11755                 buf = gst_buffer_new_and_alloc (len);
11756                 gst_buffer_fill (buf, 0, data + 8, len);
11757                 gst_caps_set_simple (entry->caps,
11758                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11759                 gst_buffer_unref (buf);
11760               }
11761             }
11762             break;
11763           }
11764           case FOURCC_mjp2:
11765           {
11766             /* see annex I of the jpeg2000 spec */
11767             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11768             const guint8 *data;
11769             const gchar *colorspace = NULL;
11770             gint ncomp = 0;
11771             guint32 ncomp_map = 0;
11772             gint32 *comp_map = NULL;
11773             guint32 nchan_def = 0;
11774             gint32 *chan_def = NULL;
11775
11776             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11777             /* some required atoms */
11778             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11779             if (!mjp2)
11780               break;
11781             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11782             if (!jp2h)
11783               break;
11784
11785             /* number of components; redundant with info in codestream, but useful
11786                to a muxer */
11787             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11788             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11789               break;
11790             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11791
11792             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11793             if (!colr)
11794               break;
11795             GST_DEBUG_OBJECT (qtdemux, "found colr");
11796             /* extract colour space info */
11797             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11798               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11799                 case 16:
11800                   colorspace = "sRGB";
11801                   break;
11802                 case 17:
11803                   colorspace = "GRAY";
11804                   break;
11805                 case 18:
11806                   colorspace = "sYUV";
11807                   break;
11808                 default:
11809                   colorspace = NULL;
11810                   break;
11811               }
11812             }
11813             if (!colorspace)
11814               /* colr is required, and only values 16, 17, and 18 are specified,
11815                  so error if we have no colorspace */
11816               break;
11817
11818             /* extract component mapping */
11819             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11820             if (cmap) {
11821               guint32 cmap_len = 0;
11822               int i;
11823               cmap_len = QT_UINT32 (cmap->data);
11824               if (cmap_len >= 8) {
11825                 /* normal box, subtract off header */
11826                 cmap_len -= 8;
11827                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11828                 if (cmap_len % 4 == 0) {
11829                   ncomp_map = (cmap_len / 4);
11830                   comp_map = g_new0 (gint32, ncomp_map);
11831                   for (i = 0; i < ncomp_map; i++) {
11832                     guint16 cmp;
11833                     guint8 mtyp, pcol;
11834                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11835                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11836                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11837                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11838                   }
11839                 }
11840               }
11841             }
11842             /* extract channel definitions */
11843             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11844             if (cdef) {
11845               guint32 cdef_len = 0;
11846               int i;
11847               cdef_len = QT_UINT32 (cdef->data);
11848               if (cdef_len >= 10) {
11849                 /* normal box, subtract off header and len */
11850                 cdef_len -= 10;
11851                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11852                 if (cdef_len % 6 == 0) {
11853                   nchan_def = (cdef_len / 6);
11854                   chan_def = g_new0 (gint32, nchan_def);
11855                   for (i = 0; i < nchan_def; i++)
11856                     chan_def[i] = -1;
11857                   for (i = 0; i < nchan_def; i++) {
11858                     guint16 cn, typ, asoc;
11859                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11860                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11861                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11862                     if (cn < nchan_def) {
11863                       switch (typ) {
11864                         case 0:
11865                           chan_def[cn] = asoc;
11866                           break;
11867                         case 1:
11868                           chan_def[cn] = 0;     /* alpha */
11869                           break;
11870                         default:
11871                           chan_def[cn] = -typ;
11872                       }
11873                     }
11874                   }
11875                 }
11876               }
11877             }
11878
11879             gst_caps_set_simple (entry->caps,
11880                 "num-components", G_TYPE_INT, ncomp, NULL);
11881             gst_caps_set_simple (entry->caps,
11882                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11883
11884             if (comp_map) {
11885               GValue arr = { 0, };
11886               GValue elt = { 0, };
11887               int i;
11888               g_value_init (&arr, GST_TYPE_ARRAY);
11889               g_value_init (&elt, G_TYPE_INT);
11890               for (i = 0; i < ncomp_map; i++) {
11891                 g_value_set_int (&elt, comp_map[i]);
11892                 gst_value_array_append_value (&arr, &elt);
11893               }
11894               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11895                   "component-map", &arr);
11896               g_value_unset (&elt);
11897               g_value_unset (&arr);
11898               g_free (comp_map);
11899             }
11900
11901             if (chan_def) {
11902               GValue arr = { 0, };
11903               GValue elt = { 0, };
11904               int i;
11905               g_value_init (&arr, GST_TYPE_ARRAY);
11906               g_value_init (&elt, G_TYPE_INT);
11907               for (i = 0; i < nchan_def; i++) {
11908                 g_value_set_int (&elt, chan_def[i]);
11909                 gst_value_array_append_value (&arr, &elt);
11910               }
11911               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11912                   "channel-definitions", &arr);
11913               g_value_unset (&elt);
11914               g_value_unset (&arr);
11915               g_free (chan_def);
11916             }
11917
11918             /* some optional atoms */
11919             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11920             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11921
11922             /* indicate possible fields in caps */
11923             if (field) {
11924               data = (guint8 *) field->data + 8;
11925               if (*data != 1)
11926                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11927                     (gint) * data, NULL);
11928             }
11929             /* add codec_data if provided */
11930             if (prefix) {
11931               GstBuffer *buf;
11932               gint len;
11933
11934               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11935               data = prefix->data;
11936               len = QT_UINT32 (data);
11937               if (len > 0x8) {
11938                 len -= 0x8;
11939                 buf = gst_buffer_new_and_alloc (len);
11940                 gst_buffer_fill (buf, 0, data + 8, len);
11941                 gst_caps_set_simple (entry->caps,
11942                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11943                 gst_buffer_unref (buf);
11944               }
11945             }
11946             break;
11947           }
11948           case FOURCC_SVQ3:
11949           case FOURCC_VP31:
11950           {
11951             GstBuffer *buf;
11952             GstBuffer *seqh = NULL;
11953             const guint8 *gamma_data = NULL;
11954             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11955
11956             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11957                 &seqh);
11958             if (gamma_data) {
11959               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11960                   QT_FP32 (gamma_data), NULL);
11961             }
11962             if (seqh) {
11963               /* sorry for the bad name, but we don't know what this is, other
11964                * than its own fourcc */
11965               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11966                   NULL);
11967               gst_buffer_unref (seqh);
11968             }
11969
11970             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11971             buf = gst_buffer_new_and_alloc (len);
11972             gst_buffer_fill (buf, 0, stsd_data, len);
11973             gst_caps_set_simple (entry->caps,
11974                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11975             gst_buffer_unref (buf);
11976             break;
11977           }
11978           case FOURCC_jpeg:
11979           {
11980             /* https://developer.apple.com/standards/qtff-2001.pdf,
11981              * page 92, "Video Sample Description", under table 3.1 */
11982             GstByteReader br;
11983
11984             const gint compressor_offset =
11985                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11986             const gint min_size = compressor_offset + 32 + 2 + 2;
11987             GNode *jpeg;
11988             guint32 len;
11989             guint16 color_table_id = 0;
11990             gboolean ok;
11991
11992             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11993
11994             /* recover information on interlaced/progressive */
11995             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11996             if (!jpeg)
11997               break;
11998
11999             len = QT_UINT32 (jpeg->data);
12000             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
12001                 min_size);
12002             if (len >= min_size) {
12003               gst_byte_reader_init (&br, jpeg->data, len);
12004
12005               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
12006               gst_byte_reader_get_uint16_le (&br, &color_table_id);
12007               if (color_table_id != 0) {
12008                 /* the spec says there can be concatenated chunks in the data, and we want
12009                  * to find one called field. Walk through them. */
12010                 gint offset = min_size;
12011                 while (offset + 8 < len) {
12012                   guint32 size = 0, tag;
12013                   ok = gst_byte_reader_get_uint32_le (&br, &size);
12014                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12015                   if (!ok || size < 8) {
12016                     GST_WARNING_OBJECT (qtdemux,
12017                         "Failed to walk optional chunk list");
12018                     break;
12019                   }
12020                   GST_DEBUG_OBJECT (qtdemux,
12021                       "Found optional %4.4s chunk, size %u",
12022                       (const char *) &tag, size);
12023                   if (tag == FOURCC_fiel) {
12024                     guint8 n_fields = 0, ordering = 0;
12025                     gst_byte_reader_get_uint8 (&br, &n_fields);
12026                     gst_byte_reader_get_uint8 (&br, &ordering);
12027                     if (n_fields == 1 || n_fields == 2) {
12028                       GST_DEBUG_OBJECT (qtdemux,
12029                           "Found fiel tag with %u fields, ordering %u",
12030                           n_fields, ordering);
12031                       if (n_fields == 2)
12032                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
12033                             "interlace-mode", G_TYPE_STRING, "interleaved",
12034                             NULL);
12035                     } else {
12036                       GST_WARNING_OBJECT (qtdemux,
12037                           "Found fiel tag with invalid fields (%u)", n_fields);
12038                     }
12039                   }
12040                   offset += size;
12041                 }
12042               } else {
12043                 GST_DEBUG_OBJECT (qtdemux,
12044                     "Color table ID is 0, not trying to get interlacedness");
12045               }
12046             } else {
12047               GST_WARNING_OBJECT (qtdemux,
12048                   "Length of jpeg chunk is too small, not trying to get interlacedness");
12049             }
12050
12051             break;
12052           }
12053           case FOURCC_rle_:
12054           case FOURCC_WRLE:
12055           {
12056             gst_caps_set_simple (entry->caps,
12057                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12058                 NULL);
12059             break;
12060           }
12061           case FOURCC_XiTh:
12062           {
12063             GNode *xith, *xdxt;
12064
12065             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12066             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12067             if (!xith)
12068               break;
12069
12070             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12071             if (!xdxt)
12072               break;
12073
12074             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12075             /* collect the headers and store them in a stream list so that we can
12076              * send them out first */
12077             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12078             break;
12079           }
12080           case FOURCC_ovc1:
12081           {
12082             GNode *ovc1;
12083             guint8 *ovc1_data;
12084             guint ovc1_len;
12085             GstBuffer *buf;
12086
12087             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12088             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12089             if (!ovc1)
12090               break;
12091             ovc1_data = ovc1->data;
12092             ovc1_len = QT_UINT32 (ovc1_data);
12093             if (ovc1_len <= 198) {
12094               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12095               break;
12096             }
12097             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12098             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12099             gst_caps_set_simple (entry->caps,
12100                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12101             gst_buffer_unref (buf);
12102             break;
12103           }
12104           case FOURCC_vc_1:
12105           {
12106             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12107             const guint8 *vc1_data = stsd_entry_data + 0x56;
12108
12109             /* find dvc1 */
12110             while (len >= 8) {
12111               gint size;
12112
12113               if (QT_UINT32 (vc1_data) <= len)
12114                 size = QT_UINT32 (vc1_data) - 8;
12115               else
12116                 size = len - 8;
12117
12118               if (size < 1)
12119                 /* No real data, so break out */
12120                 break;
12121
12122               switch (QT_FOURCC (vc1_data + 0x4)) {
12123                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12124                 {
12125                   GstBuffer *buf;
12126
12127                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12128                   buf = gst_buffer_new_and_alloc (size);
12129                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
12130                   gst_caps_set_simple (entry->caps,
12131                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12132                   gst_buffer_unref (buf);
12133                   break;
12134                 }
12135                 default:
12136                   break;
12137               }
12138               len -= size + 8;
12139               vc1_data += size + 8;
12140             }
12141             break;
12142           }
12143           case FOURCC_av01:
12144           {
12145             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12146             const guint8 *av1_data = stsd_entry_data + 0x56;
12147
12148             /* find av1C */
12149             while (len >= 0x8) {
12150               gint size;
12151
12152               if (QT_UINT32 (av1_data) <= len)
12153                 size = QT_UINT32 (av1_data) - 0x8;
12154               else
12155                 size = len - 0x8;
12156
12157               if (size < 1)
12158                 /* No real data, so break out */
12159                 break;
12160
12161               switch (QT_FOURCC (av1_data + 0x4)) {
12162                 case FOURCC_av1C:
12163                 {
12164                   /* parse, if found */
12165                   GstBuffer *buf;
12166                   guint8 pres_delay_field;
12167
12168                   GST_DEBUG_OBJECT (qtdemux,
12169                       "found av1C codec_data in stsd of size %d", size);
12170
12171                   /* not enough data, just ignore and hope for the best */
12172                   if (size < 5)
12173                     break;
12174
12175                   /* Content is:
12176                    * 4 bytes: atom length
12177                    * 4 bytes: fourcc
12178                    * 1 byte: version
12179                    * 3 bytes: flags
12180                    * 3 bits: reserved
12181                    * 1 bits:  initial_presentation_delay_present
12182                    * 4 bits: initial_presentation_delay (if present else reserved
12183                    * rest: OBUs.
12184                    */
12185
12186                   if (av1_data[9] != 0) {
12187                     GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12188                     break;
12189                   }
12190
12191                   /* We skip initial_presentation_delay* for now */
12192                   pres_delay_field = *(av1_data + 12);
12193                   if (pres_delay_field & (1 << 5)) {
12194                     gst_caps_set_simple (entry->caps,
12195                         "presentation-delay", G_TYPE_INT,
12196                         (gint) (pres_delay_field & 0x0F) + 1, NULL);
12197                   }
12198                   if (size > 5) {
12199                     buf = gst_buffer_new_and_alloc (size - 5);
12200                     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12201                     gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12202                     gst_caps_set_simple (entry->caps,
12203                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
12204                     gst_buffer_unref (buf);
12205                   }
12206                   break;
12207                 }
12208                 default:
12209                   break;
12210               }
12211
12212               len -= size + 8;
12213               av1_data += size + 8;
12214             }
12215
12216             break;
12217           }
12218           default:
12219             break;
12220         }
12221       }
12222
12223       GST_INFO_OBJECT (qtdemux,
12224           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12225           GST_FOURCC_ARGS (fourcc), entry->caps);
12226
12227     } else if (stream->subtype == FOURCC_soun) {
12228       GNode *wave;
12229       int version, samplesize;
12230       guint16 compression_id;
12231       gboolean amrwb = FALSE;
12232
12233       offset = 16;
12234       /* sample description entry (16) + sound sample description v0 (20) */
12235       if (len < 36)
12236         goto corrupt_file;
12237
12238       version = QT_UINT32 (stsd_entry_data + offset);
12239       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12240       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12241       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12242       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12243
12244       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
12245       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
12246           QT_UINT32 (stsd_entry_data + offset + 4));
12247       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
12248       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
12249       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
12250       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
12251           QT_UINT16 (stsd_entry_data + offset + 14));
12252       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
12253
12254       if (compression_id == 0xfffe)
12255         entry->sampled = TRUE;
12256
12257       /* first assume uncompressed audio */
12258       entry->bytes_per_sample = samplesize / 8;
12259       entry->samples_per_frame = entry->n_channels;
12260       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12261       entry->samples_per_packet = entry->samples_per_frame;
12262       entry->bytes_per_packet = entry->bytes_per_sample;
12263
12264       offset = 36;
12265       switch (fourcc) {
12266           /* Yes, these have to be hard-coded */
12267         case FOURCC_MAC6:
12268         {
12269           entry->samples_per_packet = 6;
12270           entry->bytes_per_packet = 1;
12271           entry->bytes_per_frame = 1 * entry->n_channels;
12272           entry->bytes_per_sample = 1;
12273           entry->samples_per_frame = 6 * entry->n_channels;
12274           break;
12275         }
12276         case FOURCC_MAC3:
12277         {
12278           entry->samples_per_packet = 3;
12279           entry->bytes_per_packet = 1;
12280           entry->bytes_per_frame = 1 * entry->n_channels;
12281           entry->bytes_per_sample = 1;
12282           entry->samples_per_frame = 3 * entry->n_channels;
12283           break;
12284         }
12285         case FOURCC_ima4:
12286         {
12287           entry->samples_per_packet = 64;
12288           entry->bytes_per_packet = 34;
12289           entry->bytes_per_frame = 34 * entry->n_channels;
12290           entry->bytes_per_sample = 2;
12291           entry->samples_per_frame = 64 * entry->n_channels;
12292           break;
12293         }
12294         case FOURCC_ulaw:
12295         case FOURCC_alaw:
12296         {
12297           entry->samples_per_packet = 1;
12298           entry->bytes_per_packet = 1;
12299           entry->bytes_per_frame = 1 * entry->n_channels;
12300           entry->bytes_per_sample = 1;
12301           entry->samples_per_frame = 1 * entry->n_channels;
12302           break;
12303         }
12304         case FOURCC_agsm:
12305         {
12306           entry->samples_per_packet = 160;
12307           entry->bytes_per_packet = 33;
12308           entry->bytes_per_frame = 33 * entry->n_channels;
12309           entry->bytes_per_sample = 2;
12310           entry->samples_per_frame = 160 * entry->n_channels;
12311           break;
12312         }
12313         default:
12314           break;
12315       }
12316
12317       if (version == 0x00010000) {
12318         /* sample description entry (16) + sound sample description v1 (20+16) */
12319         if (len < 52)
12320           goto corrupt_file;
12321
12322         switch (fourcc) {
12323           case FOURCC_twos:
12324           case FOURCC_sowt:
12325           case FOURCC_raw_:
12326           case FOURCC_lpcm:
12327             break;
12328           default:
12329           {
12330             /* only parse extra decoding config for non-pcm audio */
12331             entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12332             entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12333             entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12334             entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12335
12336             GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
12337                 entry->samples_per_packet);
12338             GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
12339                 entry->bytes_per_packet);
12340             GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
12341                 entry->bytes_per_frame);
12342             GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
12343                 entry->bytes_per_sample);
12344
12345             if (!entry->sampled && entry->bytes_per_packet) {
12346               entry->samples_per_frame = (entry->bytes_per_frame /
12347                   entry->bytes_per_packet) * entry->samples_per_packet;
12348               GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
12349                   entry->samples_per_frame);
12350             }
12351             break;
12352           }
12353         }
12354       } else if (version == 0x00020000) {
12355         union
12356         {
12357           gdouble fp;
12358           guint64 val;
12359         } qtfp;
12360
12361         /* sample description entry (16) + sound sample description v2 (56) */
12362         if (len < 72)
12363           goto corrupt_file;
12364
12365         qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
12366         entry->rate = qtfp.fp;
12367         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12368
12369         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12370         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
12371         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
12372         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
12373             QT_UINT32 (stsd_entry_data + offset + 20));
12374         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
12375             QT_UINT32 (stsd_entry_data + offset + 24));
12376         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
12377             QT_UINT32 (stsd_entry_data + offset + 28));
12378         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12379             QT_UINT32 (stsd_entry_data + offset + 32));
12380       } else if (version != 0x00000) {
12381         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12382             version);
12383       }
12384
12385       if (entry->caps)
12386         gst_caps_unref (entry->caps);
12387
12388       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12389           stsd_entry_data + 32, len - 16, &codec);
12390
12391       switch (fourcc) {
12392         case FOURCC_in24:
12393         {
12394           GNode *enda;
12395           GNode *in24;
12396
12397           in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
12398
12399           enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
12400           if (!enda) {
12401             wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
12402             if (wave)
12403               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12404           }
12405           if (enda) {
12406             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12407             gst_caps_set_simple (entry->caps,
12408                 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
12409                 NULL);
12410           }
12411           break;
12412         }
12413         case FOURCC_owma:
12414         {
12415           const guint8 *owma_data;
12416           const gchar *codec_name = NULL;
12417           guint owma_len;
12418           GstBuffer *buf;
12419           gint version = 1;
12420           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12421           /* FIXME this should also be gst_riff_strf_auds,
12422            * but the latter one is actually missing bits-per-sample :( */
12423           typedef struct
12424           {
12425             gint16 wFormatTag;
12426             gint16 nChannels;
12427             gint32 nSamplesPerSec;
12428             gint32 nAvgBytesPerSec;
12429             gint16 nBlockAlign;
12430             gint16 wBitsPerSample;
12431             gint16 cbSize;
12432           } WAVEFORMATEX;
12433           WAVEFORMATEX *wfex;
12434
12435           GST_DEBUG_OBJECT (qtdemux, "parse owma");
12436           owma_data = stsd_entry_data;
12437           owma_len = QT_UINT32 (owma_data);
12438           if (owma_len <= 54) {
12439             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12440             break;
12441           }
12442           wfex = (WAVEFORMATEX *) (owma_data + 36);
12443           buf = gst_buffer_new_and_alloc (owma_len - 54);
12444           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12445           if (wfex->wFormatTag == 0x0161) {
12446             codec_name = "Windows Media Audio";
12447             version = 2;
12448           } else if (wfex->wFormatTag == 0x0162) {
12449             codec_name = "Windows Media Audio 9 Pro";
12450             version = 3;
12451           } else if (wfex->wFormatTag == 0x0163) {
12452             codec_name = "Windows Media Audio 9 Lossless";
12453             /* is that correct? gstffmpegcodecmap.c is missing it, but
12454              * fluendo codec seems to support it */
12455             version = 4;
12456           }
12457
12458           gst_caps_set_simple (entry->caps,
12459               "codec_data", GST_TYPE_BUFFER, buf,
12460               "wmaversion", G_TYPE_INT, version,
12461               "block_align", G_TYPE_INT,
12462               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12463               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12464               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12465               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12466           gst_buffer_unref (buf);
12467
12468           if (codec_name) {
12469             g_free (codec);
12470             codec = g_strdup (codec_name);
12471           }
12472           break;
12473         }
12474         case FOURCC_wma_:
12475         {
12476           gint len = QT_UINT32 (stsd_entry_data) - offset;
12477           const guint8 *wfex_data = stsd_entry_data + offset;
12478           const gchar *codec_name = NULL;
12479           gint version = 1;
12480           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12481           /* FIXME this should also be gst_riff_strf_auds,
12482            * but the latter one is actually missing bits-per-sample :( */
12483           typedef struct
12484           {
12485             gint16 wFormatTag;
12486             gint16 nChannels;
12487             gint32 nSamplesPerSec;
12488             gint32 nAvgBytesPerSec;
12489             gint16 nBlockAlign;
12490             gint16 wBitsPerSample;
12491             gint16 cbSize;
12492           } WAVEFORMATEX;
12493           WAVEFORMATEX wfex;
12494
12495           /* FIXME: unify with similar wavformatex parsing code above */
12496           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12497
12498           /* find wfex */
12499           while (len >= 8) {
12500             gint size;
12501
12502             if (QT_UINT32 (wfex_data) <= len)
12503               size = QT_UINT32 (wfex_data) - 8;
12504             else
12505               size = len - 8;
12506
12507             if (size < 1)
12508               /* No real data, so break out */
12509               break;
12510
12511             switch (QT_FOURCC (wfex_data + 4)) {
12512               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12513               {
12514                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12515
12516                 if (size < 8 + 18)
12517                   break;
12518
12519                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12520                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12521                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12522                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12523                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12524                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12525                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12526
12527                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12528                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12529                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12530                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12531                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12532                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12533
12534                 if (wfex.wFormatTag == 0x0161) {
12535                   codec_name = "Windows Media Audio";
12536                   version = 2;
12537                 } else if (wfex.wFormatTag == 0x0162) {
12538                   codec_name = "Windows Media Audio 9 Pro";
12539                   version = 3;
12540                 } else if (wfex.wFormatTag == 0x0163) {
12541                   codec_name = "Windows Media Audio 9 Lossless";
12542                   /* is that correct? gstffmpegcodecmap.c is missing it, but
12543                    * fluendo codec seems to support it */
12544                   version = 4;
12545                 }
12546
12547                 gst_caps_set_simple (entry->caps,
12548                     "wmaversion", G_TYPE_INT, version,
12549                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
12550                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12551                     "width", G_TYPE_INT, wfex.wBitsPerSample,
12552                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12553
12554                 if (size > wfex.cbSize) {
12555                   GstBuffer *buf;
12556
12557                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12558                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12559                       size - wfex.cbSize);
12560                   gst_caps_set_simple (entry->caps,
12561                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12562                   gst_buffer_unref (buf);
12563                 } else {
12564                   GST_WARNING_OBJECT (qtdemux, "no codec data");
12565                 }
12566
12567                 if (codec_name) {
12568                   g_free (codec);
12569                   codec = g_strdup (codec_name);
12570                 }
12571                 break;
12572               }
12573               default:
12574                 break;
12575             }
12576             len -= size + 8;
12577             wfex_data += size + 8;
12578           }
12579           break;
12580         }
12581         case FOURCC_opus:
12582         {
12583           const guint8 *opus_data;
12584           guint8 *channel_mapping = NULL;
12585           guint32 rate;
12586           guint8 channels;
12587           guint8 channel_mapping_family;
12588           guint8 stream_count;
12589           guint8 coupled_count;
12590           guint8 i;
12591
12592           opus_data = stsd_entry_data;
12593
12594           channels = GST_READ_UINT8 (opus_data + 45);
12595           rate = GST_READ_UINT32_LE (opus_data + 48);
12596           channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12597           stream_count = GST_READ_UINT8 (opus_data + 55);
12598           coupled_count = GST_READ_UINT8 (opus_data + 56);
12599
12600           if (channels > 0) {
12601             channel_mapping = g_malloc (channels * sizeof (guint8));
12602             for (i = 0; i < channels; i++)
12603               channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12604           }
12605
12606           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12607               channel_mapping_family, stream_count, coupled_count,
12608               channel_mapping);
12609           break;
12610         }
12611         default:
12612           break;
12613       }
12614
12615       if (codec) {
12616         GstStructure *s;
12617         gint bitrate = 0;
12618
12619         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12620             GST_TAG_AUDIO_CODEC, codec, NULL);
12621         g_free (codec);
12622         codec = NULL;
12623
12624         /* some bitrate info may have ended up in caps */
12625         s = gst_caps_get_structure (entry->caps, 0);
12626         gst_structure_get_int (s, "bitrate", &bitrate);
12627         if (bitrate > 0)
12628           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12629               GST_TAG_BITRATE, bitrate, NULL);
12630       }
12631
12632       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12633       if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12634         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca)
12635           mp4a = NULL;
12636         else if (!stream->protected)
12637           mp4a = NULL;
12638       }
12639
12640       wave = NULL;
12641       esds = NULL;
12642       if (mp4a) {
12643         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12644         if (wave)
12645           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12646         if (!esds)
12647           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12648       }
12649
12650
12651       /* If the fourcc's bottom 16 bits gives 'sm', then the top
12652          16 bits is a byte-swapped wave-style codec identifier,
12653          and we can find a WAVE header internally to a 'wave' atom here.
12654          This can more clearly be thought of as 'ms' as the top 16 bits, and a
12655          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12656          is big-endian).
12657        */
12658       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12659         if (len < offset + 20) {
12660           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12661         } else {
12662           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12663           const guint8 *data = stsd_entry_data + offset + 16;
12664           GNode *wavenode;
12665           GNode *waveheadernode;
12666
12667           wavenode = g_node_new ((guint8 *) data);
12668           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12669             const guint8 *waveheader;
12670             guint32 headerlen;
12671
12672             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12673             if (waveheadernode) {
12674               waveheader = (const guint8 *) waveheadernode->data;
12675               headerlen = QT_UINT32 (waveheader);
12676
12677               if (headerlen > 8) {
12678                 gst_riff_strf_auds *header = NULL;
12679                 GstBuffer *headerbuf;
12680                 GstBuffer *extra;
12681
12682                 waveheader += 8;
12683                 headerlen -= 8;
12684
12685                 headerbuf = gst_buffer_new_and_alloc (headerlen);
12686                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12687
12688                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12689                         headerbuf, &header, &extra)) {
12690                   gst_caps_unref (entry->caps);
12691                   /* FIXME: Need to do something with the channel reorder map */
12692                   entry->caps =
12693                       gst_riff_create_audio_caps (header->format, NULL, header,
12694                       extra, NULL, NULL, NULL);
12695
12696                   if (extra)
12697                     gst_buffer_unref (extra);
12698                   g_free (header);
12699                 }
12700               }
12701             } else
12702               GST_DEBUG ("Didn't find waveheadernode for this codec");
12703           }
12704           g_node_destroy (wavenode);
12705         }
12706       } else if (esds) {
12707         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12708             stream->stream_tags);
12709       } else {
12710         switch (fourcc) {
12711 #if 0
12712             /* FIXME: what is in the chunk? */
12713           case FOURCC_QDMC:
12714           {
12715             gint len = QT_UINT32 (stsd_data);
12716
12717             /* seems to be always = 116 = 0x74 */
12718             break;
12719           }
12720 #endif
12721           case FOURCC_QDM2:
12722           {
12723             gint len = QT_UINT32 (stsd_entry_data);
12724
12725             if (len > 0x3C) {
12726               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12727
12728               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12729               gst_caps_set_simple (entry->caps,
12730                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12731               gst_buffer_unref (buf);
12732             }
12733             gst_caps_set_simple (entry->caps,
12734                 "samplesize", G_TYPE_INT, samplesize, NULL);
12735             break;
12736           }
12737           case FOURCC_alac:
12738           {
12739             GNode *alac, *wave = NULL;
12740
12741             /* apparently, m4a has this atom appended directly in the stsd entry,
12742              * while mov has it in a wave atom */
12743             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12744             if (alac) {
12745               /* alac now refers to stsd entry atom */
12746               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12747               if (wave)
12748                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12749               else
12750                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12751             }
12752             if (alac) {
12753               const guint8 *alac_data = alac->data;
12754               gint len = QT_UINT32 (alac->data);
12755               GstBuffer *buf;
12756
12757               if (len < 36) {
12758                 GST_DEBUG_OBJECT (qtdemux,
12759                     "discarding alac atom with unexpected len %d", len);
12760               } else {
12761                 /* codec-data contains alac atom size and prefix,
12762                  * ffmpeg likes it that way, not quite gst-ish though ...*/
12763                 buf = gst_buffer_new_and_alloc (len);
12764                 gst_buffer_fill (buf, 0, alac->data, len);
12765                 gst_caps_set_simple (entry->caps,
12766                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12767                 gst_buffer_unref (buf);
12768
12769                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12770                 entry->n_channels = QT_UINT8 (alac_data + 21);
12771                 entry->rate = QT_UINT32 (alac_data + 32);
12772               }
12773             }
12774             gst_caps_set_simple (entry->caps,
12775                 "samplesize", G_TYPE_INT, samplesize, NULL);
12776             break;
12777           }
12778           case FOURCC_fLaC:
12779           {
12780             /* The codingname of the sample entry is 'fLaC' */
12781             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12782
12783             if (flac) {
12784               /* The 'dfLa' box is added to the sample entry to convey
12785                  initializing information for the decoder. */
12786               const GNode *dfla =
12787                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12788
12789               if (dfla) {
12790                 const guint32 len = QT_UINT32 (dfla->data);
12791
12792                 /* Must contain at least dfLa box header (12),
12793                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12794                 if (len < 50) {
12795                   GST_DEBUG_OBJECT (qtdemux,
12796                       "discarding dfla atom with unexpected len %d", len);
12797                 } else {
12798                   /* skip dfLa header to get the METADATA_BLOCKs */
12799                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12800                   const guint32 metadata_blocks_len = len - 12;
12801
12802                   gchar *stream_marker = g_strdup ("fLaC");
12803                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12804                       strlen (stream_marker));
12805
12806                   guint32 index = 0;
12807                   guint32 remainder = 0;
12808                   guint32 block_size = 0;
12809                   gboolean is_last = FALSE;
12810
12811                   GValue array = G_VALUE_INIT;
12812                   GValue value = G_VALUE_INIT;
12813
12814                   g_value_init (&array, GST_TYPE_ARRAY);
12815                   g_value_init (&value, GST_TYPE_BUFFER);
12816
12817                   gst_value_set_buffer (&value, block);
12818                   gst_value_array_append_value (&array, &value);
12819                   g_value_reset (&value);
12820
12821                   gst_buffer_unref (block);
12822
12823                   /* check there's at least one METADATA_BLOCK_HEADER's worth
12824                    * of data, and we haven't already finished parsing */
12825                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
12826                     remainder = metadata_blocks_len - index;
12827
12828                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
12829                     block_size = 4 +
12830                         (metadata_blocks[index + 1] << 16) +
12831                         (metadata_blocks[index + 2] << 8) +
12832                         metadata_blocks[index + 3];
12833
12834                     /* be careful not to read off end of box */
12835                     if (block_size > remainder) {
12836                       break;
12837                     }
12838
12839                     is_last = metadata_blocks[index] >> 7;
12840
12841                     block = gst_buffer_new_and_alloc (block_size);
12842
12843                     gst_buffer_fill (block, 0, &metadata_blocks[index],
12844                         block_size);
12845
12846                     gst_value_set_buffer (&value, block);
12847                     gst_value_array_append_value (&array, &value);
12848                     g_value_reset (&value);
12849
12850                     gst_buffer_unref (block);
12851
12852                     index += block_size;
12853                   }
12854
12855                   /* only append the metadata if we successfully read all of it */
12856                   if (is_last) {
12857                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12858                             (stream)->caps, 0), "streamheader", &array);
12859                   } else {
12860                     GST_WARNING_OBJECT (qtdemux,
12861                         "discarding all METADATA_BLOCKs due to invalid "
12862                         "block_size %d at idx %d, rem %d", block_size, index,
12863                         remainder);
12864                   }
12865
12866                   g_value_unset (&value);
12867                   g_value_unset (&array);
12868
12869                   /* The sample rate obtained from the stsd may not be accurate
12870                    * since it cannot represent rates greater than 65535Hz, so
12871                    * override that value with the sample rate from the
12872                    * METADATA_BLOCK_STREAMINFO block */
12873                   CUR_STREAM (stream)->rate =
12874                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12875                 }
12876               }
12877             }
12878             break;
12879           }
12880           case FOURCC_sawb:
12881             /* Fallthrough! */
12882             amrwb = TRUE;
12883           case FOURCC_samr:
12884           {
12885             gint len = QT_UINT32 (stsd_entry_data);
12886
12887             if (len > 0x24) {
12888               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12889               guint bitrate;
12890
12891               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12892
12893               /* If we have enough data, let's try to get the 'damr' atom. See
12894                * the 3GPP container spec (26.244) for more details. */
12895               if ((len - 0x34) > 8 &&
12896                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12897                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12898                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12899               }
12900
12901               gst_caps_set_simple (entry->caps,
12902                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12903               gst_buffer_unref (buf);
12904             }
12905             break;
12906           }
12907           case FOURCC_mp4a:
12908           {
12909             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12910             gint len = QT_UINT32 (stsd_entry_data);
12911
12912             if (len >= 34) {
12913               guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12914
12915               if (sound_version == 1) {
12916                 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12917                 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12918                 guint8 codec_data[2];
12919                 GstBuffer *buf;
12920                 gint profile = 2;       /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12921
12922                 gint sample_rate_index =
12923                     gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12924
12925                 /* build AAC codec data */
12926                 codec_data[0] = profile << 3;
12927                 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12928                 codec_data[1] = (sample_rate_index & 0x01) << 7;
12929                 codec_data[1] |= (channels & 0xF) << 3;
12930
12931                 buf = gst_buffer_new_and_alloc (2);
12932                 gst_buffer_fill (buf, 0, codec_data, 2);
12933                 gst_caps_set_simple (entry->caps,
12934                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12935                 gst_buffer_unref (buf);
12936               }
12937             }
12938             break;
12939           }
12940           case FOURCC_lpcm:
12941             /* Fully handled elsewhere */
12942             break;
12943           default:
12944             GST_INFO_OBJECT (qtdemux,
12945                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12946             break;
12947         }
12948       }
12949       GST_INFO_OBJECT (qtdemux,
12950           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12951           GST_FOURCC_ARGS (fourcc), entry->caps);
12952
12953     } else if (stream->subtype == FOURCC_strm) {
12954       if (fourcc == FOURCC_rtsp) {
12955         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12956       } else {
12957         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12958             GST_FOURCC_ARGS (fourcc));
12959         goto unknown_stream;
12960       }
12961       entry->sampled = TRUE;
12962     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12963         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12964         || stream->subtype == FOURCC_clcp) {
12965
12966       entry->sampled = TRUE;
12967       entry->sparse = TRUE;
12968
12969       entry->caps =
12970           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12971           &codec);
12972       if (codec) {
12973         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12974             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12975         g_free (codec);
12976         codec = NULL;
12977       }
12978
12979       /* hunt for sort-of codec data */
12980       switch (fourcc) {
12981         case FOURCC_mp4s:
12982         {
12983           GNode *mp4s = NULL;
12984           GNode *esds = NULL;
12985
12986           /* look for palette in a stsd->mp4s->esds sub-atom */
12987           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12988           if (mp4s)
12989             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12990           if (esds == NULL) {
12991             /* Invalid STSD */
12992             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12993             break;
12994           }
12995
12996           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12997               stream->stream_tags);
12998           break;
12999         }
13000         default:
13001           GST_INFO_OBJECT (qtdemux,
13002               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13003           break;
13004       }
13005       GST_INFO_OBJECT (qtdemux,
13006           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13007           GST_FOURCC_ARGS (fourcc), entry->caps);
13008     } else {
13009       /* everything in 1 sample */
13010       entry->sampled = TRUE;
13011
13012       entry->caps =
13013           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13014           &codec);
13015
13016       if (entry->caps == NULL)
13017         goto unknown_stream;
13018
13019       if (codec) {
13020         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13021             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13022         g_free (codec);
13023         codec = NULL;
13024       }
13025     }
13026
13027     /* promote to sampled format */
13028     if (entry->fourcc == FOURCC_samr) {
13029       /* force mono 8000 Hz for AMR */
13030       entry->sampled = TRUE;
13031       entry->n_channels = 1;
13032       entry->rate = 8000;
13033     } else if (entry->fourcc == FOURCC_sawb) {
13034       /* force mono 16000 Hz for AMR-WB */
13035       entry->sampled = TRUE;
13036       entry->n_channels = 1;
13037       entry->rate = 16000;
13038     } else if (entry->fourcc == FOURCC_mp4a) {
13039       entry->sampled = TRUE;
13040     }
13041
13042
13043     stsd_entry_data += len;
13044     remaining_stsd_len -= len;
13045
13046   }
13047
13048   /* collect sample information */
13049   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13050     goto samples_failed;
13051
13052   if (qtdemux->fragmented) {
13053     guint64 offset;
13054
13055     /* need all moov samples as basis; probably not many if any at all */
13056     /* prevent moof parsing taking of at this time */
13057     offset = qtdemux->moof_offset;
13058     qtdemux->moof_offset = 0;
13059     if (stream->n_samples &&
13060         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13061       qtdemux->moof_offset = offset;
13062       goto samples_failed;
13063     }
13064     qtdemux->moof_offset = 0;
13065     /* movie duration more reliable in this case (e.g. mehd) */
13066     if (qtdemux->segment.duration &&
13067         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13068       stream->duration =
13069           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13070   }
13071
13072   /* configure segments */
13073   if (!qtdemux_parse_segments (qtdemux, stream, trak))
13074     goto segments_failed;
13075
13076   /* add some language tag, if useful */
13077   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13078       strcmp (stream->lang_id, "und")) {
13079     const gchar *lang_code;
13080
13081     /* convert ISO 639-2 code to ISO 639-1 */
13082     lang_code = gst_tag_get_language_code (stream->lang_id);
13083     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13084         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13085   }
13086
13087   /* Check for UDTA tags */
13088   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13089     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13090   }
13091
13092   /* Insert and sort new stream in track-id order.
13093    * This will help in comparing old/new streams during stream update check */
13094   g_ptr_array_add (qtdemux->active_streams, stream);
13095   g_ptr_array_sort (qtdemux->active_streams,
13096       (GCompareFunc) qtdemux_track_id_compare_func);
13097   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13098       QTDEMUX_N_STREAMS (qtdemux));
13099
13100   return TRUE;
13101
13102 /* ERRORS */
13103 corrupt_file:
13104   {
13105     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13106         (_("This file is corrupt and cannot be played.")), (NULL));
13107     if (stream)
13108       gst_qtdemux_stream_unref (stream);
13109     return FALSE;
13110   }
13111 error_encrypted:
13112   {
13113     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13114     gst_qtdemux_stream_unref (stream);
13115     return FALSE;
13116   }
13117 samples_failed:
13118 segments_failed:
13119   {
13120     /* we posted an error already */
13121     /* free stbl sub-atoms */
13122     gst_qtdemux_stbl_free (stream);
13123     gst_qtdemux_stream_unref (stream);
13124     return FALSE;
13125   }
13126 existing_stream:
13127   {
13128     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13129         track_id);
13130     return TRUE;
13131   }
13132 unknown_stream:
13133   {
13134     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13135         GST_FOURCC_ARGS (stream->subtype));
13136     gst_qtdemux_stream_unref (stream);
13137     return TRUE;
13138   }
13139 }
13140
13141 /* If we can estimate the overall bitrate, and don't have information about the
13142  * stream bitrate for exactly one stream, this guesses the stream bitrate as
13143  * the overall bitrate minus the sum of the bitrates of all other streams. This
13144  * should be useful for the common case where we have one audio and one video
13145  * stream and can estimate the bitrate of one, but not the other. */
13146 static void
13147 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13148 {
13149   QtDemuxStream *stream = NULL;
13150   gint64 size, sys_bitrate, sum_bitrate = 0;
13151   GstClockTime duration;
13152   guint bitrate;
13153   gint i;
13154
13155   if (qtdemux->fragmented)
13156     return;
13157
13158   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13159
13160   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13161       || size <= 0) {
13162     GST_DEBUG_OBJECT (qtdemux,
13163         "Size in bytes of the stream not known - bailing");
13164     return;
13165   }
13166
13167   /* Subtract the header size */
13168   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13169       size, qtdemux->header_size);
13170
13171   if (size < qtdemux->header_size)
13172     return;
13173
13174   size = size - qtdemux->header_size;
13175
13176   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13177     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13178     return;
13179   }
13180
13181   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13182     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13183     switch (str->subtype) {
13184       case FOURCC_soun:
13185       case FOURCC_vide:
13186         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13187             CUR_STREAM (str)->caps);
13188         /* retrieve bitrate, prefer avg then max */
13189         bitrate = 0;
13190         if (str->stream_tags) {
13191           if (gst_tag_list_get_uint (str->stream_tags,
13192                   GST_TAG_MAXIMUM_BITRATE, &bitrate))
13193             GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13194           if (gst_tag_list_get_uint (str->stream_tags,
13195                   GST_TAG_NOMINAL_BITRATE, &bitrate))
13196             GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13197           if (gst_tag_list_get_uint (str->stream_tags,
13198                   GST_TAG_BITRATE, &bitrate))
13199             GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13200         }
13201         if (bitrate)
13202           sum_bitrate += bitrate;
13203         else {
13204           if (stream) {
13205             GST_DEBUG_OBJECT (qtdemux,
13206                 ">1 stream with unknown bitrate - bailing");
13207             return;
13208           } else
13209             stream = str;
13210         }
13211
13212       default:
13213         /* For other subtypes, we assume no significant impact on bitrate */
13214         break;
13215     }
13216   }
13217
13218   if (!stream) {
13219     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13220     return;
13221   }
13222
13223   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13224
13225   if (sys_bitrate < sum_bitrate) {
13226     /* This can happen, since sum_bitrate might be derived from maximum
13227      * bitrates and not average bitrates */
13228     GST_DEBUG_OBJECT (qtdemux,
13229         "System bitrate less than sum bitrate - bailing");
13230     return;
13231   }
13232
13233   bitrate = sys_bitrate - sum_bitrate;
13234   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13235       ", Stream bitrate = %u", sys_bitrate, bitrate);
13236
13237   if (!stream->stream_tags)
13238     stream->stream_tags = gst_tag_list_new_empty ();
13239   else
13240     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13241
13242   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13243       GST_TAG_BITRATE, bitrate, NULL);
13244 }
13245
13246 static GstFlowReturn
13247 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13248 {
13249   GstFlowReturn ret = GST_FLOW_OK;
13250   gint i;
13251
13252   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
13253
13254   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13255     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13256     guint32 sample_num = 0;
13257
13258     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13259         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13260
13261     if (qtdemux->fragmented) {
13262       /* need all moov samples first */
13263       GST_OBJECT_LOCK (qtdemux);
13264       while (stream->n_samples == 0)
13265         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13266           break;
13267       GST_OBJECT_UNLOCK (qtdemux);
13268     } else {
13269       /* discard any stray moof */
13270       qtdemux->moof_offset = 0;
13271     }
13272
13273     /* prepare braking */
13274     if (ret != GST_FLOW_ERROR)
13275       ret = GST_FLOW_OK;
13276
13277     /* in pull mode, we should have parsed some sample info by now;
13278      * and quite some code will not handle no samples.
13279      * in push mode, we'll just have to deal with it */
13280     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13281       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13282       g_ptr_array_remove_index (qtdemux->active_streams, i);
13283       i--;
13284       continue;
13285     } else if (stream->track_id == qtdemux->chapters_track_id &&
13286         (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13287       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13288          so that it doesn't look like a subtitle track */
13289       g_ptr_array_remove_index (qtdemux->active_streams, i);
13290       i--;
13291       continue;
13292     }
13293
13294     /* parse the initial sample for use in setting the frame rate cap */
13295     while (sample_num == 0 && sample_num < stream->n_samples) {
13296       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13297         break;
13298       ++sample_num;
13299     }
13300   }
13301
13302   return ret;
13303 }
13304
13305 static gboolean
13306 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13307 {
13308   return g_strcmp0 (stream->stream_id, stream_id) == 0;
13309 }
13310
13311 static gboolean
13312 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13313 {
13314   gint i;
13315
13316   /* Different length, updated */
13317   if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13318     return TRUE;
13319
13320   /* streams in list are sorted in track-id order */
13321   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13322     /* Different stream-id, updated */
13323     if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13324             QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13325       return TRUE;
13326   }
13327
13328   return FALSE;
13329 }
13330
13331 static gboolean
13332 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13333     QtDemuxStream * oldstream, QtDemuxStream * newstream)
13334 {
13335   /* Connect old stream's srcpad to new stream */
13336   newstream->pad = oldstream->pad;
13337   oldstream->pad = NULL;
13338
13339   /* unset new_stream to prevent stream-start event */
13340   newstream->new_stream = FALSE;
13341
13342   return gst_qtdemux_configure_stream (qtdemux, newstream);
13343 }
13344
13345 /* g_ptr_array_find_with_equal_func is available since 2.54,
13346  * replacement until we can depend unconditionally on the real one in GLib */
13347 #if !GLIB_CHECK_VERSION(2,54,0)
13348 #define g_ptr_array_find_with_equal_func qtdemux_ptr_array_find_with_equal_func
13349 static gboolean
13350 qtdemux_ptr_array_find_with_equal_func (GPtrArray * haystack,
13351     gconstpointer needle, GEqualFunc equal_func, guint * index_)
13352 {
13353   guint i;
13354
13355   g_return_val_if_fail (haystack != NULL, FALSE);
13356
13357   if (equal_func == NULL)
13358     equal_func = g_direct_equal;
13359
13360   for (i = 0; i < haystack->len; i++) {
13361     if (equal_func (g_ptr_array_index (haystack, i), needle)) {
13362       if (index_ != NULL)
13363         *index_ = i;
13364       return TRUE;
13365     }
13366   }
13367
13368   return FALSE;
13369 }
13370 #endif
13371
13372 static gboolean
13373 qtdemux_update_streams (GstQTDemux * qtdemux)
13374 {
13375   gint i;
13376   g_assert (qtdemux->streams_aware);
13377
13378   /* At below, figure out which stream in active_streams has identical stream-id
13379    * with that of in old_streams. If there is matching stream-id,
13380    * corresponding newstream will not be exposed again,
13381    * but demux will reuse srcpad of matched old stream
13382    *
13383    * active_streams : newly created streams from the latest moov
13384    * old_streams : existing streams (belong to previous moov)
13385    */
13386
13387   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13388     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13389     QtDemuxStream *oldstream = NULL;
13390     guint target;
13391
13392     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13393         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13394
13395     if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13396             stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13397       oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13398
13399       /* null pad stream cannot be reused */
13400       if (oldstream->pad == NULL)
13401         oldstream = NULL;
13402     }
13403
13404     if (oldstream) {
13405       GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13406
13407       if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13408         return FALSE;
13409
13410       /* we don't need to preserve order of old streams */
13411       g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13412     } else {
13413       GstTagList *list;
13414
13415       /* now we have all info and can expose */
13416       list = stream->stream_tags;
13417       stream->stream_tags = NULL;
13418       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13419         return FALSE;
13420     }
13421   }
13422
13423   return TRUE;
13424 }
13425
13426 /* Must be called with expose lock */
13427 static GstFlowReturn
13428 qtdemux_expose_streams (GstQTDemux * qtdemux)
13429 {
13430   gint i;
13431
13432   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13433
13434   if (!qtdemux_is_streams_update (qtdemux)) {
13435     GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13436     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13437       QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13438       QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13439       if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13440         return GST_FLOW_ERROR;
13441     }
13442
13443     g_ptr_array_set_size (qtdemux->old_streams, 0);
13444     qtdemux->need_segment = TRUE;
13445
13446     return GST_FLOW_OK;
13447   }
13448
13449   if (qtdemux->streams_aware) {
13450     if (!qtdemux_update_streams (qtdemux))
13451       return GST_FLOW_ERROR;
13452   } else {
13453     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13454       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13455       GstTagList *list;
13456
13457       /* now we have all info and can expose */
13458       list = stream->stream_tags;
13459       stream->stream_tags = NULL;
13460       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13461         return GST_FLOW_ERROR;
13462
13463     }
13464   }
13465
13466   gst_qtdemux_guess_bitrate (qtdemux);
13467
13468   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13469
13470   /* If we have still old_streams, it's no more used stream */
13471   for (i = 0; i < qtdemux->old_streams->len; i++) {
13472     QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13473
13474     if (stream->pad) {
13475       GstEvent *event;
13476
13477       event = gst_event_new_eos ();
13478       if (qtdemux->segment_seqnum)
13479         gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13480
13481       gst_pad_push_event (stream->pad, event);
13482     }
13483   }
13484
13485   g_ptr_array_set_size (qtdemux->old_streams, 0);
13486
13487   /* check if we should post a redirect in case there is a single trak
13488    * and it is a redirecting trak */
13489   if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13490       QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13491     GstMessage *m;
13492
13493     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13494         "an external content");
13495     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13496         gst_structure_new ("redirect",
13497             "new-location", G_TYPE_STRING,
13498             QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13499     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13500     qtdemux->posted_redirect = TRUE;
13501   }
13502
13503   g_ptr_array_foreach (qtdemux->active_streams,
13504       (GFunc) qtdemux_do_allocation, qtdemux);
13505
13506   qtdemux->need_segment = TRUE;
13507
13508   qtdemux->exposed = TRUE;
13509   return GST_FLOW_OK;
13510 }
13511
13512 /* check if major or compatible brand is 3GP */
13513 static inline gboolean
13514 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
13515 {
13516   if (major) {
13517     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
13518         FOURCC_3g__);
13519   } else if (qtdemux->comp_brands != NULL) {
13520     GstMapInfo map;
13521     guint8 *data;
13522     gsize size;
13523     gboolean res = FALSE;
13524
13525     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
13526     data = map.data;
13527     size = map.size;
13528     while (size >= 4) {
13529       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
13530           FOURCC_3g__);
13531       data += 4;
13532       size -= 4;
13533     }
13534     gst_buffer_unmap (qtdemux->comp_brands, &map);
13535     return res;
13536   } else {
13537     return FALSE;
13538   }
13539 }
13540
13541 /* check if tag is a spec'ed 3GP tag keyword storing a string */
13542 static inline gboolean
13543 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
13544 {
13545   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
13546       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
13547       || fourcc == FOURCC_albm;
13548 }
13549
13550 static void
13551 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
13552     const char *tag, const char *dummy, GNode * node)
13553 {
13554   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13555   int offset;
13556   char *name;
13557   gchar *data;
13558   gdouble longitude, latitude, altitude;
13559   gint len;
13560
13561   len = QT_UINT32 (node->data);
13562   if (len <= 14)
13563     goto short_read;
13564
13565   data = node->data;
13566   offset = 14;
13567
13568   /* TODO: language code skipped */
13569
13570   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
13571
13572   if (!name) {
13573     /* do not alarm in trivial case, but bail out otherwise */
13574     if (*(data + offset) != 0) {
13575       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
13576           "giving up", tag);
13577     }
13578   } else {
13579     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
13580         GST_TAG_GEO_LOCATION_NAME, name, NULL);
13581     offset += strlen (name);
13582     g_free (name);
13583   }
13584
13585   if (len < offset + 2 + 4 + 4 + 4)
13586     goto short_read;
13587
13588   /* +1 +1 = skip null-terminator and location role byte */
13589   offset += 1 + 1;
13590   /* table in spec says unsigned, semantics say negative has meaning ... */
13591   longitude = QT_SFP32 (data + offset);
13592
13593   offset += 4;
13594   latitude = QT_SFP32 (data + offset);
13595
13596   offset += 4;
13597   altitude = QT_SFP32 (data + offset);
13598
13599   /* one invalid means all are invalid */
13600   if (longitude >= -180.0 && longitude <= 180.0 &&
13601       latitude >= -90.0 && latitude <= 90.0) {
13602     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
13603         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
13604         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
13605         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
13606   }
13607
13608   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
13609
13610   return;
13611
13612   /* ERRORS */
13613 short_read:
13614   {
13615     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
13616     return;
13617   }
13618 }
13619
13620
13621 static void
13622 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
13623     const char *tag, const char *dummy, GNode * node)
13624 {
13625   guint16 y;
13626   GDate *date;
13627   gint len;
13628
13629   len = QT_UINT32 (node->data);
13630   if (len < 14)
13631     return;
13632
13633   y = QT_UINT16 ((guint8 *) node->data + 12);
13634   if (y == 0) {
13635     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
13636     return;
13637   }
13638   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
13639
13640   date = g_date_new_dmy (1, 1, y);
13641   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13642   g_date_free (date);
13643 }
13644
13645 static void
13646 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
13647     const char *tag, const char *dummy, GNode * node)
13648 {
13649   int offset;
13650   char *tag_str = NULL;
13651   guint8 *entity;
13652   guint16 table;
13653   gint len;
13654
13655   len = QT_UINT32 (node->data);
13656   if (len <= 20)
13657     goto short_read;
13658
13659   offset = 12;
13660   entity = (guint8 *) node->data + offset;
13661   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
13662     GST_DEBUG_OBJECT (qtdemux,
13663         "classification info: %c%c%c%c invalid classification entity",
13664         entity[0], entity[1], entity[2], entity[3]);
13665     return;
13666   }
13667
13668   offset += 4;
13669   table = QT_UINT16 ((guint8 *) node->data + offset);
13670
13671   /* Language code skipped */
13672
13673   offset += 4;
13674
13675   /* Tag format: "XXXX://Y[YYYY]/classification info string"
13676    * XXXX: classification entity, fixed length 4 chars.
13677    * Y[YYYY]: classification table, max 5 chars.
13678    */
13679   tag_str = g_strdup_printf ("----://%u/%s",
13680       table, (char *) node->data + offset);
13681
13682   /* memcpy To be sure we're preserving byte order */
13683   memcpy (tag_str, entity, 4);
13684   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
13685
13686   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
13687
13688   g_free (tag_str);
13689
13690   return;
13691
13692   /* ERRORS */
13693 short_read:
13694   {
13695     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
13696     return;
13697   }
13698 }
13699
13700 static gboolean
13701 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
13702     const char *tag, const char *dummy, GNode * node)
13703 {
13704   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13705   GNode *data;
13706   char *s;
13707   int len;
13708   guint32 type;
13709   int offset;
13710   gboolean ret = TRUE;
13711   const gchar *charset = NULL;
13712
13713   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13714   if (data) {
13715     len = QT_UINT32 (data->data);
13716     type = QT_UINT32 ((guint8 *) data->data + 8);
13717     if (type == 0x00000001 && len > 16) {
13718       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
13719           env_vars);
13720       if (s) {
13721         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13722         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13723         g_free (s);
13724       } else {
13725         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13726       }
13727     }
13728   } else {
13729     len = QT_UINT32 (node->data);
13730     type = QT_UINT32 ((guint8 *) node->data + 4);
13731     if ((type >> 24) == 0xa9 && len > 8 + 4) {
13732       gint str_len;
13733       gint lang_code;
13734
13735       /* Type starts with the (C) symbol, so the next data is a list
13736        * of (string size(16), language code(16), string) */
13737
13738       str_len = QT_UINT16 ((guint8 *) node->data + 8);
13739       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
13740
13741       /* the string + fourcc + size + 2 16bit fields,
13742        * means that there are more tags in this atom */
13743       if (len > str_len + 8 + 4) {
13744         /* TODO how to represent the same tag in different languages? */
13745         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
13746             "text alternatives, reading only first one");
13747       }
13748
13749       offset = 12;
13750       len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
13751       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
13752
13753       if (lang_code < 0x800) {  /* MAC encoded string */
13754         charset = "mac";
13755       }
13756     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
13757             QT_FOURCC ((guint8 *) node->data + 4))) {
13758       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
13759
13760       /* we go for 3GP style encoding if major brands claims so,
13761        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
13762       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13763           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
13764               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
13765         offset = 14;
13766         /* 16-bit Language code is ignored here as well */
13767         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
13768       } else {
13769         goto normal;
13770       }
13771     } else {
13772     normal:
13773       offset = 8;
13774       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
13775       ret = FALSE;              /* may have to fallback */
13776     }
13777     if (charset) {
13778       GError *err = NULL;
13779
13780       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
13781           charset, NULL, NULL, &err);
13782       if (err) {
13783         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
13784             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
13785             err->message);
13786         g_error_free (err);
13787       }
13788     } else {
13789       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13790           len - offset, env_vars);
13791     }
13792     if (s) {
13793       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13794       gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13795       g_free (s);
13796       ret = TRUE;
13797     } else {
13798       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13799     }
13800   }
13801   return ret;
13802 }
13803
13804 static void
13805 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
13806     const char *tag, const char *dummy, GNode * node)
13807 {
13808   qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
13809 }
13810
13811 static void
13812 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
13813     const char *tag, const char *dummy, GNode * node)
13814 {
13815   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13816   guint8 *data;
13817   char *s, *t, *k = NULL;
13818   int len;
13819   int offset;
13820   int count;
13821
13822   /* first try normal string tag if major brand not 3GP */
13823   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
13824     if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
13825       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
13826        * let's try it 3gpp way after minor safety check */
13827       data = node->data;
13828       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
13829         return;
13830     } else
13831       return;
13832   }
13833
13834   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
13835
13836   data = node->data;
13837
13838   len = QT_UINT32 (data);
13839   if (len < 15)
13840     goto short_read;
13841
13842   count = QT_UINT8 (data + 14);
13843   offset = 15;
13844   for (; count; count--) {
13845     gint slen;
13846
13847     if (offset + 1 > len)
13848       goto short_read;
13849     slen = QT_UINT8 (data + offset);
13850     offset += 1;
13851     if (offset + slen > len)
13852       goto short_read;
13853     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13854         slen, env_vars);
13855     if (s) {
13856       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
13857       if (k) {
13858         t = g_strjoin (",", k, s, NULL);
13859         g_free (s);
13860         g_free (k);
13861         k = t;
13862       } else {
13863         k = s;
13864       }
13865     } else {
13866       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
13867     }
13868     offset += slen;
13869   }
13870
13871 done:
13872   if (k) {
13873     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
13874     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
13875   }
13876   g_free (k);
13877
13878   return;
13879
13880   /* ERRORS */
13881 short_read:
13882   {
13883     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
13884     goto done;
13885   }
13886 }
13887
13888 static void
13889 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
13890     const char *tag1, const char *tag2, GNode * node)
13891 {
13892   GNode *data;
13893   int len;
13894   int type;
13895   int n1, n2;
13896
13897   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13898   if (data) {
13899     len = QT_UINT32 (data->data);
13900     type = QT_UINT32 ((guint8 *) data->data + 8);
13901     if (type == 0x00000000 && len >= 22) {
13902       n1 = QT_UINT16 ((guint8 *) data->data + 18);
13903       n2 = QT_UINT16 ((guint8 *) data->data + 20);
13904       if (n1 > 0) {
13905         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
13906         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
13907       }
13908       if (n2 > 0) {
13909         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
13910         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
13911       }
13912     }
13913   }
13914 }
13915
13916 static void
13917 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
13918     const char *tag1, const char *dummy, GNode * node)
13919 {
13920   GNode *data;
13921   int len;
13922   int type;
13923   int n1;
13924
13925   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13926   if (data) {
13927     len = QT_UINT32 (data->data);
13928     type = QT_UINT32 ((guint8 *) data->data + 8);
13929     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
13930     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13931     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
13932       n1 = QT_UINT16 ((guint8 *) data->data + 16);
13933       if (n1) {
13934         /* do not add bpm=0 */
13935         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
13936         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13937             NULL);
13938       }
13939     }
13940   }
13941 }
13942
13943 static void
13944 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13945     const char *tag1, const char *dummy, GNode * node)
13946 {
13947   GNode *data;
13948   int len;
13949   int type;
13950   guint32 num;
13951
13952   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13953   if (data) {
13954     len = QT_UINT32 (data->data);
13955     type = QT_UINT32 ((guint8 *) data->data + 8);
13956     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
13957     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13958     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
13959       num = QT_UINT32 ((guint8 *) data->data + 16);
13960       if (num) {
13961         /* do not add num=0 */
13962         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
13963         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
13964       }
13965     }
13966   }
13967 }
13968
13969 static void
13970 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
13971     const char *tag1, const char *dummy, GNode * node)
13972 {
13973   GNode *data;
13974   int len;
13975   int type;
13976   GstSample *sample;
13977
13978   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13979   if (data) {
13980     len = QT_UINT32 (data->data);
13981     type = QT_UINT32 ((guint8 *) data->data + 8);
13982     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
13983     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
13984       GstTagImageType image_type;
13985
13986       if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
13987         image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
13988       else
13989         image_type = GST_TAG_IMAGE_TYPE_NONE;
13990
13991       if ((sample =
13992               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
13993                   len - 16, image_type))) {
13994         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
13995         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
13996         gst_sample_unref (sample);
13997       }
13998     }
13999   }
14000 }
14001
14002 static void
14003 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
14004     const char *tag, const char *dummy, GNode * node)
14005 {
14006   GNode *data;
14007   GstDateTime *datetime = NULL;
14008   char *s;
14009   int len;
14010   int type;
14011
14012   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14013   if (data) {
14014     len = QT_UINT32 (data->data);
14015     type = QT_UINT32 ((guint8 *) data->data + 8);
14016     if (type == 0x00000001 && len > 16) {
14017       guint y, m = 1, d = 1;
14018       gint ret;
14019
14020       s = g_strndup ((char *) data->data + 16, len - 16);
14021       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
14022       datetime = gst_date_time_new_from_iso8601_string (s);
14023       if (datetime != NULL) {
14024         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
14025             datetime, NULL);
14026         gst_date_time_unref (datetime);
14027       }
14028
14029       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
14030       if (ret >= 1 && y > 1500 && y < 3000) {
14031         GDate *date;
14032
14033         date = g_date_new_dmy (d, m, y);
14034         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
14035         g_date_free (date);
14036       } else {
14037         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
14038       }
14039       g_free (s);
14040     }
14041   }
14042 }
14043
14044 static void
14045 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
14046     const char *tag, const char *dummy, GNode * node)
14047 {
14048   GNode *data;
14049
14050   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14051
14052   /* re-route to normal string tag if major brand says so
14053    * or no data atom and compatible brand suggests so */
14054   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
14055       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
14056     qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
14057     return;
14058   }
14059
14060   if (data) {
14061     guint len, type, n;
14062
14063     len = QT_UINT32 (data->data);
14064     type = QT_UINT32 ((guint8 *) data->data + 8);
14065     if (type == 0x00000000 && len >= 18) {
14066       n = QT_UINT16 ((guint8 *) data->data + 16);
14067       if (n > 0) {
14068         const gchar *genre;
14069
14070         genre = gst_tag_id3_genre_get (n - 1);
14071         if (genre != NULL) {
14072           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
14073           gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
14074         }
14075       }
14076     }
14077   }
14078 }
14079
14080 static void
14081 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
14082     const gchar * tag, guint8 * data, guint32 datasize)
14083 {
14084   gdouble value;
14085   gchar *datacopy;
14086
14087   /* make a copy to have \0 at the end */
14088   datacopy = g_strndup ((gchar *) data, datasize);
14089
14090   /* convert the str to double */
14091   if (sscanf (datacopy, "%lf", &value) == 1) {
14092     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
14093     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
14094   } else {
14095     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
14096         datacopy);
14097   }
14098   g_free (datacopy);
14099 }
14100
14101
14102 static void
14103 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
14104     const char *tag, const char *tag_bis, GNode * node)
14105 {
14106   GNode *mean;
14107   GNode *name;
14108   GNode *data;
14109   guint32 meansize;
14110   guint32 namesize;
14111   guint32 datatype;
14112   guint32 datasize;
14113   const gchar *meanstr;
14114   const gchar *namestr;
14115
14116   /* checking the whole ---- atom size for consistency */
14117   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
14118     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
14119     return;
14120   }
14121
14122   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
14123   if (!mean) {
14124     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
14125     return;
14126   }
14127
14128   meansize = QT_UINT32 (mean->data);
14129   if (meansize <= 12) {
14130     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
14131     return;
14132   }
14133   meanstr = ((gchar *) mean->data) + 12;
14134   meansize -= 12;
14135
14136   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
14137   if (!name) {
14138     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
14139     return;
14140   }
14141
14142   namesize = QT_UINT32 (name->data);
14143   if (namesize <= 12) {
14144     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
14145     return;
14146   }
14147   namestr = ((gchar *) name->data) + 12;
14148   namesize -= 12;
14149
14150   /*
14151    * Data atom is:
14152    * uint32 - size
14153    * uint32 - name
14154    * uint8  - version
14155    * uint24 - data type
14156    * uint32 - all 0
14157    * rest   - the data
14158    */
14159   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14160   if (!data) {
14161     GST_WARNING_OBJECT (demux, "No data atom in this tag");
14162     return;
14163   }
14164   datasize = QT_UINT32 (data->data);
14165   if (datasize <= 16) {
14166     GST_WARNING_OBJECT (demux, "Data atom too small");
14167     return;
14168   }
14169   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
14170
14171   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
14172       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
14173     static const struct
14174     {
14175       const gchar name[28];
14176       const gchar tag[28];
14177     } tags[] = {
14178       {
14179       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
14180       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
14181       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
14182       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
14183       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
14184       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
14185       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
14186       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
14187     };
14188     int i;
14189
14190     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
14191       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
14192         switch (gst_tag_get_type (tags[i].tag)) {
14193           case G_TYPE_DOUBLE:
14194             qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
14195                 ((guint8 *) data->data) + 16, datasize - 16);
14196             break;
14197           case G_TYPE_STRING:
14198             qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
14199             break;
14200           default:
14201             /* not reached */
14202             break;
14203         }
14204         break;
14205       }
14206     }
14207     if (i == G_N_ELEMENTS (tags))
14208       goto unknown_tag;
14209   } else {
14210     goto unknown_tag;
14211   }
14212
14213   return;
14214
14215 /* errors */
14216 unknown_tag:
14217 #ifndef GST_DISABLE_GST_DEBUG
14218   {
14219     gchar *namestr_dbg;
14220     gchar *meanstr_dbg;
14221
14222     meanstr_dbg = g_strndup (meanstr, meansize);
14223     namestr_dbg = g_strndup (namestr, namesize);
14224
14225     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
14226         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
14227
14228     g_free (namestr_dbg);
14229     g_free (meanstr_dbg);
14230   }
14231 #endif
14232   return;
14233 }
14234
14235 static void
14236 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
14237     const char *tag_bis, GNode * node)
14238 {
14239   guint8 *data;
14240   GstBuffer *buf;
14241   guint len;
14242   GstTagList *id32_taglist = NULL;
14243
14244   GST_LOG_OBJECT (demux, "parsing ID32");
14245
14246   data = node->data;
14247   len = GST_READ_UINT32_BE (data);
14248
14249   /* need at least full box and language tag */
14250   if (len < 12 + 2)
14251     return;
14252
14253   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
14254   gst_buffer_fill (buf, 0, data + 14, len - 14);
14255
14256   id32_taglist = gst_tag_list_from_id3v2_tag (buf);
14257   if (id32_taglist) {
14258     GST_LOG_OBJECT (demux, "parsing ok");
14259     gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
14260     gst_tag_list_unref (id32_taglist);
14261   } else {
14262     GST_LOG_OBJECT (demux, "parsing failed");
14263   }
14264
14265   gst_buffer_unref (buf);
14266 }
14267
14268 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
14269     const char *tag, const char *tag_bis, GNode * node);
14270
14271 /* unmapped tags
14272 FOURCC_pcst -> if media is a podcast -> bool
14273 FOURCC_cpil -> if media is part of a compilation -> bool
14274 FOURCC_pgap -> if media is part of a gapless context -> bool
14275 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
14276 */
14277
14278 static const struct
14279 {
14280   guint32 fourcc;
14281   const gchar *gst_tag;
14282   const gchar *gst_tag_bis;
14283   const GstQTDemuxAddTagFunc func;
14284 } add_funcs[] = {
14285   {
14286   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
14287   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
14288   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
14289   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
14290   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
14291   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
14292   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
14293   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
14294   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
14295   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
14296   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
14297   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
14298   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
14299   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14300   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14301   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14302   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
14303   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
14304   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
14305   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
14306   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
14307   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
14308   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
14309         qtdemux_tag_add_num}, {
14310   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
14311         qtdemux_tag_add_num}, {
14312   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
14313   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
14314   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
14315   FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
14316   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
14317   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
14318   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
14319   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
14320   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
14321   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
14322   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
14323   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
14324   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
14325   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
14326   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
14327   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
14328   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
14329   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
14330         qtdemux_tag_add_classification}, {
14331   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
14332   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
14333   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
14334
14335     /* This is a special case, some tags are stored in this
14336      * 'reverse dns naming', according to:
14337      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
14338      * bug #614471
14339      */
14340   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
14341     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
14342   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
14343 };
14344
14345 struct _GstQtDemuxTagList
14346 {
14347   GstQTDemux *demux;
14348   GstTagList *taglist;
14349 };
14350 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
14351
14352 static void
14353 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
14354 {
14355   gint len;
14356   guint8 *data;
14357   GstBuffer *buf;
14358   gchar *media_type;
14359   const gchar *style;
14360   GstSample *sample;
14361   GstStructure *s;
14362   guint i;
14363   guint8 ndata[4];
14364   GstQTDemux *demux = qtdemuxtaglist->demux;
14365   GstTagList *taglist = qtdemuxtaglist->taglist;
14366
14367   data = node->data;
14368   len = QT_UINT32 (data);
14369   buf = gst_buffer_new_and_alloc (len);
14370   gst_buffer_fill (buf, 0, data, len);
14371
14372   /* heuristic to determine style of tag */
14373   if (QT_FOURCC (data + 4) == FOURCC_____ ||
14374       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
14375     style = "itunes";
14376   else if (demux->major_brand == FOURCC_qt__)
14377     style = "quicktime";
14378   /* fall back to assuming iso/3gp tag style */
14379   else
14380     style = "iso";
14381
14382   /* santize the name for the caps. */
14383   for (i = 0; i < 4; i++) {
14384     guint8 d = data[4 + i];
14385     if (g_ascii_isalnum (d))
14386       ndata[i] = g_ascii_tolower (d);
14387     else
14388       ndata[i] = '_';
14389   }
14390
14391   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
14392       ndata[0], ndata[1], ndata[2], ndata[3]);
14393   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
14394
14395   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
14396   sample = gst_sample_new (buf, NULL, NULL, s);
14397   gst_buffer_unref (buf);
14398   g_free (media_type);
14399
14400   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
14401       len, s);
14402
14403   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
14404       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
14405
14406   gst_sample_unref (sample);
14407 }
14408
14409 static void
14410 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
14411 {
14412   GNode *meta;
14413   GNode *ilst;
14414   GNode *xmp_;
14415   GNode *node;
14416   gint i;
14417   GstQtDemuxTagList demuxtaglist;
14418
14419   demuxtaglist.demux = qtdemux;
14420   demuxtaglist.taglist = taglist;
14421
14422   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
14423   if (meta != NULL) {
14424     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
14425     if (ilst == NULL) {
14426       GST_LOG_OBJECT (qtdemux, "no ilst");
14427       return;
14428     }
14429   } else {
14430     ilst = udta;
14431     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
14432   }
14433
14434   i = 0;
14435   while (i < G_N_ELEMENTS (add_funcs)) {
14436     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
14437     if (node) {
14438       gint len;
14439
14440       len = QT_UINT32 (node->data);
14441       if (len < 12) {
14442         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
14443             GST_FOURCC_ARGS (add_funcs[i].fourcc));
14444       } else {
14445         add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
14446             add_funcs[i].gst_tag_bis, node);
14447       }
14448       g_node_destroy (node);
14449     } else {
14450       i++;
14451     }
14452   }
14453
14454   /* parsed nodes have been removed, pass along remainder as blob */
14455   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
14456       (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
14457
14458   /* parse up XMP_ node if existing */
14459   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
14460   if (xmp_ != NULL) {
14461     GstBuffer *buf;
14462     GstTagList *xmptaglist;
14463
14464     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
14465         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
14466     xmptaglist = gst_tag_list_from_xmp_buffer (buf);
14467     gst_buffer_unref (buf);
14468
14469     qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
14470   } else {
14471     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
14472   }
14473 }
14474
14475 typedef struct
14476 {
14477   GstStructure *structure;      /* helper for sort function */
14478   gchar *location;
14479   guint min_req_bitrate;
14480   guint min_req_qt_version;
14481 } GstQtReference;
14482
14483 static gint
14484 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
14485 {
14486   GstQtReference *ref_a = (GstQtReference *) a;
14487   GstQtReference *ref_b = (GstQtReference *) b;
14488
14489   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
14490     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
14491
14492   /* known bitrates go before unknown; higher bitrates go first */
14493   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
14494 }
14495
14496 /* sort the redirects and post a message for the application.
14497  */
14498 static void
14499 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
14500 {
14501   GstQtReference *best;
14502   GstStructure *s;
14503   GstMessage *msg;
14504   GValue list_val = { 0, };
14505   GList *l;
14506
14507   g_assert (references != NULL);
14508
14509   references = g_list_sort (references, qtdemux_redirects_sort_func);
14510
14511   best = (GstQtReference *) references->data;
14512
14513   g_value_init (&list_val, GST_TYPE_LIST);
14514
14515   for (l = references; l != NULL; l = l->next) {
14516     GstQtReference *ref = (GstQtReference *) l->data;
14517     GValue struct_val = { 0, };
14518
14519     ref->structure = gst_structure_new ("redirect",
14520         "new-location", G_TYPE_STRING, ref->location, NULL);
14521
14522     if (ref->min_req_bitrate > 0) {
14523       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
14524           ref->min_req_bitrate, NULL);
14525     }
14526
14527     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
14528     g_value_set_boxed (&struct_val, ref->structure);
14529     gst_value_list_append_value (&list_val, &struct_val);
14530     g_value_unset (&struct_val);
14531     /* don't free anything here yet, since we need best->structure below */
14532   }
14533
14534   g_assert (best != NULL);
14535   s = gst_structure_copy (best->structure);
14536
14537   if (g_list_length (references) > 1) {
14538     gst_structure_set_value (s, "locations", &list_val);
14539   }
14540
14541   g_value_unset (&list_val);
14542
14543   for (l = references; l != NULL; l = l->next) {
14544     GstQtReference *ref = (GstQtReference *) l->data;
14545
14546     gst_structure_free (ref->structure);
14547     g_free (ref->location);
14548     g_free (ref);
14549   }
14550   g_list_free (references);
14551
14552   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
14553   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
14554   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
14555   qtdemux->posted_redirect = TRUE;
14556 }
14557
14558 /* look for redirect nodes, collect all redirect information and
14559  * process it.
14560  */
14561 static gboolean
14562 qtdemux_parse_redirects (GstQTDemux * qtdemux)
14563 {
14564   GNode *rmra, *rmda, *rdrf;
14565
14566   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
14567   if (rmra) {
14568     GList *redirects = NULL;
14569
14570     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
14571     while (rmda) {
14572       GstQtReference ref = { NULL, NULL, 0, 0 };
14573       GNode *rmdr, *rmvc;
14574
14575       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
14576         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
14577         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
14578             ref.min_req_bitrate);
14579       }
14580
14581       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
14582         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
14583         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
14584
14585 #ifndef GST_DISABLE_GST_DEBUG
14586         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
14587 #endif
14588         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
14589
14590         GST_LOG_OBJECT (qtdemux,
14591             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
14592             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
14593             bitmask, check_type);
14594         if (package == FOURCC_qtim && check_type == 0) {
14595           ref.min_req_qt_version = version;
14596         }
14597       }
14598
14599       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
14600       if (rdrf) {
14601         guint32 ref_type;
14602         guint8 *ref_data;
14603         guint ref_len;
14604
14605         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
14606         if (ref_len > 20) {
14607           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
14608           ref_data = (guint8 *) rdrf->data + 20;
14609           if (ref_type == FOURCC_alis) {
14610             guint record_len, record_version, fn_len;
14611
14612             if (ref_len > 70) {
14613               /* MacOSX alias record, google for alias-layout.txt */
14614               record_len = QT_UINT16 (ref_data + 4);
14615               record_version = QT_UINT16 (ref_data + 4 + 2);
14616               fn_len = QT_UINT8 (ref_data + 50);
14617               if (record_len > 50 && record_version == 2 && fn_len > 0) {
14618                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
14619               }
14620             } else {
14621               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
14622                   ref_len);
14623             }
14624           } else if (ref_type == FOURCC_url_) {
14625             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
14626           } else {
14627             GST_DEBUG_OBJECT (qtdemux,
14628                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
14629                 GST_FOURCC_ARGS (ref_type));
14630           }
14631           if (ref.location != NULL) {
14632             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
14633             redirects =
14634                 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
14635           } else {
14636             GST_WARNING_OBJECT (qtdemux,
14637                 "Failed to extract redirect location from rdrf atom");
14638           }
14639         } else {
14640           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
14641         }
14642       }
14643
14644       /* look for others */
14645       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
14646     }
14647
14648     if (redirects != NULL) {
14649       qtdemux_process_redirects (qtdemux, redirects);
14650     }
14651   }
14652   return TRUE;
14653 }
14654
14655 static GstTagList *
14656 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
14657 {
14658   const gchar *fmt;
14659
14660   if (tags == NULL) {
14661     tags = gst_tag_list_new_empty ();
14662     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
14663   }
14664
14665   if (qtdemux->major_brand == FOURCC_mjp2)
14666     fmt = "Motion JPEG 2000";
14667   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
14668     fmt = "3GP";
14669   else if (qtdemux->major_brand == FOURCC_qt__)
14670     fmt = "Quicktime";
14671   else if (qtdemux->fragmented)
14672     fmt = "ISO fMP4";
14673   else
14674     fmt = "ISO MP4/M4A";
14675
14676   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
14677       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
14678
14679   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
14680       fmt, NULL);
14681
14682   return tags;
14683 }
14684
14685 /* we have read the complete moov node now.
14686  * This function parses all of the relevant info, creates the traks and
14687  * prepares all data structures for playback
14688  */
14689 static gboolean
14690 qtdemux_parse_tree (GstQTDemux * qtdemux)
14691 {
14692   GNode *mvhd;
14693   GNode *trak;
14694   GNode *udta;
14695   GNode *mvex;
14696   GNode *pssh;
14697   guint64 creation_time;
14698   GstDateTime *datetime = NULL;
14699   gint version;
14700
14701   /* make sure we have a usable taglist */
14702   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14703
14704   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14705   if (mvhd == NULL) {
14706     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14707     return qtdemux_parse_redirects (qtdemux);
14708   }
14709
14710   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14711   if (version == 1) {
14712     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14713     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14714     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14715   } else if (version == 0) {
14716     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14717     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14718     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14719   } else {
14720     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14721     return FALSE;
14722   }
14723
14724   /* Moving qt creation time (secs since 1904) to unix time */
14725   if (creation_time != 0) {
14726     /* Try to use epoch first as it should be faster and more commonly found */
14727     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14728       GTimeVal now;
14729
14730       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14731       /* some data cleansing sanity */
14732       g_get_current_time (&now);
14733       if (now.tv_sec + 24 * 3600 < creation_time) {
14734         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14735       } else {
14736         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14737       }
14738     } else {
14739       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14740       GDateTime *dt, *dt_local;
14741
14742       dt = g_date_time_add_seconds (base_dt, creation_time);
14743       dt_local = g_date_time_to_local (dt);
14744       datetime = gst_date_time_new_from_g_date_time (dt_local);
14745
14746       g_date_time_unref (base_dt);
14747       g_date_time_unref (dt);
14748     }
14749   }
14750   if (datetime) {
14751     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14752     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14753         datetime, NULL);
14754     gst_date_time_unref (datetime);
14755   }
14756
14757   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14758   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14759
14760   /* check for fragmented file and get some (default) data */
14761   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14762   if (mvex) {
14763     GNode *mehd;
14764     GstByteReader mehd_data;
14765
14766     /* let track parsing or anyone know weird stuff might happen ... */
14767     qtdemux->fragmented = TRUE;
14768
14769     /* compensate for total duration */
14770     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14771     if (mehd)
14772       qtdemux_parse_mehd (qtdemux, &mehd_data);
14773   }
14774
14775   /* Update the movie segment duration, unless it was directly given to us
14776    * by upstream. Otherwise let it as is, as we don't want to mangle the
14777    * duration provided by upstream that may come e.g. from a MPD file. */
14778   if (!qtdemux->upstream_format_is_time) {
14779     GstClockTime duration;
14780     /* set duration in the segment info */
14781     gst_qtdemux_get_duration (qtdemux, &duration);
14782     qtdemux->segment.duration = duration;
14783     /* also do not exceed duration; stop is set that way post seek anyway,
14784      * and segment activation falls back to duration,
14785      * whereas loop only checks stop, so let's align this here as well */
14786     qtdemux->segment.stop = duration;
14787   }
14788
14789   /* parse all traks */
14790   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14791   while (trak) {
14792     qtdemux_parse_trak (qtdemux, trak);
14793     /* iterate all siblings */
14794     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14795   }
14796
14797   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14798
14799   /* find tags */
14800   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14801   if (udta) {
14802     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14803   } else {
14804     GST_LOG_OBJECT (qtdemux, "No udta node found.");
14805   }
14806
14807   /* maybe also some tags in meta box */
14808   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14809   if (udta) {
14810     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14811     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14812   } else {
14813     GST_LOG_OBJECT (qtdemux, "No meta node found.");
14814   }
14815
14816   /* parse any protection system info */
14817   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14818   while (pssh) {
14819     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14820     qtdemux_parse_pssh (qtdemux, pssh);
14821     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14822   }
14823
14824   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14825
14826   return TRUE;
14827 }
14828
14829 /* taken from ffmpeg */
14830 static int
14831 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14832 {
14833   int count = 4;
14834   int len = 0;
14835
14836   while (count--) {
14837     int c;
14838
14839     if (ptr >= end)
14840       return -1;
14841
14842     c = *ptr++;
14843     len = (len << 7) | (c & 0x7f);
14844     if (!(c & 0x80))
14845       break;
14846   }
14847   *end_out = ptr;
14848   return len;
14849 }
14850
14851 static GList *
14852 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14853     gsize codec_data_size)
14854 {
14855   GList *list = NULL;
14856   guint8 *p = codec_data;
14857   gint i, offset, num_packets;
14858   guint *length, last;
14859
14860   GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14861
14862   if (codec_data == NULL || codec_data_size == 0)
14863     goto error;
14864
14865   /* start of the stream and vorbis audio or theora video, need to
14866    * send the codec_priv data as first three packets */
14867   num_packets = p[0] + 1;
14868   GST_DEBUG_OBJECT (qtdemux,
14869       "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14870       (guint) num_packets, codec_data_size);
14871
14872   /* Let's put some limits, Don't think there even is a xiph codec
14873    * with more than 3-4 headers */
14874   if (G_UNLIKELY (num_packets > 16)) {
14875     GST_WARNING_OBJECT (qtdemux,
14876         "Unlikely number of xiph headers, most likely not valid");
14877     goto error;
14878   }
14879
14880   length = g_alloca (num_packets * sizeof (guint));
14881   last = 0;
14882   offset = 1;
14883
14884   /* first packets, read length values */
14885   for (i = 0; i < num_packets - 1; i++) {
14886     length[i] = 0;
14887     while (offset < codec_data_size) {
14888       length[i] += p[offset];
14889       if (p[offset++] != 0xff)
14890         break;
14891     }
14892     last += length[i];
14893   }
14894   if (offset + last > codec_data_size)
14895     goto error;
14896
14897   /* last packet is the remaining size */
14898   length[i] = codec_data_size - offset - last;
14899
14900   for (i = 0; i < num_packets; i++) {
14901     GstBuffer *hdr;
14902
14903     GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14904
14905     if (offset + length[i] > codec_data_size)
14906       goto error;
14907
14908     hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
14909     list = g_list_append (list, hdr);
14910
14911     offset += length[i];
14912   }
14913
14914   return list;
14915
14916   /* ERRORS */
14917 error:
14918   {
14919     if (list != NULL)
14920       g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14921     return NULL;
14922   }
14923
14924 }
14925
14926 /* this can change the codec originally present in @list */
14927 static void
14928 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14929     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14930 {
14931   int len = QT_UINT32 (esds->data);
14932   guint8 *ptr = esds->data;
14933   guint8 *end = ptr + len;
14934   int tag;
14935   guint8 *data_ptr = NULL;
14936   int data_len = 0;
14937   guint8 object_type_id = 0;
14938   guint8 stream_type = 0;
14939   const char *codec_name = NULL;
14940   GstCaps *caps = NULL;
14941
14942   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14943   ptr += 8;
14944   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14945   ptr += 4;
14946   while (ptr + 1 < end) {
14947     tag = QT_UINT8 (ptr);
14948     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14949     ptr++;
14950     len = read_descr_size (ptr, end, &ptr);
14951     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14952
14953     /* Check the stated amount of data is available for reading */
14954     if (len < 0 || ptr + len > end)
14955       break;
14956
14957     switch (tag) {
14958       case ES_DESCRIPTOR_TAG:
14959         GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
14960         GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
14961         ptr += 3;
14962         break;
14963       case DECODER_CONFIG_DESC_TAG:{
14964         guint max_bitrate, avg_bitrate;
14965
14966         object_type_id = QT_UINT8 (ptr);
14967         stream_type = QT_UINT8 (ptr + 1) >> 2;
14968         max_bitrate = QT_UINT32 (ptr + 5);
14969         avg_bitrate = QT_UINT32 (ptr + 9);
14970         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
14971         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
14972         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
14973         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
14974         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
14975         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
14976           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14977               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
14978         }
14979         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
14980           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
14981               avg_bitrate, NULL);
14982         }
14983         ptr += 13;
14984         break;
14985       }
14986       case DECODER_SPECIFIC_INFO_TAG:
14987         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
14988         if (object_type_id == 0xe0 && len == 0x40) {
14989           guint8 *data;
14990           GstStructure *s;
14991           guint32 clut[16];
14992           gint i;
14993
14994           GST_DEBUG_OBJECT (qtdemux,
14995               "Have VOBSUB palette. Creating palette event");
14996           /* move to decConfigDescr data and read palette */
14997           data = ptr;
14998           for (i = 0; i < 16; i++) {
14999             clut[i] = QT_UINT32 (data);
15000             data += 4;
15001           }
15002
15003           s = gst_structure_new ("application/x-gst-dvd", "event",
15004               G_TYPE_STRING, "dvd-spu-clut-change",
15005               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
15006               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
15007               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
15008               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
15009               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
15010               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
15011               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
15012               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
15013               NULL);
15014
15015           /* store event and trigger custom processing */
15016           stream->pending_event =
15017               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
15018         } else {
15019           /* Generic codec_data handler puts it on the caps */
15020           data_ptr = ptr;
15021           data_len = len;
15022         }
15023
15024         ptr += len;
15025         break;
15026       case SL_CONFIG_DESC_TAG:
15027         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
15028         ptr += 1;
15029         break;
15030       default:
15031         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
15032             tag);
15033         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
15034         ptr += len;
15035         break;
15036     }
15037   }
15038
15039   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
15040    * in use, and should also be used to override some other parameters for some
15041    * codecs. */
15042   switch (object_type_id) {
15043     case 0x20:                 /* MPEG-4 */
15044       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
15045        * profile_and_level_indication */
15046       if (data_ptr != NULL && data_len >= 5 &&
15047           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
15048         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
15049             data_ptr + 4, data_len - 4);
15050       }
15051       break;                    /* Nothing special needed here */
15052     case 0x21:                 /* H.264 */
15053       codec_name = "H.264 / AVC";
15054       caps = gst_caps_new_simple ("video/x-h264",
15055           "stream-format", G_TYPE_STRING, "avc",
15056           "alignment", G_TYPE_STRING, "au", NULL);
15057       break;
15058     case 0x40:                 /* AAC (any) */
15059     case 0x66:                 /* AAC Main */
15060     case 0x67:                 /* AAC LC */
15061     case 0x68:                 /* AAC SSR */
15062       /* Override channels and rate based on the codec_data, as it's often
15063        * wrong. */
15064       /* Only do so for basic setup without HE-AAC extension */
15065       if (data_ptr && data_len == 2) {
15066         guint channels, rate;
15067
15068         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
15069         if (channels > 0)
15070           entry->n_channels = channels;
15071
15072         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
15073         if (rate > 0)
15074           entry->rate = rate;
15075       }
15076
15077       /* Set level and profile if possible */
15078       if (data_ptr != NULL && data_len >= 2) {
15079         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
15080             data_ptr, data_len);
15081       } else {
15082         const gchar *profile_str = NULL;
15083         GstBuffer *buffer;
15084         GstMapInfo map;
15085         guint8 *codec_data;
15086         gint rate_idx, profile;
15087
15088         /* No codec_data, let's invent something.
15089          * FIXME: This is wrong for SBR! */
15090
15091         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
15092
15093         buffer = gst_buffer_new_and_alloc (2);
15094         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
15095         codec_data = map.data;
15096
15097         rate_idx =
15098             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
15099             (stream)->rate);
15100
15101         switch (object_type_id) {
15102           case 0x66:
15103             profile_str = "main";
15104             profile = 0;
15105             break;
15106           case 0x67:
15107             profile_str = "lc";
15108             profile = 1;
15109             break;
15110           case 0x68:
15111             profile_str = "ssr";
15112             profile = 2;
15113             break;
15114           default:
15115             profile = 3;
15116             break;
15117         }
15118
15119         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
15120         codec_data[1] =
15121             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
15122
15123         gst_buffer_unmap (buffer, &map);
15124         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
15125             GST_TYPE_BUFFER, buffer, NULL);
15126         gst_buffer_unref (buffer);
15127
15128         if (profile_str) {
15129           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
15130               G_TYPE_STRING, profile_str, NULL);
15131         }
15132       }
15133       break;
15134     case 0x60:                 /* MPEG-2, various profiles */
15135     case 0x61:
15136     case 0x62:
15137     case 0x63:
15138     case 0x64:
15139     case 0x65:
15140       codec_name = "MPEG-2 video";
15141       caps = gst_caps_new_simple ("video/mpeg",
15142           "mpegversion", G_TYPE_INT, 2,
15143           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15144       break;
15145     case 0x69:                 /* MPEG-2 BC audio */
15146     case 0x6B:                 /* MPEG-1 audio */
15147       caps = gst_caps_new_simple ("audio/mpeg",
15148           "mpegversion", G_TYPE_INT, 1, NULL);
15149       codec_name = "MPEG-1 audio";
15150       break;
15151     case 0x6A:                 /* MPEG-1 */
15152       codec_name = "MPEG-1 video";
15153       caps = gst_caps_new_simple ("video/mpeg",
15154           "mpegversion", G_TYPE_INT, 1,
15155           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15156       break;
15157     case 0x6C:                 /* MJPEG */
15158       caps =
15159           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15160           NULL);
15161       codec_name = "Motion-JPEG";
15162       break;
15163     case 0x6D:                 /* PNG */
15164       caps =
15165           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
15166           NULL);
15167       codec_name = "PNG still images";
15168       break;
15169     case 0x6E:                 /* JPEG2000 */
15170       codec_name = "JPEG-2000";
15171       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15172       break;
15173     case 0xA4:                 /* Dirac */
15174       codec_name = "Dirac";
15175       caps = gst_caps_new_empty_simple ("video/x-dirac");
15176       break;
15177     case 0xA5:                 /* AC3 */
15178       codec_name = "AC-3 audio";
15179       caps = gst_caps_new_simple ("audio/x-ac3",
15180           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15181       break;
15182     case 0xA9:                 /* AC3 */
15183       codec_name = "DTS audio";
15184       caps = gst_caps_new_simple ("audio/x-dts",
15185           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15186       break;
15187     case 0xDD:
15188       if (stream_type == 0x05 && data_ptr) {
15189         GList *headers =
15190             parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
15191         if (headers) {
15192           GList *tmp;
15193           GValue arr_val = G_VALUE_INIT;
15194           GValue buf_val = G_VALUE_INIT;
15195           GstStructure *s;
15196
15197           /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
15198           codec_name = "Vorbis";
15199           caps = gst_caps_new_empty_simple ("audio/x-vorbis");
15200           g_value_init (&arr_val, GST_TYPE_ARRAY);
15201           g_value_init (&buf_val, GST_TYPE_BUFFER);
15202           for (tmp = headers; tmp; tmp = tmp->next) {
15203             g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
15204             gst_value_array_append_value (&arr_val, &buf_val);
15205           }
15206           s = gst_caps_get_structure (caps, 0);
15207           gst_structure_take_value (s, "streamheader", &arr_val);
15208           g_value_unset (&buf_val);
15209           g_list_free (headers);
15210
15211           data_ptr = NULL;
15212           data_len = 0;
15213         }
15214       }
15215       break;
15216     case 0xE1:                 /* QCELP */
15217       /* QCELP, the codec_data is a riff tag (little endian) with
15218        * 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). */
15219       caps = gst_caps_new_empty_simple ("audio/qcelp");
15220       codec_name = "QCELP";
15221       break;
15222     default:
15223       break;
15224   }
15225
15226   /* If we have a replacement caps, then change our caps for this stream */
15227   if (caps) {
15228     gst_caps_unref (entry->caps);
15229     entry->caps = caps;
15230   }
15231
15232   if (codec_name && list)
15233     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
15234         GST_TAG_AUDIO_CODEC, codec_name, NULL);
15235
15236   /* Add the codec_data attribute to caps, if we have it */
15237   if (data_ptr) {
15238     GstBuffer *buffer;
15239
15240     buffer = gst_buffer_new_and_alloc (data_len);
15241     gst_buffer_fill (buffer, 0, data_ptr, data_len);
15242
15243     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
15244     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
15245
15246     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
15247         buffer, NULL);
15248     gst_buffer_unref (buffer);
15249   }
15250
15251 }
15252
15253 static inline GstCaps *
15254 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
15255 {
15256   GstCaps *caps;
15257   guint i;
15258   char *s, fourstr[5];
15259
15260   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
15261   for (i = 0; i < 4; i++) {
15262     if (!g_ascii_isalnum (fourstr[i]))
15263       fourstr[i] = '_';
15264   }
15265   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
15266   caps = gst_caps_new_empty_simple (s);
15267   g_free (s);
15268   return caps;
15269 }
15270
15271 #define _codec(name) \
15272   do { \
15273     if (codec_name) { \
15274       *codec_name = g_strdup (name); \
15275     } \
15276   } while (0)
15277
15278 static GstCaps *
15279 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15280     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15281     const guint8 * stsd_entry_data, gchar ** codec_name)
15282 {
15283   GstCaps *caps = NULL;
15284   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
15285
15286   switch (fourcc) {
15287     case FOURCC_png:
15288       _codec ("PNG still images");
15289       caps = gst_caps_new_empty_simple ("image/png");
15290       break;
15291     case FOURCC_jpeg:
15292       _codec ("JPEG still images");
15293       caps =
15294           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15295           NULL);
15296       break;
15297     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
15298     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
15299     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
15300     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
15301       _codec ("Motion-JPEG");
15302       caps =
15303           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15304           NULL);
15305       break;
15306     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
15307       _codec ("Motion-JPEG format B");
15308       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
15309       break;
15310     case FOURCC_mjp2:
15311       _codec ("JPEG-2000");
15312       /* override to what it should be according to spec, avoid palette_data */
15313       entry->bits_per_sample = 24;
15314       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15315       break;
15316     case FOURCC_SVQ3:
15317       _codec ("Sorensen video v.3");
15318       caps = gst_caps_new_simple ("video/x-svq",
15319           "svqversion", G_TYPE_INT, 3, NULL);
15320       break;
15321     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
15322     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
15323       _codec ("Sorensen video v.1");
15324       caps = gst_caps_new_simple ("video/x-svq",
15325           "svqversion", G_TYPE_INT, 1, NULL);
15326       break;
15327     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
15328       caps = gst_caps_new_empty_simple ("video/x-raw");
15329       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
15330       _codec ("Windows Raw RGB");
15331       stream->alignment = 32;
15332       break;
15333     case FOURCC_raw_:
15334     {
15335       guint16 bps;
15336
15337       bps = QT_UINT16 (stsd_entry_data + 82);
15338       switch (bps) {
15339         case 15:
15340           format = GST_VIDEO_FORMAT_RGB15;
15341           break;
15342         case 16:
15343           format = GST_VIDEO_FORMAT_RGB16;
15344           break;
15345         case 24:
15346           format = GST_VIDEO_FORMAT_RGB;
15347           break;
15348         case 32:
15349           format = GST_VIDEO_FORMAT_ARGB;
15350           break;
15351         default:
15352           /* unknown */
15353           break;
15354       }
15355       break;
15356     }
15357     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
15358       format = GST_VIDEO_FORMAT_I420;
15359       break;
15360     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
15361     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
15362       format = GST_VIDEO_FORMAT_I420;
15363       break;
15364     case FOURCC_2vuy:
15365     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
15366       format = GST_VIDEO_FORMAT_UYVY;
15367       break;
15368     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
15369       format = GST_VIDEO_FORMAT_v308;
15370       break;
15371     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
15372       format = GST_VIDEO_FORMAT_v216;
15373       break;
15374     case FOURCC_v210:
15375       format = GST_VIDEO_FORMAT_v210;
15376       break;
15377     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
15378       format = GST_VIDEO_FORMAT_r210;
15379       break;
15380       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
15381          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
15382          format = GST_VIDEO_FORMAT_v410;
15383          break;
15384        */
15385       /* Packed YUV 4:4:4:4 8 bit in 32 bits
15386        * but different order than AYUV
15387        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
15388        format = GST_VIDEO_FORMAT_v408;
15389        break;
15390        */
15391     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
15392     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
15393       _codec ("MPEG-1 video");
15394       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15395           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15396       break;
15397     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
15398     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
15399     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
15400     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
15401     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
15402     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
15403     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
15404     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
15405     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
15406     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
15407     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
15408     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
15409     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
15410     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
15411     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
15412     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
15413     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
15414     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
15415     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
15416     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
15417     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
15418     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
15419     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
15420     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
15421     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
15422     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
15423     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
15424     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
15425     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
15426     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
15427     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
15428     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
15429     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
15430     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
15431     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
15432     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
15433     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15434     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15435     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
15436     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
15437     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
15438     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
15439     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
15440     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
15441     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
15442     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
15443     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
15444       _codec ("MPEG-2 video");
15445       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
15446           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15447       break;
15448     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
15449       _codec ("GIF still images");
15450       caps = gst_caps_new_empty_simple ("image/gif");
15451       break;
15452     case FOURCC_h263:
15453     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
15454     case FOURCC_s263:
15455     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
15456       _codec ("H.263");
15457       /* ffmpeg uses the height/width props, don't know why */
15458       caps = gst_caps_new_simple ("video/x-h263",
15459           "variant", G_TYPE_STRING, "itu", NULL);
15460       break;
15461     case FOURCC_mp4v:
15462     case FOURCC_MP4V:
15463       _codec ("MPEG-4 video");
15464       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15465           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15466       break;
15467     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
15468     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
15469       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
15470       caps = gst_caps_new_simple ("video/x-msmpeg",
15471           "msmpegversion", G_TYPE_INT, 43, NULL);
15472       break;
15473     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
15474       _codec ("DivX 3");
15475       caps = gst_caps_new_simple ("video/x-divx",
15476           "divxversion", G_TYPE_INT, 3, NULL);
15477       break;
15478     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
15479     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
15480       _codec ("DivX 4");
15481       caps = gst_caps_new_simple ("video/x-divx",
15482           "divxversion", G_TYPE_INT, 4, NULL);
15483       break;
15484     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
15485       _codec ("DivX 5");
15486       caps = gst_caps_new_simple ("video/x-divx",
15487           "divxversion", G_TYPE_INT, 5, NULL);
15488       break;
15489
15490     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
15491       _codec ("FFV1");
15492       caps = gst_caps_new_simple ("video/x-ffv",
15493           "ffvversion", G_TYPE_INT, 1, NULL);
15494       break;
15495
15496     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
15497     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
15498     case FOURCC_XVID:
15499     case FOURCC_xvid:
15500     case FOURCC_FMP4:
15501     case FOURCC_fmp4:
15502     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
15503       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15504           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15505       _codec ("MPEG-4");
15506       break;
15507
15508     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
15509       _codec ("Cinepak");
15510       caps = gst_caps_new_empty_simple ("video/x-cinepak");
15511       break;
15512     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
15513       _codec ("Apple QuickDraw");
15514       caps = gst_caps_new_empty_simple ("video/x-qdrw");
15515       break;
15516     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
15517       _codec ("Apple video");
15518       caps = gst_caps_new_empty_simple ("video/x-apple-video");
15519       break;
15520     case FOURCC_H264:
15521     case FOURCC_avc1:
15522       _codec ("H.264 / AVC");
15523       caps = gst_caps_new_simple ("video/x-h264",
15524           "stream-format", G_TYPE_STRING, "avc",
15525           "alignment", G_TYPE_STRING, "au", NULL);
15526       break;
15527     case FOURCC_avc3:
15528       _codec ("H.264 / AVC");
15529       caps = gst_caps_new_simple ("video/x-h264",
15530           "stream-format", G_TYPE_STRING, "avc3",
15531           "alignment", G_TYPE_STRING, "au", NULL);
15532       break;
15533     case FOURCC_H265:
15534     case FOURCC_hvc1:
15535       _codec ("H.265 / HEVC");
15536       caps = gst_caps_new_simple ("video/x-h265",
15537           "stream-format", G_TYPE_STRING, "hvc1",
15538           "alignment", G_TYPE_STRING, "au", NULL);
15539       break;
15540     case FOURCC_hev1:
15541       _codec ("H.265 / HEVC");
15542       caps = gst_caps_new_simple ("video/x-h265",
15543           "stream-format", G_TYPE_STRING, "hev1",
15544           "alignment", G_TYPE_STRING, "au", NULL);
15545       break;
15546     case FOURCC_rle_:
15547       _codec ("Run-length encoding");
15548       caps = gst_caps_new_simple ("video/x-rle",
15549           "layout", G_TYPE_STRING, "quicktime", NULL);
15550       break;
15551     case FOURCC_WRLE:
15552       _codec ("Run-length encoding");
15553       caps = gst_caps_new_simple ("video/x-rle",
15554           "layout", G_TYPE_STRING, "microsoft", NULL);
15555       break;
15556     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
15557     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
15558       _codec ("Indeo Video 3");
15559       caps = gst_caps_new_simple ("video/x-indeo",
15560           "indeoversion", G_TYPE_INT, 3, NULL);
15561       break;
15562     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
15563     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
15564       _codec ("Intel Video 4");
15565       caps = gst_caps_new_simple ("video/x-indeo",
15566           "indeoversion", G_TYPE_INT, 4, NULL);
15567       break;
15568     case FOURCC_dvcp:
15569     case FOURCC_dvc_:
15570     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
15571     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
15572     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
15573     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
15574     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
15575     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
15576       _codec ("DV Video");
15577       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
15578           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15579       break;
15580     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
15581     case FOURCC_dv5p:          /* DVCPRO50 PAL */
15582       _codec ("DVCPro50 Video");
15583       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
15584           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15585       break;
15586     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
15587     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
15588       _codec ("DVCProHD Video");
15589       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
15590           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15591       break;
15592     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
15593       _codec ("Apple Graphics (SMC)");
15594       caps = gst_caps_new_empty_simple ("video/x-smc");
15595       break;
15596     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
15597       _codec ("VP3");
15598       caps = gst_caps_new_empty_simple ("video/x-vp3");
15599       break;
15600     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
15601       _codec ("VP6 Flash");
15602       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
15603       break;
15604     case FOURCC_XiTh:
15605       _codec ("Theora");
15606       caps = gst_caps_new_empty_simple ("video/x-theora");
15607       /* theora uses one byte of padding in the data stream because it does not
15608        * allow 0 sized packets while theora does */
15609       entry->padding = 1;
15610       break;
15611     case FOURCC_drac:
15612       _codec ("Dirac");
15613       caps = gst_caps_new_empty_simple ("video/x-dirac");
15614       break;
15615     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
15616       _codec ("TIFF still images");
15617       caps = gst_caps_new_empty_simple ("image/tiff");
15618       break;
15619     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
15620       _codec ("Apple Intermediate Codec");
15621       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
15622       break;
15623     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
15624       _codec ("AVID DNxHD");
15625       caps = gst_caps_from_string ("video/x-dnxhd");
15626       break;
15627     case FOURCC_VP80:
15628     case FOURCC_vp08:
15629       _codec ("On2 VP8");
15630       caps = gst_caps_from_string ("video/x-vp8");
15631       break;
15632     case FOURCC_vp09:
15633       _codec ("Google VP9");
15634       caps = gst_caps_from_string ("video/x-vp9");
15635       break;
15636     case FOURCC_apcs:
15637       _codec ("Apple ProRes LT");
15638       caps =
15639           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
15640           NULL);
15641       break;
15642     case FOURCC_apch:
15643       _codec ("Apple ProRes HQ");
15644       caps =
15645           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
15646           NULL);
15647       break;
15648     case FOURCC_apcn:
15649       _codec ("Apple ProRes");
15650       caps =
15651           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15652           "standard", NULL);
15653       break;
15654     case FOURCC_apco:
15655       _codec ("Apple ProRes Proxy");
15656       caps =
15657           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15658           "proxy", NULL);
15659       break;
15660     case FOURCC_ap4h:
15661       _codec ("Apple ProRes 4444");
15662       caps =
15663           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15664           "4444", NULL);
15665       break;
15666     case FOURCC_ap4x:
15667       _codec ("Apple ProRes 4444 XQ");
15668       caps =
15669           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15670           "4444xq", NULL);
15671       break;
15672     case FOURCC_cfhd:
15673       _codec ("GoPro CineForm");
15674       caps = gst_caps_from_string ("video/x-cineform");
15675       break;
15676     case FOURCC_vc_1:
15677     case FOURCC_ovc1:
15678       _codec ("VC-1");
15679       caps = gst_caps_new_simple ("video/x-wmv",
15680           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
15681       break;
15682     case FOURCC_av01:
15683       _codec ("AV1");
15684       caps = gst_caps_new_empty_simple ("video/x-av1");
15685       break;
15686     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15687     default:
15688     {
15689       caps = _get_unknown_codec_name ("video", fourcc);
15690       break;
15691     }
15692   }
15693
15694   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15695     GstVideoInfo info;
15696
15697     gst_video_info_init (&info);
15698     gst_video_info_set_format (&info, format, entry->width, entry->height);
15699
15700     caps = gst_video_info_to_caps (&info);
15701     *codec_name = gst_pb_utils_get_codec_description (caps);
15702
15703     /* enable clipping for raw video streams */
15704     stream->need_clip = TRUE;
15705     stream->alignment = 32;
15706   }
15707
15708   return caps;
15709 }
15710
15711 static guint
15712 round_up_pow2 (guint n)
15713 {
15714   n = n - 1;
15715   n = n | (n >> 1);
15716   n = n | (n >> 2);
15717   n = n | (n >> 4);
15718   n = n | (n >> 8);
15719   n = n | (n >> 16);
15720   return n + 1;
15721 }
15722
15723 static GstCaps *
15724 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15725     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15726     int len, gchar ** codec_name)
15727 {
15728   GstCaps *caps;
15729   const GstStructure *s;
15730   const gchar *name;
15731   gint endian = 0;
15732   GstAudioFormat format = 0;
15733   gint depth;
15734
15735   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15736
15737   depth = entry->bytes_per_packet * 8;
15738
15739   switch (fourcc) {
15740     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15741     case FOURCC_raw_:
15742       /* 8-bit audio is unsigned */
15743       if (depth == 8)
15744         format = GST_AUDIO_FORMAT_U8;
15745       /* otherwise it's signed and big-endian just like 'twos' */
15746     case FOURCC_twos:
15747       endian = G_BIG_ENDIAN;
15748       /* fall-through */
15749     case FOURCC_sowt:
15750     {
15751       gchar *str;
15752
15753       if (!endian)
15754         endian = G_LITTLE_ENDIAN;
15755
15756       if (!format)
15757         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15758
15759       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15760       _codec (str);
15761       g_free (str);
15762
15763       caps = gst_caps_new_simple ("audio/x-raw",
15764           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15765           "layout", G_TYPE_STRING, "interleaved", NULL);
15766       stream->alignment = GST_ROUND_UP_8 (depth);
15767       stream->alignment = round_up_pow2 (stream->alignment);
15768       break;
15769     }
15770     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
15771       _codec ("Raw 64-bit floating-point audio");
15772       caps = gst_caps_new_simple ("audio/x-raw",
15773           "format", G_TYPE_STRING, "F64BE",
15774           "layout", G_TYPE_STRING, "interleaved", NULL);
15775       stream->alignment = 8;
15776       break;
15777     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
15778       _codec ("Raw 32-bit floating-point audio");
15779       caps = gst_caps_new_simple ("audio/x-raw",
15780           "format", G_TYPE_STRING, "F32BE",
15781           "layout", G_TYPE_STRING, "interleaved", NULL);
15782       stream->alignment = 4;
15783       break;
15784     case FOURCC_in24:
15785       _codec ("Raw 24-bit PCM audio");
15786       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15787        * endian later */
15788       caps = gst_caps_new_simple ("audio/x-raw",
15789           "format", G_TYPE_STRING, "S24BE",
15790           "layout", G_TYPE_STRING, "interleaved", NULL);
15791       stream->alignment = 4;
15792       break;
15793     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
15794       _codec ("Raw 32-bit PCM audio");
15795       caps = gst_caps_new_simple ("audio/x-raw",
15796           "format", G_TYPE_STRING, "S32BE",
15797           "layout", G_TYPE_STRING, "interleaved", NULL);
15798       stream->alignment = 4;
15799       break;
15800     case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
15801       _codec ("Raw 16-bit PCM audio");
15802       caps = gst_caps_new_simple ("audio/x-raw",
15803           "format", G_TYPE_STRING, "S16LE",
15804           "layout", G_TYPE_STRING, "interleaved", NULL);
15805       stream->alignment = 2;
15806       break;
15807     case FOURCC_ulaw:
15808       _codec ("Mu-law audio");
15809       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15810       break;
15811     case FOURCC_alaw:
15812       _codec ("A-law audio");
15813       caps = gst_caps_new_empty_simple ("audio/x-alaw");
15814       break;
15815     case 0x0200736d:
15816     case 0x6d730002:
15817       _codec ("Microsoft ADPCM");
15818       /* Microsoft ADPCM-ACM code 2 */
15819       caps = gst_caps_new_simple ("audio/x-adpcm",
15820           "layout", G_TYPE_STRING, "microsoft", NULL);
15821       break;
15822     case 0x1100736d:
15823     case 0x6d730011:
15824       _codec ("DVI/IMA ADPCM");
15825       caps = gst_caps_new_simple ("audio/x-adpcm",
15826           "layout", G_TYPE_STRING, "dvi", NULL);
15827       break;
15828     case 0x1700736d:
15829     case 0x6d730017:
15830       _codec ("DVI/Intel IMA ADPCM");
15831       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15832       caps = gst_caps_new_simple ("audio/x-adpcm",
15833           "layout", G_TYPE_STRING, "quicktime", NULL);
15834       break;
15835     case 0x5500736d:
15836     case 0x6d730055:
15837       /* MPEG layer 3, CBR only (pre QT4.1) */
15838     case FOURCC__mp3:
15839       _codec ("MPEG-1 layer 3");
15840       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15841       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15842           "mpegversion", G_TYPE_INT, 1, NULL);
15843       break;
15844     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15845       _codec ("MPEG-1 layer 2");
15846       /* MPEG layer 2 */
15847       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15848           "mpegversion", G_TYPE_INT, 1, NULL);
15849       break;
15850     case 0x20736d:
15851     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15852       _codec ("EAC-3 audio");
15853       caps = gst_caps_new_simple ("audio/x-eac3",
15854           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15855       entry->sampled = TRUE;
15856       break;
15857     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15858     case FOURCC_ac_3:
15859       _codec ("AC-3 audio");
15860       caps = gst_caps_new_simple ("audio/x-ac3",
15861           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15862       entry->sampled = TRUE;
15863       break;
15864     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15865     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15866       _codec ("DTS audio");
15867       caps = gst_caps_new_simple ("audio/x-dts",
15868           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15869       entry->sampled = TRUE;
15870       break;
15871     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15872     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15873       _codec ("DTS-HD 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 FOURCC_MAC3:
15879       _codec ("MACE-3");
15880       caps = gst_caps_new_simple ("audio/x-mace",
15881           "maceversion", G_TYPE_INT, 3, NULL);
15882       break;
15883     case FOURCC_MAC6:
15884       _codec ("MACE-6");
15885       caps = gst_caps_new_simple ("audio/x-mace",
15886           "maceversion", G_TYPE_INT, 6, NULL);
15887       break;
15888     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15889       /* ogg/vorbis */
15890       caps = gst_caps_new_empty_simple ("application/ogg");
15891       break;
15892     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15893       _codec ("DV audio");
15894       caps = gst_caps_new_empty_simple ("audio/x-dv");
15895       break;
15896     case FOURCC_mp4a:
15897       _codec ("MPEG-4 AAC audio");
15898       caps = gst_caps_new_simple ("audio/mpeg",
15899           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15900           "stream-format", G_TYPE_STRING, "raw", NULL);
15901       break;
15902     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15903       _codec ("QDesign Music");
15904       caps = gst_caps_new_empty_simple ("audio/x-qdm");
15905       break;
15906     case FOURCC_QDM2:
15907       _codec ("QDesign Music v.2");
15908       /* FIXME: QDesign music version 2 (no constant) */
15909       if (FALSE && data) {
15910         caps = gst_caps_new_simple ("audio/x-qdm2",
15911             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15912             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15913             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15914       } else {
15915         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15916       }
15917       break;
15918     case FOURCC_agsm:
15919       _codec ("GSM audio");
15920       caps = gst_caps_new_empty_simple ("audio/x-gsm");
15921       break;
15922     case FOURCC_samr:
15923       _codec ("AMR audio");
15924       caps = gst_caps_new_empty_simple ("audio/AMR");
15925       break;
15926     case FOURCC_sawb:
15927       _codec ("AMR-WB audio");
15928       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15929       break;
15930     case FOURCC_ima4:
15931       _codec ("Quicktime IMA ADPCM");
15932       caps = gst_caps_new_simple ("audio/x-adpcm",
15933           "layout", G_TYPE_STRING, "quicktime", NULL);
15934       break;
15935     case FOURCC_alac:
15936       _codec ("Apple lossless audio");
15937       caps = gst_caps_new_empty_simple ("audio/x-alac");
15938       break;
15939     case FOURCC_fLaC:
15940       _codec ("Free Lossless Audio Codec");
15941       caps = gst_caps_new_simple ("audio/x-flac",
15942           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15943       break;
15944     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15945       _codec ("QualComm PureVoice");
15946       caps = gst_caps_from_string ("audio/qcelp");
15947       break;
15948     case FOURCC_wma_:
15949     case FOURCC_owma:
15950       _codec ("WMA");
15951       caps = gst_caps_new_empty_simple ("audio/x-wma");
15952       break;
15953     case FOURCC_opus:
15954       _codec ("Opus");
15955       caps = gst_caps_new_empty_simple ("audio/x-opus");
15956       break;
15957     case FOURCC_lpcm:
15958     {
15959       guint32 flags = 0;
15960       guint32 depth = 0;
15961       guint32 width = 0;
15962       GstAudioFormat format;
15963       enum
15964       {
15965         FLAG_IS_FLOAT = 0x1,
15966         FLAG_IS_BIG_ENDIAN = 0x2,
15967         FLAG_IS_SIGNED = 0x4,
15968         FLAG_IS_PACKED = 0x8,
15969         FLAG_IS_ALIGNED_HIGH = 0x10,
15970         FLAG_IS_NON_INTERLEAVED = 0x20
15971       };
15972       _codec ("Raw LPCM audio");
15973
15974       if (data && len >= 36) {
15975         depth = QT_UINT32 (data + 24);
15976         flags = QT_UINT32 (data + 28);
15977         width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
15978       }
15979       if ((flags & FLAG_IS_FLOAT) == 0) {
15980         if (depth == 0)
15981           depth = 16;
15982         if (width == 0)
15983           width = 16;
15984         if ((flags & FLAG_IS_ALIGNED_HIGH))
15985           depth = width;
15986
15987         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
15988             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
15989             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
15990         caps = gst_caps_new_simple ("audio/x-raw",
15991             "format", G_TYPE_STRING,
15992             format !=
15993             GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
15994             "UNKNOWN", "layout", G_TYPE_STRING,
15995             (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
15996             "interleaved", NULL);
15997         stream->alignment = GST_ROUND_UP_8 (depth);
15998         stream->alignment = round_up_pow2 (stream->alignment);
15999       } else {
16000         if (width == 0)
16001           width = 32;
16002         if (width == 64) {
16003           if (flags & FLAG_IS_BIG_ENDIAN)
16004             format = GST_AUDIO_FORMAT_F64BE;
16005           else
16006             format = GST_AUDIO_FORMAT_F64LE;
16007         } else {
16008           if (flags & FLAG_IS_BIG_ENDIAN)
16009             format = GST_AUDIO_FORMAT_F32BE;
16010           else
16011             format = GST_AUDIO_FORMAT_F32LE;
16012         }
16013         caps = gst_caps_new_simple ("audio/x-raw",
16014             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
16015             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
16016             "non-interleaved" : "interleaved", NULL);
16017         stream->alignment = width / 8;
16018       }
16019       break;
16020     }
16021     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
16022       /* ? */
16023     default:
16024     {
16025       caps = _get_unknown_codec_name ("audio", fourcc);
16026       break;
16027     }
16028   }
16029
16030   if (caps) {
16031     GstCaps *templ_caps =
16032         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
16033     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
16034     gst_caps_unref (caps);
16035     gst_caps_unref (templ_caps);
16036     caps = intersection;
16037   }
16038
16039   /* enable clipping for raw audio streams */
16040   s = gst_caps_get_structure (caps, 0);
16041   name = gst_structure_get_name (s);
16042   if (g_str_has_prefix (name, "audio/x-raw")) {
16043     stream->need_clip = TRUE;
16044     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
16045     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
16046   }
16047   return caps;
16048 }
16049
16050 static GstCaps *
16051 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16052     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16053     const guint8 * stsd_entry_data, gchar ** codec_name)
16054 {
16055   GstCaps *caps;
16056
16057   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
16058
16059   switch (fourcc) {
16060     case FOURCC_mp4s:
16061       _codec ("DVD subtitle");
16062       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
16063       stream->need_process = TRUE;
16064       break;
16065     case FOURCC_text:
16066       _codec ("Quicktime timed text");
16067       goto text;
16068     case FOURCC_tx3g:
16069       _codec ("3GPP timed text");
16070     text:
16071       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
16072           "utf8", NULL);
16073       /* actual text piece needs to be extracted */
16074       stream->need_process = TRUE;
16075       break;
16076     case FOURCC_stpp:
16077       _codec ("XML subtitles");
16078       caps = gst_caps_new_empty_simple ("application/ttml+xml");
16079       break;
16080     case FOURCC_c608:
16081       _codec ("CEA 608 Closed Caption");
16082       caps =
16083           gst_caps_new_simple ("closedcaption/x-cea-608", "format",
16084           G_TYPE_STRING, "s334-1a", NULL);
16085       stream->need_process = TRUE;
16086       stream->need_split = TRUE;
16087       break;
16088     case FOURCC_c708:
16089       _codec ("CEA 708 Closed Caption");
16090       caps =
16091           gst_caps_new_simple ("closedcaption/x-cea-708", "format",
16092           G_TYPE_STRING, "cdp", NULL);
16093       stream->need_process = TRUE;
16094       break;
16095
16096     default:
16097     {
16098       caps = _get_unknown_codec_name ("text", fourcc);
16099       break;
16100     }
16101   }
16102   return caps;
16103 }
16104
16105 static GstCaps *
16106 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16107     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16108     const guint8 * stsd_entry_data, gchar ** codec_name)
16109 {
16110   GstCaps *caps;
16111
16112   switch (fourcc) {
16113     case FOURCC_m1v:
16114       _codec ("MPEG 1 video");
16115       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
16116           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
16117       break;
16118     default:
16119       caps = NULL;
16120       break;
16121   }
16122   return caps;
16123 }
16124
16125 static void
16126 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
16127     const gchar * system_id)
16128 {
16129   gint i;
16130
16131   if (!qtdemux->protection_system_ids)
16132     qtdemux->protection_system_ids =
16133         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
16134   /* Check whether we already have an entry for this system ID. */
16135   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
16136     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
16137     if (g_ascii_strcasecmp (system_id, id) == 0) {
16138       return;
16139     }
16140   }
16141   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
16142   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
16143           -1));
16144 }