ca78b20d152cd72fa3fedb80fa8879e9bf01ca50
[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 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
334   guint64 tkhd_duration;
335 #endif
336
337   /* duration/scale */
338   guint64 duration;             /* in timescale units */
339   guint32 timescale;
340
341   /* language */
342   gchar lang_id[4];             /* ISO 639-2T language code */
343
344   /* our samples */
345   guint32 n_samples;
346   QtDemuxSample *samples;
347   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
348   guint32 n_samples_moof;       /* sample count in a moof */
349   guint64 duration_moof;        /* duration in timescale of a moof, used for figure out
350                                  * the framerate of fragmented format stream */
351   guint64 duration_last_moof;
352
353   guint32 offset_in_sample;     /* Offset in the current sample, used for
354                                  * streams which have got exceedingly big
355                                  * sample size (such as 24s of raw audio).
356                                  * Only used when max_buffer_size is non-NULL */
357   guint32 max_buffer_size;      /* Maximum allowed size for output buffers.
358                                  * Currently only set for raw audio streams*/
359
360   /* video info */
361   /* aspect ratio */
362   gint display_width;
363   gint display_height;
364
365   /* allocation */
366   gboolean use_allocator;
367   GstAllocator *allocator;
368   GstAllocationParams params;
369
370   gsize alignment;
371
372   /* when a discontinuity is pending */
373   gboolean discont;
374
375   /* list of buffers to push first */
376   GSList *buffers;
377
378   /* if we need to clip this buffer. This is only needed for uncompressed
379    * data */
380   gboolean need_clip;
381
382   /* buffer needs some custom processing, e.g. subtitles */
383   gboolean need_process;
384   /* buffer needs potentially be split, e.g. CEA608 subtitles */
385   gboolean need_split;
386
387   /* current position */
388   guint32 segment_index;
389   guint32 sample_index;
390   GstClockTime time_position;   /* in gst time */
391   guint64 accumulated_base;
392
393   /* the Gst segment we are processing out, used for clipping */
394   GstSegment segment;
395
396   /* quicktime segments */
397   guint32 n_segments;
398   QtDemuxSegment *segments;
399   gboolean dummy_segment;
400   guint32 from_sample;
401   guint32 to_sample;
402
403   gboolean sent_eos;
404   GstTagList *stream_tags;
405   gboolean send_global_tags;
406
407   GstEvent *pending_event;
408
409   GstByteReader stco;
410   GstByteReader stsz;
411   GstByteReader stsc;
412   GstByteReader stts;
413   GstByteReader stss;
414   GstByteReader stps;
415   GstByteReader ctts;
416
417   gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
418   gint64 stbl_index;
419   /* stco */
420   guint co_size;
421   GstByteReader co_chunk;
422   guint32 first_chunk;
423   guint32 current_chunk;
424   guint32 last_chunk;
425   guint32 samples_per_chunk;
426   guint32 stsd_sample_description_id;
427   guint32 stco_sample_index;
428   /* stsz */
429   guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
430   /* stsc */
431   guint32 stsc_index;
432   guint32 n_samples_per_chunk;
433   guint32 stsc_chunk_index;
434   guint32 stsc_sample_index;
435   guint64 chunk_offset;
436   /* stts */
437   guint32 stts_index;
438   guint32 stts_samples;
439   guint32 n_sample_times;
440   guint32 stts_sample_index;
441   guint64 stts_time;
442   guint32 stts_duration;
443   /* stss */
444   gboolean stss_present;
445   guint32 n_sample_syncs;
446   guint32 stss_index;
447   /* stps */
448   gboolean stps_present;
449   guint32 n_sample_partial_syncs;
450   guint32 stps_index;
451   QtDemuxRandomAccessEntry *ra_entries;
452   guint n_ra_entries;
453
454   const QtDemuxRandomAccessEntry *pending_seek;
455
456   /* ctts */
457   gboolean ctts_present;
458   guint32 n_composition_times;
459   guint32 ctts_index;
460   guint32 ctts_sample_index;
461   guint32 ctts_count;
462   gint32 ctts_soffset;
463
464   /* cslg */
465   guint32 cslg_shift;
466
467   /* fragmented */
468   gboolean parsed_trex;
469   guint32 def_sample_description_index; /* index is 1-based */
470   guint32 def_sample_duration;
471   guint32 def_sample_size;
472   guint32 def_sample_flags;
473
474   gboolean disabled;
475
476   /* stereoscopic video streams */
477   GstVideoMultiviewMode multiview_mode;
478   GstVideoMultiviewFlags multiview_flags;
479
480   /* protected streams */
481   gboolean protected;
482   guint32 protection_scheme_type;
483   guint32 protection_scheme_version;
484   gpointer protection_scheme_info;      /* specific to the protection scheme */
485   GQueue protection_scheme_event_queue;
486
487   gint ref_count;               /* atomic */
488 };
489
490 /* Contains properties and cryptographic info for a set of samples from a
491  * track protected using Common Encryption (cenc) */
492 struct _QtDemuxCencSampleSetInfo
493 {
494   GstStructure *default_properties;
495
496   /* @crypto_info holds one GstStructure per sample */
497   GPtrArray *crypto_info;
498 };
499
500 static const gchar *
501 qt_demux_state_string (enum QtDemuxState state)
502 {
503   switch (state) {
504     case QTDEMUX_STATE_INITIAL:
505       return "<INITIAL>";
506     case QTDEMUX_STATE_HEADER:
507       return "<HEADER>";
508     case QTDEMUX_STATE_MOVIE:
509       return "<MOVIE>";
510     case QTDEMUX_STATE_BUFFER_MDAT:
511       return "<BUFFER_MDAT>";
512     default:
513       return "<UNKNOWN>";
514   }
515 }
516
517 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
518 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
519     guint32 fourcc, GstByteReader * parser);
520 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
521 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
522     guint32 fourcc, GstByteReader * parser);
523
524 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
525
526 static void gst_qtdemux_check_send_pending_segment (GstQTDemux * demux);
527
528 static GstStaticPadTemplate gst_qtdemux_sink_template =
529     GST_STATIC_PAD_TEMPLATE ("sink",
530     GST_PAD_SINK,
531     GST_PAD_ALWAYS,
532     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
533         "application/x-3gp")
534     );
535
536 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
537 GST_STATIC_PAD_TEMPLATE ("video_%u",
538     GST_PAD_SRC,
539     GST_PAD_SOMETIMES,
540     GST_STATIC_CAPS_ANY);
541
542 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
543 GST_STATIC_PAD_TEMPLATE ("audio_%u",
544     GST_PAD_SRC,
545     GST_PAD_SOMETIMES,
546     GST_STATIC_CAPS_ANY);
547
548 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
549 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
550     GST_PAD_SRC,
551     GST_PAD_SOMETIMES,
552     GST_STATIC_CAPS_ANY);
553
554 #define gst_qtdemux_parent_class parent_class
555 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
556
557 static void gst_qtdemux_dispose (GObject * object);
558
559 static guint32
560 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
561     GstClockTime media_time);
562 static guint32
563 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
564     QtDemuxStream * str, gint64 media_offset);
565
566 #if 0
567 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
568 static GstIndex *gst_qtdemux_get_index (GstElement * element);
569 #endif
570 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
571     GstStateChange transition);
572 static void gst_qtdemux_set_context (GstElement * element,
573     GstContext * context);
574 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
575 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
576     GstObject * parent, GstPadMode mode, gboolean active);
577
578 static void gst_qtdemux_loop (GstPad * pad);
579 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
580     GstBuffer * inbuf);
581 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
582     GstEvent * event);
583 static gboolean gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
584     GstQuery * query);
585 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
586 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
587     QtDemuxStream * stream);
588 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
589     QtDemuxStream * stream);
590 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
591     gboolean force);
592
593 static void gst_qtdemux_check_seekability (GstQTDemux * demux);
594
595 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
596     const guint8 * buffer, guint length);
597 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
598     const guint8 * buffer, guint length);
599 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
600 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
601     GNode * udta);
602
603 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
604     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
605     GstTagList * list);
606 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
607     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
608     const guint8 * stsd_entry_data, gchar ** codec_name);
609 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
610     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
611     const guint8 * data, int len, gchar ** codec_name);
612 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
613     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
614     gchar ** codec_name);
615 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
616     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
617     const guint8 * stsd_entry_data, gchar ** codec_name);
618
619 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
620     QtDemuxStream * stream, guint32 n);
621 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
622 static QtDemuxStream *gst_qtdemux_stream_ref (QtDemuxStream * stream);
623 static void gst_qtdemux_stream_unref (QtDemuxStream * stream);
624 static void gst_qtdemux_stream_clear (QtDemuxStream * stream);
625 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
626 static void qtdemux_do_allocation (QtDemuxStream * stream,
627     GstQTDemux * qtdemux);
628 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
629     QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
630 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
631     QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
632     GstClockTime * _start, GstClockTime * _stop);
633 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
634     QtDemuxStream * stream, gint segment_index, GstClockTime pos);
635
636 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
637 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
638
639 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
640
641 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
642     QtDemuxStream * stream, guint sample_index);
643 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
644     const gchar * id);
645 static void qtdemux_gst_structure_free (GstStructure * gststructure);
646 static void gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard);
647
648 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
649 static void gst_tag_register_spherical_tags (void);
650 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
651
652 static void
653 gst_qtdemux_class_init (GstQTDemuxClass * klass)
654 {
655   GObjectClass *gobject_class;
656   GstElementClass *gstelement_class;
657
658   gobject_class = (GObjectClass *) klass;
659   gstelement_class = (GstElementClass *) klass;
660
661   parent_class = g_type_class_peek_parent (klass);
662
663   gobject_class->dispose = gst_qtdemux_dispose;
664
665   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
666 #if 0
667   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
668   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
669 #endif
670   gstelement_class->set_context = GST_DEBUG_FUNCPTR (gst_qtdemux_set_context);
671
672   gst_tag_register_musicbrainz_tags ();
673
674 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
675   gst_tag_register_spherical_tags ();
676 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
677
678   gst_element_class_add_static_pad_template (gstelement_class,
679       &gst_qtdemux_sink_template);
680   gst_element_class_add_static_pad_template (gstelement_class,
681       &gst_qtdemux_videosrc_template);
682   gst_element_class_add_static_pad_template (gstelement_class,
683       &gst_qtdemux_audiosrc_template);
684   gst_element_class_add_static_pad_template (gstelement_class,
685       &gst_qtdemux_subsrc_template);
686   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
687       "Codec/Demuxer",
688       "Demultiplex a QuickTime file into audio and video streams",
689       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
690
691   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
692   gst_riff_init ();
693 }
694
695 static void
696 gst_qtdemux_init (GstQTDemux * qtdemux)
697 {
698   qtdemux->sinkpad =
699       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
700   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
701   gst_pad_set_activatemode_function (qtdemux->sinkpad,
702       qtdemux_sink_activate_mode);
703   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
704   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
705   gst_pad_set_query_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_query);
706   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
707
708   qtdemux->adapter = gst_adapter_new ();
709   g_queue_init (&qtdemux->protection_event_queue);
710   qtdemux->flowcombiner = gst_flow_combiner_new ();
711   g_mutex_init (&qtdemux->expose_lock);
712
713   qtdemux->active_streams = g_ptr_array_new_with_free_func
714       ((GDestroyNotify) gst_qtdemux_stream_unref);
715   qtdemux->old_streams = g_ptr_array_new_with_free_func
716       ((GDestroyNotify) gst_qtdemux_stream_unref);
717
718 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
719   qtdemux->spherical_metadata = (QtDemuxSphericalMetadata *)
720       malloc (sizeof (QtDemuxSphericalMetadata));
721
722   if (qtdemux->spherical_metadata) {
723     qtdemux->spherical_metadata->is_spherical = FALSE;
724     qtdemux->spherical_metadata->is_stitched = FALSE;
725     qtdemux->spherical_metadata->stitching_software = NULL;
726     qtdemux->spherical_metadata->projection_type = NULL;
727     qtdemux->spherical_metadata->stereo_mode = NULL;
728     qtdemux->spherical_metadata->source_count = 0;
729     qtdemux->spherical_metadata->init_view_heading = 0;
730     qtdemux->spherical_metadata->init_view_pitch = 0;
731     qtdemux->spherical_metadata->init_view_roll = 0;
732     qtdemux->spherical_metadata->timestamp = 0;
733     qtdemux->spherical_metadata->full_pano_width_pixels = 0;
734     qtdemux->spherical_metadata->full_pano_height_pixels = 0;
735     qtdemux->spherical_metadata->cropped_area_image_width = 0;
736     qtdemux->spherical_metadata->cropped_area_image_height = 0;
737     qtdemux->spherical_metadata->cropped_area_left = 0;
738     qtdemux->spherical_metadata->cropped_area_top = 0;
739     qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
740     qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_UNKNOWN;
741     qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_UNKNOWN;
742   }
743 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
744
745   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
746
747   gst_qtdemux_reset (qtdemux, TRUE);
748 }
749
750 static void
751 gst_qtdemux_dispose (GObject * object)
752 {
753   GstQTDemux *qtdemux = GST_QTDEMUX (object);
754
755 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
756   if (qtdemux->spherical_metadata) {
757     if (qtdemux->spherical_metadata->stitching_software)
758       free(qtdemux->spherical_metadata->stitching_software);
759     if (qtdemux->spherical_metadata->projection_type)
760       free(qtdemux->spherical_metadata->projection_type);
761     if (qtdemux->spherical_metadata->stereo_mode)
762       free(qtdemux->spherical_metadata->stereo_mode);
763
764     free(qtdemux->spherical_metadata);
765     qtdemux->spherical_metadata = NULL;
766   }
767 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
768
769   if (qtdemux->adapter) {
770     g_object_unref (G_OBJECT (qtdemux->adapter));
771     qtdemux->adapter = NULL;
772   }
773   gst_tag_list_unref (qtdemux->tag_list);
774   gst_flow_combiner_free (qtdemux->flowcombiner);
775   g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
776       NULL);
777   g_queue_clear (&qtdemux->protection_event_queue);
778
779   g_free (qtdemux->cenc_aux_info_sizes);
780   qtdemux->cenc_aux_info_sizes = NULL;
781   g_mutex_clear (&qtdemux->expose_lock);
782
783   g_ptr_array_free (qtdemux->active_streams, TRUE);
784   g_ptr_array_free (qtdemux->old_streams, TRUE);
785
786   G_OBJECT_CLASS (parent_class)->dispose (object);
787 }
788
789 static void
790 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
791 {
792   if (qtdemux->posted_redirect) {
793     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
794         (_("This file contains no playable streams.")),
795         ("no known streams found, a redirect message has been posted"));
796   } else {
797     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
798         (_("This file contains no playable streams.")),
799         ("no known streams found"));
800   }
801 }
802
803 static GstBuffer *
804 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
805 {
806   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
807       mem, size, 0, size, mem, free_func);
808 }
809
810 static GstFlowReturn
811 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
812     GstBuffer ** buf)
813 {
814   GstFlowReturn flow;
815   GstMapInfo map;
816   gsize bsize;
817
818   if (G_UNLIKELY (size == 0)) {
819     GstFlowReturn ret;
820     GstBuffer *tmp = NULL;
821
822     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
823     if (ret != GST_FLOW_OK)
824       return ret;
825
826     gst_buffer_map (tmp, &map, GST_MAP_READ);
827     size = QT_UINT32 (map.data);
828     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
829
830     gst_buffer_unmap (tmp, &map);
831     gst_buffer_unref (tmp);
832   }
833
834   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
835   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
836     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
837       /* we're pulling header but already got most interesting bits,
838        * so never mind the rest (e.g. tags) (that much) */
839       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
840           size);
841       return GST_FLOW_EOS;
842     } else {
843       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
844           (_("This file is invalid and cannot be played.")),
845           ("atom has bogus size %" G_GUINT64_FORMAT, size));
846       return GST_FLOW_ERROR;
847     }
848   }
849
850   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
851
852   if (G_UNLIKELY (flow != GST_FLOW_OK))
853     return flow;
854
855   bsize = gst_buffer_get_size (*buf);
856   /* Catch short reads - we don't want any partial atoms */
857   if (G_UNLIKELY (bsize < size)) {
858     GST_WARNING_OBJECT (qtdemux,
859         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
860     gst_buffer_unref (*buf);
861     *buf = NULL;
862     return GST_FLOW_EOS;
863   }
864
865   return flow;
866 }
867
868 #if 1
869 static gboolean
870 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
871     GstFormat src_format, gint64 src_value, GstFormat dest_format,
872     gint64 * dest_value)
873 {
874   gboolean res = TRUE;
875   QtDemuxStream *stream = gst_pad_get_element_private (pad);
876   gint32 index;
877
878   if (stream->subtype != FOURCC_vide) {
879     res = FALSE;
880     goto done;
881   }
882
883   switch (src_format) {
884     case GST_FORMAT_TIME:
885       switch (dest_format) {
886         case GST_FORMAT_BYTES:{
887           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
888           if (-1 == index) {
889             res = FALSE;
890             goto done;
891           }
892
893           *dest_value = stream->samples[index].offset;
894
895           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
896               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
897               GST_TIME_ARGS (src_value), *dest_value);
898           break;
899         }
900         default:
901           res = FALSE;
902           break;
903       }
904       break;
905     case GST_FORMAT_BYTES:
906       switch (dest_format) {
907         case GST_FORMAT_TIME:{
908           index =
909               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
910               stream, src_value);
911
912           if (-1 == index) {
913             res = FALSE;
914             goto done;
915           }
916
917           *dest_value =
918               QTSTREAMTIME_TO_GSTTIME (stream,
919               stream->samples[index].timestamp);
920           GST_DEBUG_OBJECT (qtdemux,
921               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
922               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
923           break;
924         }
925         default:
926           res = FALSE;
927           break;
928       }
929       break;
930     default:
931       res = FALSE;
932       break;
933   }
934
935 done:
936   return res;
937 }
938 #endif
939
940 static gboolean
941 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
942 {
943   gboolean res = FALSE;
944
945   *duration = GST_CLOCK_TIME_NONE;
946
947   if (qtdemux->duration != 0 &&
948       qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
949     *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
950     res = TRUE;
951   } else {
952     *duration = GST_CLOCK_TIME_NONE;
953   }
954
955   return res;
956 }
957
958 static gboolean
959 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
960     GstQuery * query)
961 {
962   gboolean res = FALSE;
963   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
964
965   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
966
967   switch (GST_QUERY_TYPE (query)) {
968     case GST_QUERY_POSITION:{
969       GstFormat fmt;
970
971       gst_query_parse_position (query, &fmt, NULL);
972       if (fmt == GST_FORMAT_TIME
973           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
974         gst_query_set_position (query, GST_FORMAT_TIME,
975             qtdemux->segment.position);
976         res = TRUE;
977       }
978     }
979       break;
980     case GST_QUERY_DURATION:{
981       GstFormat fmt;
982
983       gst_query_parse_duration (query, &fmt, NULL);
984       if (fmt == GST_FORMAT_TIME) {
985         /* First try to query upstream */
986         res = gst_pad_query_default (pad, parent, query);
987         if (!res) {
988           GstClockTime duration;
989           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
990             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
991             res = TRUE;
992           }
993         }
994       }
995       break;
996     }
997     case GST_QUERY_CONVERT:{
998       GstFormat src_fmt, dest_fmt;
999       gint64 src_value, dest_value = 0;
1000
1001       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
1002
1003       res = gst_qtdemux_src_convert (qtdemux, pad,
1004           src_fmt, src_value, dest_fmt, &dest_value);
1005       if (res)
1006         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
1007
1008       break;
1009     }
1010     case GST_QUERY_FORMATS:
1011       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
1012       res = TRUE;
1013       break;
1014     case GST_QUERY_SEEKING:{
1015       GstFormat fmt;
1016       gboolean seekable;
1017
1018       /* try upstream first */
1019       res = gst_pad_query_default (pad, parent, query);
1020
1021       if (!res) {
1022         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1023         if (fmt == GST_FORMAT_TIME) {
1024           GstClockTime duration;
1025
1026           gst_qtdemux_get_duration (qtdemux, &duration);
1027           seekable = TRUE;
1028           if (!qtdemux->pullbased) {
1029             GstQuery *q;
1030
1031             /* we might be able with help from upstream */
1032             seekable = FALSE;
1033             q = gst_query_new_seeking (GST_FORMAT_BYTES);
1034             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
1035               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
1036               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
1037             }
1038             gst_query_unref (q);
1039           }
1040           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
1041           res = TRUE;
1042         }
1043       }
1044       break;
1045     }
1046     case GST_QUERY_SEGMENT:
1047     {
1048       GstFormat format;
1049       gint64 start, stop;
1050
1051       format = qtdemux->segment.format;
1052
1053       start =
1054           gst_segment_to_stream_time (&qtdemux->segment, format,
1055           qtdemux->segment.start);
1056       if ((stop = qtdemux->segment.stop) == -1)
1057         stop = qtdemux->segment.duration;
1058       else
1059         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
1060
1061       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
1062       res = TRUE;
1063       break;
1064     }
1065     default:
1066       res = gst_pad_query_default (pad, parent, query);
1067       break;
1068   }
1069
1070   return res;
1071 }
1072
1073 static void
1074 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
1075 {
1076   if (G_LIKELY (stream->pad)) {
1077     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
1078         GST_DEBUG_PAD_NAME (stream->pad));
1079
1080     if (!gst_tag_list_is_empty (stream->stream_tags)) {
1081       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
1082           stream->stream_tags);
1083       gst_pad_push_event (stream->pad,
1084           gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
1085 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
1086       /* post message qtdemux tag (for early recive application) */
1087       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1088             gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
1089                   gst_tag_list_copy (stream->stream_tags)));
1090 #endif
1091     }
1092
1093     if (G_UNLIKELY (stream->send_global_tags)) {
1094       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1095           qtdemux->tag_list);
1096       gst_pad_push_event (stream->pad,
1097           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1098       stream->send_global_tags = FALSE;
1099     }
1100   }
1101 }
1102
1103 /* push event on all source pads; takes ownership of the event */
1104 static void
1105 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1106 {
1107   gboolean has_valid_stream = FALSE;
1108   GstEventType etype = GST_EVENT_TYPE (event);
1109   guint i;
1110
1111   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1112       GST_EVENT_TYPE_NAME (event));
1113
1114   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1115     GstPad *pad;
1116     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1117     GST_DEBUG_OBJECT (qtdemux, "pushing on track-id %u", stream->track_id);
1118
1119     if ((pad = stream->pad)) {
1120       has_valid_stream = TRUE;
1121
1122       if (etype == GST_EVENT_EOS) {
1123         /* let's not send twice */
1124         if (stream->sent_eos)
1125           continue;
1126         stream->sent_eos = TRUE;
1127       }
1128
1129       gst_pad_push_event (pad, gst_event_ref (event));
1130     }
1131   }
1132
1133   gst_event_unref (event);
1134
1135   /* if it is EOS and there are no pads, post an error */
1136   if (!has_valid_stream && etype == GST_EVENT_EOS) {
1137     gst_qtdemux_post_no_playable_stream_error (qtdemux);
1138   }
1139 }
1140
1141 typedef struct
1142 {
1143   guint64 media_time;
1144 } FindData;
1145
1146 static gint
1147 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1148 {
1149   if ((gint64) s1->timestamp > *media_time)
1150     return 1;
1151   if ((gint64) s1->timestamp == *media_time)
1152     return 0;
1153
1154   return -1;
1155 }
1156
1157 /* find the index of the sample that includes the data for @media_time using a
1158  * binary search.  Only to be called in optimized cases of linear search below.
1159  *
1160  * Returns the index of the sample with the corresponding *DTS*.
1161  */
1162 static guint32
1163 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1164     guint64 media_time)
1165 {
1166   QtDemuxSample *result;
1167   guint32 index;
1168
1169   /* convert media_time to mov format */
1170   media_time =
1171       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1172
1173   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1174       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1175       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1176
1177   if (G_LIKELY (result))
1178     index = result - str->samples;
1179   else
1180     index = 0;
1181
1182   return index;
1183 }
1184
1185
1186
1187 /* find the index of the sample that includes the data for @media_offset using a
1188  * linear search
1189  *
1190  * Returns the index of the sample.
1191  */
1192 static guint32
1193 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1194     QtDemuxStream * str, gint64 media_offset)
1195 {
1196   QtDemuxSample *result = str->samples;
1197   guint32 index = 0;
1198
1199   if (result == NULL || str->n_samples == 0)
1200     return -1;
1201
1202   if (media_offset == result->offset)
1203     return index;
1204
1205   result++;
1206   while (index < str->n_samples - 1) {
1207     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1208       goto parse_failed;
1209
1210     if (media_offset < result->offset)
1211       break;
1212
1213     index++;
1214     result++;
1215   }
1216   return index;
1217
1218   /* ERRORS */
1219 parse_failed:
1220   {
1221     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1222     return -1;
1223   }
1224 }
1225
1226 /* find the index of the sample that includes the data for @media_time using a
1227  * linear search, and keeping in mind that not all samples may have been parsed
1228  * yet.  If possible, it will delegate to binary search.
1229  *
1230  * Returns the index of the sample.
1231  */
1232 static guint32
1233 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1234     GstClockTime media_time)
1235 {
1236   guint32 index = 0;
1237   guint64 mov_time;
1238   QtDemuxSample *sample;
1239
1240   /* convert media_time to mov format */
1241   mov_time =
1242       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1243
1244   sample = str->samples;
1245   if (mov_time == sample->timestamp + sample->pts_offset)
1246     return index;
1247
1248   /* use faster search if requested time in already parsed range */
1249   sample = str->samples + str->stbl_index;
1250   if (str->stbl_index >= 0 && mov_time <= sample->timestamp) {
1251     index = gst_qtdemux_find_index (qtdemux, str, media_time);
1252     sample = str->samples + index;
1253   } else {
1254     while (index < str->n_samples - 1) {
1255       if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1256         goto parse_failed;
1257
1258       sample = str->samples + index + 1;
1259       if (mov_time < sample->timestamp) {
1260         sample = str->samples + index;
1261         break;
1262       }
1263
1264       index++;
1265     }
1266   }
1267
1268   /* sample->timestamp is now <= media_time, need to find the corresponding
1269    * PTS now by looking backwards */
1270   while (index > 0 && sample->timestamp + sample->pts_offset > mov_time) {
1271     index--;
1272     sample = str->samples + index;
1273   }
1274
1275   return index;
1276
1277   /* ERRORS */
1278 parse_failed:
1279   {
1280     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1281     return -1;
1282   }
1283 }
1284
1285 /* find the index of the keyframe needed to decode the sample at @index
1286  * of stream @str, or of a subsequent keyframe (depending on @next)
1287  *
1288  * Returns the index of the keyframe.
1289  */
1290 static guint32
1291 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1292     guint32 index, gboolean next)
1293 {
1294   guint32 new_index = index;
1295
1296   if (index >= str->n_samples) {
1297     new_index = str->n_samples;
1298     goto beach;
1299   }
1300
1301   /* all keyframes, return index */
1302   if (str->all_keyframe) {
1303     new_index = index;
1304     goto beach;
1305   }
1306
1307   /* else search until we have a keyframe */
1308   while (new_index < str->n_samples) {
1309     if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1310       goto parse_failed;
1311
1312     if (str->samples[new_index].keyframe)
1313       break;
1314
1315     if (new_index == 0)
1316       break;
1317
1318     if (next)
1319       new_index++;
1320     else
1321       new_index--;
1322   }
1323
1324   if (new_index == str->n_samples) {
1325     GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1326     new_index = -1;
1327   }
1328
1329 beach:
1330   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1331       "gave %u", next ? "after" : "before", index, new_index);
1332
1333   return new_index;
1334
1335   /* ERRORS */
1336 parse_failed:
1337   {
1338     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1339     return -1;
1340   }
1341 }
1342
1343 /* find the segment for @time_position for @stream
1344  *
1345  * Returns the index of the segment containing @time_position.
1346  * Returns the last segment and sets the @eos variable to TRUE
1347  * if the time is beyond the end. @eos may be NULL
1348  */
1349 static guint32
1350 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1351     GstClockTime time_position)
1352 {
1353   gint i;
1354   guint32 seg_idx;
1355
1356   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1357       GST_TIME_ARGS (time_position));
1358
1359   seg_idx = -1;
1360   for (i = 0; i < stream->n_segments; i++) {
1361     QtDemuxSegment *segment = &stream->segments[i];
1362
1363     GST_LOG_OBJECT (stream->pad,
1364         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1365         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1366
1367     /* For the last segment we include stop_time in the last segment */
1368     if (i < stream->n_segments - 1) {
1369       if (segment->time <= time_position && time_position < segment->stop_time) {
1370         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1371         seg_idx = i;
1372         break;
1373       }
1374     } else {
1375       /* Last segment always matches */
1376       seg_idx = i;
1377       break;
1378     }
1379   }
1380   return seg_idx;
1381 }
1382
1383 /* move the stream @str to the sample position @index.
1384  *
1385  * Updates @str->sample_index and marks discontinuity if needed.
1386  */
1387 static void
1388 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1389     guint32 index)
1390 {
1391   /* no change needed */
1392   if (index == str->sample_index)
1393     return;
1394
1395   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1396       str->n_samples);
1397
1398   /* position changed, we have a discont */
1399   str->sample_index = index;
1400   str->offset_in_sample = 0;
1401   /* Each time we move in the stream we store the position where we are
1402    * starting from */
1403   str->from_sample = index;
1404   str->discont = TRUE;
1405 }
1406
1407 static void
1408 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1409     gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1410 {
1411   guint64 min_offset;
1412   gint64 min_byte_offset = -1;
1413   guint i;
1414
1415   min_offset = desired_time;
1416
1417   /* for each stream, find the index of the sample in the segment
1418    * and move back to the previous keyframe. */
1419   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1420     QtDemuxStream *str;
1421     guint32 index, kindex;
1422     guint32 seg_idx;
1423     GstClockTime media_start;
1424     GstClockTime media_time;
1425     GstClockTime seg_time;
1426     QtDemuxSegment *seg;
1427     gboolean empty_segment = FALSE;
1428
1429     str = QTDEMUX_NTH_STREAM (qtdemux, i);
1430
1431     if (CUR_STREAM (str)->sparse && !use_sparse)
1432       continue;
1433
1434     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1435     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1436
1437     /* get segment and time in the segment */
1438     seg = &str->segments[seg_idx];
1439     seg_time = (desired_time - seg->time) * seg->rate;
1440
1441     while (QTSEGMENT_IS_EMPTY (seg)) {
1442       seg_time = 0;
1443       empty_segment = TRUE;
1444       GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1445           seg_idx);
1446       seg_idx++;
1447       if (seg_idx == str->n_segments)
1448         break;
1449       seg = &str->segments[seg_idx];
1450     }
1451
1452     if (seg_idx == str->n_segments) {
1453       /* FIXME track shouldn't have the last segment as empty, but if it
1454        * happens we better handle it */
1455       continue;
1456     }
1457
1458     /* get the media time in the segment */
1459     media_start = seg->media_start + seg_time;
1460
1461     /* get the index of the sample with media time */
1462     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1463     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1464         " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1465         GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1466         empty_segment);
1467
1468     /* shift to next frame if we are looking for next keyframe */
1469     if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1470         && index < str->stbl_index)
1471       index++;
1472
1473     if (!empty_segment) {
1474       /* find previous keyframe */
1475       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1476
1477       /* we will settle for one before if none found after */
1478       if (next && kindex == -1)
1479         kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1480
1481       /* if the keyframe is at a different position, we need to update the
1482        * requested seek time */
1483       if (index != kindex) {
1484         index = kindex;
1485
1486         /* get timestamp of keyframe */
1487         media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1488         GST_DEBUG_OBJECT (qtdemux,
1489             "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1490             G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1491             str->samples[kindex].offset);
1492
1493         /* keyframes in the segment get a chance to change the
1494          * desired_offset. keyframes out of the segment are
1495          * ignored. */
1496         if (media_time >= seg->media_start) {
1497           GstClockTime seg_time;
1498
1499           /* this keyframe is inside the segment, convert back to
1500            * segment time */
1501           seg_time = (media_time - seg->media_start) + seg->time;
1502           if ((!next && (seg_time < min_offset)) ||
1503               (next && (seg_time > min_offset)))
1504             min_offset = seg_time;
1505         }
1506       }
1507     }
1508
1509     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1510       min_byte_offset = str->samples[index].offset;
1511   }
1512
1513   if (key_time)
1514     *key_time = min_offset;
1515   if (key_offset)
1516     *key_offset = min_byte_offset;
1517 }
1518
1519 static gboolean
1520 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1521     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1522 {
1523   gboolean res;
1524
1525   g_return_val_if_fail (format != NULL, FALSE);
1526   g_return_val_if_fail (cur != NULL, FALSE);
1527   g_return_val_if_fail (stop != NULL, FALSE);
1528
1529   if (*format == GST_FORMAT_TIME)
1530     return TRUE;
1531
1532   res = TRUE;
1533   if (cur_type != GST_SEEK_TYPE_NONE)
1534     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1535   if (res && stop_type != GST_SEEK_TYPE_NONE)
1536     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1537
1538   if (res)
1539     *format = GST_FORMAT_TIME;
1540
1541   return res;
1542 }
1543
1544 /* perform seek in push based mode:
1545    find BYTE position to move to based on time and delegate to upstream
1546 */
1547 static gboolean
1548 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1549 {
1550   gdouble rate;
1551   GstFormat format;
1552   GstSeekFlags flags;
1553   GstSeekType cur_type, stop_type;
1554   gint64 cur, stop, key_cur;
1555   gboolean res;
1556   gint64 byte_cur;
1557   gint64 original_stop;
1558   guint32 seqnum;
1559
1560   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1561
1562   gst_event_parse_seek (event, &rate, &format, &flags,
1563       &cur_type, &cur, &stop_type, &stop);
1564   seqnum = gst_event_get_seqnum (event);
1565
1566   /* only forward streaming and seeking is possible */
1567   if (rate <= 0)
1568     goto unsupported_seek;
1569
1570   /* convert to TIME if needed and possible */
1571   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1572           stop_type, &stop))
1573     goto no_format;
1574
1575   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1576    * the original stop position to use when upstream pushes the new segment
1577    * for this seek */
1578   original_stop = stop;
1579   stop = -1;
1580
1581   /* find reasonable corresponding BYTE position,
1582    * also try to mind about keyframes, since we can not go back a bit for them
1583    * later on */
1584   /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1585    * mostly just work, but let's not yet boldly go there  ... */
1586   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1587
1588   if (byte_cur == -1)
1589     goto abort_seek;
1590
1591   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1592       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1593       stop);
1594
1595   GST_OBJECT_LOCK (qtdemux);
1596   qtdemux->seek_offset = byte_cur;
1597   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1598     qtdemux->push_seek_start = cur;
1599   } else {
1600     qtdemux->push_seek_start = key_cur;
1601   }
1602
1603   if (stop_type == GST_SEEK_TYPE_NONE) {
1604     qtdemux->push_seek_stop = qtdemux->segment.stop;
1605   } else {
1606     qtdemux->push_seek_stop = original_stop;
1607   }
1608   GST_OBJECT_UNLOCK (qtdemux);
1609
1610   qtdemux->segment_seqnum = seqnum;
1611   /* BYTE seek event */
1612   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1613       stop_type, stop);
1614   gst_event_set_seqnum (event, seqnum);
1615   res = gst_pad_push_event (qtdemux->sinkpad, event);
1616
1617   return res;
1618
1619   /* ERRORS */
1620 abort_seek:
1621   {
1622     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1623         "seek aborted.");
1624     return FALSE;
1625   }
1626 unsupported_seek:
1627   {
1628     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1629     return FALSE;
1630   }
1631 no_format:
1632   {
1633     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1634     return FALSE;
1635   }
1636 }
1637
1638 /* perform the seek.
1639  *
1640  * We set all segment_indexes in the streams to unknown and
1641  * adjust the time_position to the desired position. this is enough
1642  * to trigger a segment switch in the streaming thread to start
1643  * streaming from the desired position.
1644  *
1645  * Keyframe seeking is a little more complicated when dealing with
1646  * segments. Ideally we want to move to the previous keyframe in
1647  * the segment but there might not be a keyframe in the segment. In
1648  * fact, none of the segments could contain a keyframe. We take a
1649  * practical approach: seek to the previous keyframe in the segment,
1650  * if there is none, seek to the beginning of the segment.
1651  *
1652  * Called with STREAM_LOCK
1653  */
1654 static gboolean
1655 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1656     guint32 seqnum, GstSeekFlags flags)
1657 {
1658   gint64 desired_offset;
1659   guint i;
1660
1661   desired_offset = segment->position;
1662
1663   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1664       GST_TIME_ARGS (desired_offset));
1665
1666   /* may not have enough fragmented info to do this adjustment,
1667    * and we can't scan (and probably should not) at this time with
1668    * possibly flushing upstream */
1669   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1670     gint64 min_offset;
1671     gboolean next, before, after;
1672
1673     before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1674     after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1675     next = after && !before;
1676     if (segment->rate < 0)
1677       next = !next;
1678
1679     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1680         NULL);
1681     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1682         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1683     desired_offset = min_offset;
1684   }
1685
1686   /* and set all streams to the final position */
1687   gst_flow_combiner_reset (qtdemux->flowcombiner);
1688   qtdemux->segment_seqnum = seqnum;
1689   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1690     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1691
1692     stream->time_position = desired_offset;
1693     stream->accumulated_base = 0;
1694     stream->sample_index = -1;
1695     stream->offset_in_sample = 0;
1696     stream->segment_index = -1;
1697     stream->sent_eos = FALSE;
1698
1699     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1700       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1701   }
1702   segment->position = desired_offset;
1703   segment->time = desired_offset;
1704   if (segment->rate >= 0) {
1705     segment->start = desired_offset;
1706
1707     /* we stop at the end */
1708     if (segment->stop == -1)
1709       segment->stop = segment->duration;
1710   } else {
1711     segment->stop = desired_offset;
1712   }
1713
1714   if (qtdemux->fragmented)
1715     qtdemux->fragmented_seek_pending = TRUE;
1716
1717   return TRUE;
1718 }
1719
1720 /* do a seek in pull based mode */
1721 static gboolean
1722 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1723 {
1724   gdouble rate;
1725   GstFormat format;
1726   GstSeekFlags flags;
1727   GstSeekType cur_type, stop_type;
1728   gint64 cur, stop;
1729   gboolean flush;
1730   gboolean update;
1731   GstSegment seeksegment;
1732   guint32 seqnum = GST_SEQNUM_INVALID;
1733   GstEvent *flush_event;
1734   gboolean ret;
1735
1736   if (event) {
1737     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1738
1739     gst_event_parse_seek (event, &rate, &format, &flags,
1740         &cur_type, &cur, &stop_type, &stop);
1741     seqnum = gst_event_get_seqnum (event);
1742
1743     /* we have to have a format as the segment format. Try to convert
1744      * if not. */
1745     if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1746             stop_type, &stop))
1747       goto no_format;
1748
1749     GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1750   } else {
1751     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1752     flags = 0;
1753   }
1754
1755   flush = flags & GST_SEEK_FLAG_FLUSH;
1756
1757   /* stop streaming, either by flushing or by pausing the task */
1758   if (flush) {
1759     flush_event = gst_event_new_flush_start ();
1760     if (seqnum != GST_SEQNUM_INVALID)
1761       gst_event_set_seqnum (flush_event, seqnum);
1762     /* unlock upstream pull_range */
1763     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1764     /* make sure out loop function exits */
1765     gst_qtdemux_push_event (qtdemux, flush_event);
1766   } else {
1767     /* non flushing seek, pause the task */
1768     gst_pad_pause_task (qtdemux->sinkpad);
1769   }
1770
1771   /* wait for streaming to finish */
1772   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1773
1774   /* copy segment, we need this because we still need the old
1775    * segment when we close the current segment. */
1776   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1777
1778   if (event) {
1779     /* configure the segment with the seek variables */
1780     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1781     if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1782             cur_type, cur, stop_type, stop, &update)) {
1783       ret = FALSE;
1784       GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1785     } else {
1786       /* now do the seek */
1787       ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1788     }
1789   } else {
1790     /* now do the seek */
1791     ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1792   }
1793
1794   /* prepare for streaming again */
1795   if (flush) {
1796     flush_event = gst_event_new_flush_stop (TRUE);
1797     if (seqnum != GST_SEQNUM_INVALID)
1798       gst_event_set_seqnum (flush_event, seqnum);
1799
1800     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1801     gst_qtdemux_push_event (qtdemux, flush_event);
1802   }
1803
1804   /* commit the new segment */
1805   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1806
1807   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1808     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1809         qtdemux->segment.format, qtdemux->segment.position);
1810     if (seqnum != GST_SEQNUM_INVALID)
1811       gst_message_set_seqnum (msg, seqnum);
1812     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1813   }
1814
1815   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1816   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1817       qtdemux->sinkpad, NULL);
1818
1819   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1820
1821   return ret;
1822
1823   /* ERRORS */
1824 no_format:
1825   {
1826     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1827     return FALSE;
1828   }
1829 }
1830
1831 static gboolean
1832 qtdemux_ensure_index (GstQTDemux * qtdemux)
1833 {
1834   guint i;
1835
1836   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1837
1838   /* Build complete index */
1839   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
1840     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
1841
1842     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
1843       GST_LOG_OBJECT (qtdemux,
1844           "Building complete index of track-id %u for seeking failed!",
1845           stream->track_id);
1846       return FALSE;
1847     }
1848   }
1849
1850   return TRUE;
1851 }
1852
1853 static gboolean
1854 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1855     GstEvent * event)
1856 {
1857   gboolean res = TRUE;
1858   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1859
1860   switch (GST_EVENT_TYPE (event)) {
1861     case GST_EVENT_SEEK:
1862     {
1863 #ifndef GST_DISABLE_GST_DEBUG
1864       GstClockTime ts = gst_util_get_timestamp ();
1865 #endif
1866       guint32 seqnum = gst_event_get_seqnum (event);
1867
1868       qtdemux->received_seek = TRUE;
1869
1870       if (seqnum == qtdemux->segment_seqnum) {
1871         GST_LOG_OBJECT (pad,
1872             "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1873         gst_event_unref (event);
1874         return TRUE;
1875       }
1876
1877       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1878         /* seek should be handled by upstream, we might need to re-download fragments */
1879         GST_DEBUG_OBJECT (qtdemux,
1880             "let upstream handle seek for fragmented playback");
1881         goto upstream;
1882       }
1883
1884       /* Build complete index for seeking;
1885        * if not a fragmented file at least */
1886       if (!qtdemux->fragmented)
1887         if (!qtdemux_ensure_index (qtdemux))
1888           goto index_failed;
1889 #ifndef GST_DISABLE_GST_DEBUG
1890       ts = gst_util_get_timestamp () - ts;
1891       GST_INFO_OBJECT (qtdemux,
1892           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1893 #endif
1894     }
1895       if (qtdemux->pullbased) {
1896         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1897       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1898         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1899         res = TRUE;
1900       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE
1901           && QTDEMUX_N_STREAMS (qtdemux)
1902           && !qtdemux->fragmented) {
1903         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1904       } else {
1905         GST_DEBUG_OBJECT (qtdemux,
1906             "ignoring seek in push mode in current state");
1907         res = FALSE;
1908       }
1909       gst_event_unref (event);
1910       break;
1911     default:
1912     upstream:
1913       res = gst_pad_event_default (pad, parent, event);
1914       break;
1915   }
1916
1917 done:
1918   return res;
1919
1920   /* ERRORS */
1921 index_failed:
1922   {
1923     GST_ERROR_OBJECT (qtdemux, "Index failed");
1924     gst_event_unref (event);
1925     res = FALSE;
1926     goto done;
1927   }
1928 }
1929
1930 /* Find, for each track, the first sample in coding order that has a file offset >= @byte_pos.
1931  *
1932  * If @fw is false, the coding order is explored backwards.
1933  *
1934  * If @set is true, each stream will be moved to its matched sample, or EOS if no matching
1935  * sample is found for that track.
1936  *
1937  * The stream and sample index of the sample with the minimum offset in the direction explored
1938  * (see @fw) is returned in the output parameters @_stream and @_index respectively.
1939  *
1940  * @_time is set to the QTSAMPLE_PTS of the matched sample with the minimum QTSAMPLE_PTS in the
1941  * direction explored, which may not always match the QTSAMPLE_PTS of the sample returned in
1942  * @_stream and @_index. */
1943 static void
1944 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1945     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1946 {
1947   gint i, index;
1948   gint64 time, min_time;
1949   QtDemuxStream *stream;
1950   gint iter;
1951
1952   min_time = -1;
1953   stream = NULL;
1954   index = -1;
1955
1956   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
1957     QtDemuxStream *str;
1958     gint inc;
1959     gboolean set_sample;
1960
1961     str = QTDEMUX_NTH_STREAM (qtdemux, iter);
1962     set_sample = !set;
1963
1964     if (fw) {
1965       i = 0;
1966       inc = 1;
1967     } else {
1968       i = str->n_samples - 1;
1969       inc = -1;
1970     }
1971
1972     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1973       if (str->samples[i].size == 0)
1974         continue;
1975
1976       if (fw && (str->samples[i].offset < byte_pos))
1977         continue;
1978
1979       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1980         continue;
1981
1982       /* move stream to first available sample */
1983       if (set) {
1984         gst_qtdemux_move_stream (qtdemux, str, i);
1985         set_sample = TRUE;
1986       }
1987
1988       /* avoid index from sparse streams since they might be far away */
1989       if (!CUR_STREAM (str)->sparse) {
1990         /* determine min/max time */
1991         time = QTSAMPLE_PTS (str, &str->samples[i]);
1992         if (min_time == -1 || (!fw && time > min_time) ||
1993             (fw && time < min_time)) {
1994           min_time = time;
1995         }
1996
1997         /* determine stream with leading sample, to get its position */
1998         if (!stream ||
1999             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
2000             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
2001           stream = str;
2002           index = i;
2003         }
2004       }
2005       break;
2006     }
2007
2008     /* no sample for this stream, mark eos */
2009     if (!set_sample)
2010       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
2011   }
2012
2013   if (_time)
2014     *_time = min_time;
2015   if (_stream)
2016     *_stream = stream;
2017   if (_index)
2018     *_index = index;
2019 }
2020
2021 /* Copied from mpegtsbase code */
2022 /* FIXME: replace this function when we add new util function for stream-id creation */
2023 static gchar *
2024 _get_upstream_id (GstQTDemux * demux)
2025 {
2026   gchar *upstream_id = gst_pad_get_stream_id (demux->sinkpad);
2027
2028   if (!upstream_id) {
2029     /* Try to create one from the upstream URI, else use a randome number */
2030     GstQuery *query;
2031     gchar *uri = NULL;
2032
2033     /* Try to generate one from the URI query and
2034      * if it fails take a random number instead */
2035     query = gst_query_new_uri ();
2036     if (gst_element_query (GST_ELEMENT_CAST (demux), query)) {
2037       gst_query_parse_uri (query, &uri);
2038     }
2039
2040     if (uri) {
2041       GChecksum *cs;
2042
2043       /* And then generate an SHA256 sum of the URI */
2044       cs = g_checksum_new (G_CHECKSUM_SHA256);
2045       g_checksum_update (cs, (const guchar *) uri, strlen (uri));
2046       g_free (uri);
2047       upstream_id = g_strdup (g_checksum_get_string (cs));
2048       g_checksum_free (cs);
2049     } else {
2050       /* Just get some random number if the URI query fails */
2051       GST_FIXME_OBJECT (demux, "Creating random stream-id, consider "
2052           "implementing a deterministic way of creating a stream-id");
2053       upstream_id =
2054           g_strdup_printf ("%08x%08x%08x%08x", g_random_int (), g_random_int (),
2055           g_random_int (), g_random_int ());
2056     }
2057
2058     gst_query_unref (query);
2059   }
2060   return upstream_id;
2061 }
2062
2063 static QtDemuxStream *
2064 _create_stream (GstQTDemux * demux, guint32 track_id)
2065 {
2066   QtDemuxStream *stream;
2067   gchar *upstream_id;
2068
2069   stream = g_new0 (QtDemuxStream, 1);
2070   stream->demux = demux;
2071   stream->track_id = track_id;
2072   upstream_id = _get_upstream_id (demux);
2073   stream->stream_id = g_strdup_printf ("%s/%03u", upstream_id, track_id);
2074   g_free (upstream_id);
2075   /* new streams always need a discont */
2076   stream->discont = TRUE;
2077   /* we enable clipping for raw audio/video streams */
2078   stream->need_clip = FALSE;
2079   stream->need_process = FALSE;
2080   stream->segment_index = -1;
2081   stream->time_position = 0;
2082   stream->sample_index = -1;
2083   stream->offset_in_sample = 0;
2084   stream->new_stream = TRUE;
2085   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2086   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2087   stream->protected = FALSE;
2088   stream->protection_scheme_type = 0;
2089   stream->protection_scheme_version = 0;
2090   stream->protection_scheme_info = NULL;
2091   stream->n_samples_moof = 0;
2092   stream->duration_moof = 0;
2093   stream->duration_last_moof = 0;
2094   stream->alignment = 1;
2095   stream->stream_tags = gst_tag_list_new_empty ();
2096   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2097   g_queue_init (&stream->protection_scheme_event_queue);
2098   stream->ref_count = 1;
2099   /* consistent default for push based mode */
2100   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
2101   return stream;
2102 }
2103
2104 static gboolean
2105 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2106 {
2107   GstStructure *structure;
2108   const gchar *variant;
2109   const GstCaps *mediacaps = NULL;
2110
2111   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2112
2113   structure = gst_caps_get_structure (caps, 0);
2114   variant = gst_structure_get_string (structure, "variant");
2115
2116   if (variant && strcmp (variant, "mss-fragmented") == 0) {
2117     QtDemuxStream *stream;
2118     const GValue *value;
2119
2120     demux->fragmented = TRUE;
2121     demux->mss_mode = TRUE;
2122
2123     if (QTDEMUX_N_STREAMS (demux) > 1) {
2124       /* can't do this, we can only renegotiate for another mss format */
2125       return FALSE;
2126     }
2127
2128     value = gst_structure_get_value (structure, "media-caps");
2129     /* create stream */
2130     if (value) {
2131       const GValue *timescale_v;
2132
2133       /* TODO update when stream changes during playback */
2134
2135       if (QTDEMUX_N_STREAMS (demux) == 0) {
2136         stream = _create_stream (demux, 1);
2137         g_ptr_array_add (demux->active_streams, stream);
2138         /* mss has no stsd/stsd entry, use id 0 as default */
2139         stream->stsd_entries_length = 1;
2140         stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2141         stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2142       } else {
2143         stream = QTDEMUX_NTH_STREAM (demux, 0);
2144       }
2145
2146       timescale_v = gst_structure_get_value (structure, "timescale");
2147       if (timescale_v) {
2148         stream->timescale = g_value_get_uint64 (timescale_v);
2149       } else {
2150         /* default mss timescale */
2151         stream->timescale = 10000000;
2152       }
2153       demux->timescale = stream->timescale;
2154
2155       mediacaps = gst_value_get_caps (value);
2156       if (!CUR_STREAM (stream)->caps
2157           || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2158         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2159             mediacaps);
2160         stream->new_caps = TRUE;
2161       }
2162       gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2163       structure = gst_caps_get_structure (mediacaps, 0);
2164       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2165         stream->subtype = FOURCC_vide;
2166
2167         gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2168         gst_structure_get_int (structure, "height",
2169             &CUR_STREAM (stream)->height);
2170         gst_structure_get_fraction (structure, "framerate",
2171             &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2172       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2173         gint rate = 0;
2174         stream->subtype = FOURCC_soun;
2175         gst_structure_get_int (structure, "channels",
2176             &CUR_STREAM (stream)->n_channels);
2177         gst_structure_get_int (structure, "rate", &rate);
2178         CUR_STREAM (stream)->rate = rate;
2179       }
2180     }
2181     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2182   } else {
2183     demux->mss_mode = FALSE;
2184   }
2185
2186   return TRUE;
2187 }
2188
2189 static void
2190 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2191 {
2192   gint i;
2193
2194   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2195   gst_pad_stop_task (qtdemux->sinkpad);
2196
2197   if (hard || qtdemux->upstream_format_is_time) {
2198     qtdemux->state = QTDEMUX_STATE_INITIAL;
2199     qtdemux->neededbytes = 16;
2200     qtdemux->todrop = 0;
2201     qtdemux->pullbased = FALSE;
2202     qtdemux->posted_redirect = FALSE;
2203     qtdemux->first_mdat = -1;
2204     qtdemux->header_size = 0;
2205     qtdemux->mdatoffset = -1;
2206     qtdemux->restoredata_offset = -1;
2207     if (qtdemux->mdatbuffer)
2208       gst_buffer_unref (qtdemux->mdatbuffer);
2209     if (qtdemux->restoredata_buffer)
2210       gst_buffer_unref (qtdemux->restoredata_buffer);
2211     qtdemux->mdatbuffer = NULL;
2212     qtdemux->restoredata_buffer = NULL;
2213     qtdemux->mdatleft = 0;
2214     qtdemux->mdatsize = 0;
2215     if (qtdemux->comp_brands)
2216       gst_buffer_unref (qtdemux->comp_brands);
2217     qtdemux->comp_brands = NULL;
2218     qtdemux->last_moov_offset = -1;
2219     if (qtdemux->moov_node_compressed) {
2220       g_node_destroy (qtdemux->moov_node_compressed);
2221       if (qtdemux->moov_node)
2222         g_free (qtdemux->moov_node->data);
2223     }
2224     qtdemux->moov_node_compressed = NULL;
2225     if (qtdemux->moov_node)
2226       g_node_destroy (qtdemux->moov_node);
2227     qtdemux->moov_node = NULL;
2228     if (qtdemux->tag_list)
2229       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2230     qtdemux->tag_list = gst_tag_list_new_empty ();
2231     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2232 #if 0
2233     if (qtdemux->element_index)
2234       gst_object_unref (qtdemux->element_index);
2235     qtdemux->element_index = NULL;
2236 #endif
2237     qtdemux->major_brand = 0;
2238     qtdemux->upstream_format_is_time = FALSE;
2239     qtdemux->upstream_seekable = FALSE;
2240     qtdemux->upstream_size = 0;
2241
2242     qtdemux->fragment_start = -1;
2243     qtdemux->fragment_start_offset = -1;
2244     qtdemux->duration = 0;
2245     qtdemux->moof_offset = 0;
2246     qtdemux->chapters_track_id = 0;
2247     qtdemux->have_group_id = FALSE;
2248     qtdemux->group_id = G_MAXUINT;
2249
2250     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2251         NULL);
2252     g_queue_clear (&qtdemux->protection_event_queue);
2253
2254     qtdemux->received_seek = FALSE;
2255     qtdemux->first_moof_already_parsed = FALSE;
2256   }
2257   qtdemux->offset = 0;
2258   gst_adapter_clear (qtdemux->adapter);
2259   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2260   qtdemux->need_segment = TRUE;
2261
2262   if (hard) {
2263     qtdemux->segment_seqnum = GST_SEQNUM_INVALID;
2264     g_ptr_array_set_size (qtdemux->active_streams, 0);
2265     g_ptr_array_set_size (qtdemux->old_streams, 0);
2266     qtdemux->n_video_streams = 0;
2267     qtdemux->n_audio_streams = 0;
2268     qtdemux->n_sub_streams = 0;
2269     qtdemux->exposed = FALSE;
2270     qtdemux->fragmented = FALSE;
2271     qtdemux->mss_mode = FALSE;
2272     gst_caps_replace (&qtdemux->media_caps, NULL);
2273     qtdemux->timescale = 0;
2274     qtdemux->got_moov = FALSE;
2275     qtdemux->cenc_aux_info_offset = 0;
2276     qtdemux->cenc_aux_info_sizes = NULL;
2277     qtdemux->cenc_aux_sample_count = 0;
2278     if (qtdemux->protection_system_ids) {
2279       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2280       qtdemux->protection_system_ids = NULL;
2281     }
2282     qtdemux->streams_aware = GST_OBJECT_PARENT (qtdemux)
2283         && GST_OBJECT_FLAG_IS_SET (GST_OBJECT_PARENT (qtdemux),
2284         GST_BIN_FLAG_STREAMS_AWARE);
2285
2286     if (qtdemux->preferred_protection_system_id) {
2287       g_free (qtdemux->preferred_protection_system_id);
2288       qtdemux->preferred_protection_system_id = NULL;
2289     }
2290   } else if (qtdemux->mss_mode) {
2291     gst_flow_combiner_reset (qtdemux->flowcombiner);
2292     g_ptr_array_foreach (qtdemux->active_streams,
2293         (GFunc) gst_qtdemux_stream_clear, NULL);
2294   } else {
2295     gst_flow_combiner_reset (qtdemux->flowcombiner);
2296     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
2297       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
2298       stream->sent_eos = FALSE;
2299       stream->time_position = 0;
2300       stream->accumulated_base = 0;
2301     }
2302   }
2303 }
2304
2305
2306 /* Maps the @segment to the qt edts internal segments and pushes
2307  * the correspnding segment event.
2308  *
2309  * If it ends up being at a empty segment, a gap will be pushed and the next
2310  * edts segment will be activated in sequence.
2311  *
2312  * To be used in push-mode only */
2313 static void
2314 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2315 {
2316   gint i, iter;
2317
2318   for (iter = 0; iter < QTDEMUX_N_STREAMS (qtdemux); iter++) {
2319     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, iter);
2320
2321     stream->time_position = segment->start;
2322
2323     /* in push mode we should be guaranteed that we will have empty segments
2324      * at the beginning and then one segment after, other scenarios are not
2325      * supported and are discarded when parsing the edts */
2326     for (i = 0; i < stream->n_segments; i++) {
2327       if (stream->segments[i].stop_time > segment->start) {
2328         /* push the empty segment and move to the next one */
2329         gst_qtdemux_activate_segment (qtdemux, stream, i,
2330             stream->time_position);
2331         if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2332           gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2333               stream->time_position);
2334
2335           /* accumulate previous segments */
2336           if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
2337             stream->accumulated_base +=
2338                 (stream->segment.stop -
2339                 stream->segment.start) / ABS (stream->segment.rate);
2340           continue;
2341         }
2342
2343         g_assert (i == stream->n_segments - 1);
2344       }
2345     }
2346   }
2347 }
2348
2349 static void
2350 gst_qtdemux_stream_concat (GstQTDemux * qtdemux, GPtrArray * dest,
2351     GPtrArray * src)
2352 {
2353   guint i;
2354   guint len;
2355
2356   len = src->len;
2357
2358   if (len == 0)
2359     return;
2360
2361   for (i = 0; i < len; i++) {
2362     QtDemuxStream *stream = g_ptr_array_index (src, i);
2363
2364 #ifndef GST_DISABLE_GST_DEBUG
2365     GST_DEBUG_OBJECT (qtdemux, "Move stream %p (stream-id %s) to %p",
2366         stream, GST_STR_NULL (stream->stream_id), dest);
2367 #endif
2368     g_ptr_array_add (dest, gst_qtdemux_stream_ref (stream));
2369   }
2370
2371   g_ptr_array_set_size (src, 0);
2372 }
2373
2374 static gboolean
2375 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2376     GstEvent * event)
2377 {
2378   GstQTDemux *demux = GST_QTDEMUX (parent);
2379   gboolean res = TRUE;
2380
2381   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2382
2383   switch (GST_EVENT_TYPE (event)) {
2384     case GST_EVENT_SEGMENT:
2385     {
2386       gint64 offset = 0;
2387       QtDemuxStream *stream;
2388       gint idx;
2389       GstSegment segment;
2390
2391       /* some debug output */
2392       gst_event_copy_segment (event, &segment);
2393       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2394           &segment);
2395
2396       if (segment.format == GST_FORMAT_TIME) {
2397         demux->upstream_format_is_time = TRUE;
2398         demux->segment_seqnum = gst_event_get_seqnum (event);
2399       } else {
2400         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2401             "not in time format");
2402
2403         /* chain will send initial newsegment after pads have been added */
2404         if (demux->state != QTDEMUX_STATE_MOVIE || !QTDEMUX_N_STREAMS (demux)) {
2405           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2406           goto exit;
2407         }
2408       }
2409
2410       /* check if this matches a time seek we received previously
2411        * FIXME for backwards compatibility reasons we use the
2412        * seek_offset here to compare. In the future we might want to
2413        * change this to use the seqnum as it uniquely should identify
2414        * the segment that corresponds to the seek. */
2415       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2416           ", received segment offset %" G_GINT64_FORMAT,
2417           demux->seek_offset, segment.start);
2418       if (segment.format == GST_FORMAT_BYTES
2419           && demux->seek_offset == segment.start) {
2420         GST_OBJECT_LOCK (demux);
2421         offset = segment.start;
2422
2423         segment.format = GST_FORMAT_TIME;
2424         segment.start = demux->push_seek_start;
2425         segment.stop = demux->push_seek_stop;
2426         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2427             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2428             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2429         GST_OBJECT_UNLOCK (demux);
2430       }
2431
2432       /* we only expect a BYTE segment, e.g. following a seek */
2433       if (segment.format == GST_FORMAT_BYTES) {
2434         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2435           offset = segment.start;
2436
2437           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2438               NULL, (gint64 *) & segment.start);
2439           if ((gint64) segment.start < 0)
2440             segment.start = 0;
2441         }
2442         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2443           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2444               NULL, (gint64 *) & segment.stop);
2445           /* keyframe seeking should already arrange for start >= stop,
2446            * but make sure in other rare cases */
2447           segment.stop = MAX (segment.stop, segment.start);
2448         }
2449       } else if (segment.format == GST_FORMAT_TIME) {
2450         /* push all data on the adapter before starting this
2451          * new segment */
2452         gst_qtdemux_process_adapter (demux, TRUE);
2453       } else {
2454         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2455         goto exit;
2456       }
2457
2458       /* We shouldn't modify upstream driven TIME FORMAT segment */
2459       if (!demux->upstream_format_is_time) {
2460         /* accept upstream's notion of segment and distribute along */
2461         segment.format = GST_FORMAT_TIME;
2462         segment.position = segment.time = segment.start;
2463         segment.duration = demux->segment.duration;
2464         segment.base = gst_segment_to_running_time (&demux->segment,
2465             GST_FORMAT_TIME, demux->segment.position);
2466       }
2467
2468       gst_segment_copy_into (&segment, &demux->segment);
2469       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2470
2471       /* map segment to internal qt segments and push on each stream */
2472       if (QTDEMUX_N_STREAMS (demux)) {
2473         demux->need_segment = TRUE;
2474         gst_qtdemux_check_send_pending_segment (demux);
2475       }
2476
2477       /* clear leftover in current segment, if any */
2478       gst_adapter_clear (demux->adapter);
2479
2480       /* set up streaming thread */
2481       demux->offset = offset;
2482       if (demux->upstream_format_is_time) {
2483         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2484             "set values to restart reading from a new atom");
2485         demux->neededbytes = 16;
2486         demux->todrop = 0;
2487       } else {
2488         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2489             NULL);
2490         if (stream) {
2491           demux->todrop = stream->samples[idx].offset - offset;
2492           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2493         } else {
2494           /* set up for EOS */
2495           demux->neededbytes = -1;
2496           demux->todrop = 0;
2497         }
2498       }
2499     exit:
2500       gst_event_unref (event);
2501       res = TRUE;
2502       goto drop;
2503     }
2504     case GST_EVENT_FLUSH_START:
2505     {
2506       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2507         gst_event_unref (event);
2508         goto drop;
2509       }
2510       QTDEMUX_EXPOSE_LOCK (demux);
2511       res = gst_pad_event_default (demux->sinkpad, parent, event);
2512       QTDEMUX_EXPOSE_UNLOCK (demux);
2513       goto drop;
2514     }
2515     case GST_EVENT_FLUSH_STOP:
2516     {
2517       guint64 dur;
2518
2519       dur = demux->segment.duration;
2520       gst_qtdemux_reset (demux, FALSE);
2521       demux->segment.duration = dur;
2522
2523       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2524         gst_event_unref (event);
2525         goto drop;
2526       }
2527       break;
2528     }
2529     case GST_EVENT_EOS:
2530       /* If we are in push mode, and get an EOS before we've seen any streams,
2531        * then error out - we have nowhere to send the EOS */
2532       if (!demux->pullbased) {
2533         gint i;
2534         gboolean has_valid_stream = FALSE;
2535         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
2536           if (QTDEMUX_NTH_STREAM (demux, i)->pad != NULL) {
2537             has_valid_stream = TRUE;
2538             break;
2539           }
2540         }
2541         if (!has_valid_stream)
2542           gst_qtdemux_post_no_playable_stream_error (demux);
2543         else {
2544           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2545               (guint) gst_adapter_available (demux->adapter));
2546           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2547             res = FALSE;
2548           }
2549         }
2550       }
2551       break;
2552     case GST_EVENT_CAPS:{
2553       GstCaps *caps = NULL;
2554
2555       gst_event_parse_caps (event, &caps);
2556       gst_qtdemux_setcaps (demux, caps);
2557       res = TRUE;
2558       gst_event_unref (event);
2559       goto drop;
2560     }
2561     case GST_EVENT_PROTECTION:
2562     {
2563       const gchar *system_id = NULL;
2564
2565       gst_event_parse_protection (event, &system_id, NULL, NULL);
2566       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2567           system_id);
2568       gst_qtdemux_append_protection_system_id (demux, system_id);
2569       /* save the event for later, for source pads that have not been created */
2570       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2571       /* send it to all pads that already exist */
2572       gst_qtdemux_push_event (demux, event);
2573       res = TRUE;
2574       goto drop;
2575     }
2576     case GST_EVENT_STREAM_START:
2577     {
2578       res = TRUE;
2579       gst_event_unref (event);
2580
2581       /* Drain all the buffers */
2582       gst_qtdemux_process_adapter (demux, TRUE);
2583       gst_qtdemux_reset (demux, FALSE);
2584       /* We expect new moov box after new stream-start event */
2585       if (demux->exposed) {
2586         gst_qtdemux_stream_concat (demux,
2587             demux->old_streams, demux->active_streams);
2588       }
2589
2590       goto drop;
2591     }
2592     default:
2593       break;
2594   }
2595
2596   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2597
2598 drop:
2599   return res;
2600 }
2601
2602 static gboolean
2603 gst_qtdemux_handle_sink_query (GstPad * pad, GstObject * parent,
2604     GstQuery * query)
2605 {
2606   GstQTDemux *demux = GST_QTDEMUX (parent);
2607   gboolean res = FALSE;
2608
2609   switch (GST_QUERY_TYPE (query)) {
2610     case GST_QUERY_BITRATE:
2611     {
2612       GstClockTime duration;
2613
2614       /* populate demux->upstream_size if not done yet */
2615       gst_qtdemux_check_seekability (demux);
2616
2617       if (demux->upstream_size != -1
2618           && gst_qtdemux_get_duration (demux, &duration)) {
2619         guint bitrate =
2620             gst_util_uint64_scale (8 * demux->upstream_size, GST_SECOND,
2621             duration);
2622
2623         GST_LOG_OBJECT (demux, "bitrate query byte length: %" G_GUINT64_FORMAT
2624             " duration %" GST_TIME_FORMAT " resulting a bitrate of %u",
2625             demux->upstream_size, GST_TIME_ARGS (duration), bitrate);
2626
2627         /* TODO: better results based on ranges/index tables */
2628         gst_query_set_bitrate (query, bitrate);
2629         res = TRUE;
2630       }
2631       break;
2632     }
2633     default:
2634       res = gst_pad_query_default (pad, (GstObject *) demux, query);
2635       break;
2636   }
2637
2638   return res;
2639 }
2640
2641
2642 #if 0
2643 static void
2644 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2645 {
2646   GstQTDemux *demux = GST_QTDEMUX (element);
2647
2648   GST_OBJECT_LOCK (demux);
2649   if (demux->element_index)
2650     gst_object_unref (demux->element_index);
2651   if (index) {
2652     demux->element_index = gst_object_ref (index);
2653   } else {
2654     demux->element_index = NULL;
2655   }
2656   GST_OBJECT_UNLOCK (demux);
2657   /* object lock might be taken again */
2658   if (index)
2659     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2660   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2661       demux->element_index, demux->index_id);
2662 }
2663
2664 static GstIndex *
2665 gst_qtdemux_get_index (GstElement * element)
2666 {
2667   GstIndex *result = NULL;
2668   GstQTDemux *demux = GST_QTDEMUX (element);
2669
2670   GST_OBJECT_LOCK (demux);
2671   if (demux->element_index)
2672     result = gst_object_ref (demux->element_index);
2673   GST_OBJECT_UNLOCK (demux);
2674
2675   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2676
2677   return result;
2678 }
2679 #endif
2680
2681 static void
2682 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2683 {
2684   g_free ((gpointer) stream->stco.data);
2685   stream->stco.data = NULL;
2686   g_free ((gpointer) stream->stsz.data);
2687   stream->stsz.data = NULL;
2688   g_free ((gpointer) stream->stsc.data);
2689   stream->stsc.data = NULL;
2690   g_free ((gpointer) stream->stts.data);
2691   stream->stts.data = NULL;
2692   g_free ((gpointer) stream->stss.data);
2693   stream->stss.data = NULL;
2694   g_free ((gpointer) stream->stps.data);
2695   stream->stps.data = NULL;
2696   g_free ((gpointer) stream->ctts.data);
2697   stream->ctts.data = NULL;
2698 }
2699
2700 static void
2701 gst_qtdemux_stream_flush_segments_data (QtDemuxStream * stream)
2702 {
2703   g_free (stream->segments);
2704   stream->segments = NULL;
2705   stream->segment_index = -1;
2706   stream->accumulated_base = 0;
2707 }
2708
2709 static void
2710 gst_qtdemux_stream_flush_samples_data (QtDemuxStream * stream)
2711 {
2712   g_free (stream->samples);
2713   stream->samples = NULL;
2714   gst_qtdemux_stbl_free (stream);
2715
2716   /* fragments */
2717   g_free (stream->ra_entries);
2718   stream->ra_entries = NULL;
2719   stream->n_ra_entries = 0;
2720
2721   stream->sample_index = -1;
2722   stream->stbl_index = -1;
2723   stream->n_samples = 0;
2724   stream->time_position = 0;
2725
2726   stream->n_samples_moof = 0;
2727   stream->duration_moof = 0;
2728   stream->duration_last_moof = 0;
2729 }
2730
2731 static void
2732 gst_qtdemux_stream_clear (QtDemuxStream * stream)
2733 {
2734   gint i;
2735   if (stream->allocator)
2736     gst_object_unref (stream->allocator);
2737   while (stream->buffers) {
2738     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2739     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2740   }
2741   for (i = 0; i < stream->stsd_entries_length; i++) {
2742     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2743     if (entry->rgb8_palette) {
2744       gst_memory_unref (entry->rgb8_palette);
2745       entry->rgb8_palette = NULL;
2746     }
2747     entry->sparse = FALSE;
2748   }
2749
2750   if (stream->stream_tags)
2751     gst_tag_list_unref (stream->stream_tags);
2752
2753   stream->stream_tags = gst_tag_list_new_empty ();
2754   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2755   g_free (stream->redirect_uri);
2756   stream->redirect_uri = NULL;
2757   stream->sent_eos = FALSE;
2758   stream->protected = FALSE;
2759   if (stream->protection_scheme_info) {
2760     if (stream->protection_scheme_type == FOURCC_cenc) {
2761       QtDemuxCencSampleSetInfo *info =
2762           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2763       if (info->default_properties)
2764         gst_structure_free (info->default_properties);
2765       if (info->crypto_info)
2766         g_ptr_array_free (info->crypto_info, TRUE);
2767     }
2768     g_free (stream->protection_scheme_info);
2769     stream->protection_scheme_info = NULL;
2770   }
2771   stream->protection_scheme_type = 0;
2772   stream->protection_scheme_version = 0;
2773   g_queue_foreach (&stream->protection_scheme_event_queue,
2774       (GFunc) gst_event_unref, NULL);
2775   g_queue_clear (&stream->protection_scheme_event_queue);
2776   gst_qtdemux_stream_flush_segments_data (stream);
2777   gst_qtdemux_stream_flush_samples_data (stream);
2778 }
2779
2780 static void
2781 gst_qtdemux_stream_reset (QtDemuxStream * stream)
2782 {
2783   gint i;
2784   gst_qtdemux_stream_clear (stream);
2785   for (i = 0; i < stream->stsd_entries_length; i++) {
2786     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2787     if (entry->caps) {
2788       gst_caps_unref (entry->caps);
2789       entry->caps = NULL;
2790     }
2791   }
2792   g_free (stream->stsd_entries);
2793   stream->stsd_entries = NULL;
2794   stream->stsd_entries_length = 0;
2795 }
2796
2797 static QtDemuxStream *
2798 gst_qtdemux_stream_ref (QtDemuxStream * stream)
2799 {
2800   g_atomic_int_add (&stream->ref_count, 1);
2801
2802   return stream;
2803 }
2804
2805 static void
2806 gst_qtdemux_stream_unref (QtDemuxStream * stream)
2807 {
2808   if (g_atomic_int_dec_and_test (&stream->ref_count)) {
2809     gst_qtdemux_stream_reset (stream);
2810     gst_tag_list_unref (stream->stream_tags);
2811     if (stream->pad) {
2812       GstQTDemux *demux = stream->demux;
2813       gst_element_remove_pad (GST_ELEMENT_CAST (demux), stream->pad);
2814       gst_flow_combiner_remove_pad (demux->flowcombiner, stream->pad);
2815     }
2816     g_free (stream->stream_id);
2817     g_free (stream);
2818   }
2819 }
2820
2821 static GstStateChangeReturn
2822 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2823 {
2824   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2825   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2826
2827   switch (transition) {
2828     case GST_STATE_CHANGE_READY_TO_PAUSED:
2829       gst_qtdemux_reset (qtdemux, TRUE);
2830       break;
2831     default:
2832       break;
2833   }
2834
2835   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2836
2837   switch (transition) {
2838     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2839       gst_qtdemux_reset (qtdemux, TRUE);
2840       break;
2841     }
2842     default:
2843       break;
2844   }
2845
2846   return result;
2847 }
2848
2849 static void
2850 gst_qtdemux_set_context (GstElement * element, GstContext * context)
2851 {
2852   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2853
2854   g_return_if_fail (GST_IS_CONTEXT (context));
2855
2856   if (gst_context_has_context_type (context,
2857           "drm-preferred-decryption-system-id")) {
2858     const GstStructure *s;
2859
2860     s = gst_context_get_structure (context);
2861     g_free (qtdemux->preferred_protection_system_id);
2862     qtdemux->preferred_protection_system_id =
2863         g_strdup (gst_structure_get_string (s, "decryption-system-id"));
2864     GST_DEBUG_OBJECT (element, "set preferred decryption system to %s",
2865         qtdemux->preferred_protection_system_id);
2866   }
2867
2868   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
2869 }
2870
2871 static void
2872 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2873 {
2874   /* counts as header data */
2875   qtdemux->header_size += length;
2876
2877   /* only consider at least a sufficiently complete ftyp atom */
2878   if (length >= 20) {
2879     GstBuffer *buf;
2880
2881     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2882     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2883         GST_FOURCC_ARGS (qtdemux->major_brand));
2884     if (qtdemux->comp_brands)
2885       gst_buffer_unref (qtdemux->comp_brands);
2886     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2887     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2888   }
2889 }
2890
2891 static void
2892 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2893     GstTagList * xmptaglist)
2894 {
2895   /* Strip out bogus fields */
2896   if (xmptaglist) {
2897     if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2898       gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2899       gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2900     } else {
2901       gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2902     }
2903
2904     GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2905
2906     /* prioritize native tags using _KEEP mode */
2907     gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2908     gst_tag_list_unref (xmptaglist);
2909   }
2910 }
2911
2912 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
2913 static void
2914 _get_int_value_from_xml_string (GstQTDemux * qtdemux,
2915     const char *xml_str, const char *param_name, int *value)
2916 {
2917   char *value_start, *value_end, *endptr;
2918   const short value_length_max = 12;
2919   char init_view_ret[12];
2920   int value_length = 0;
2921   int i = 0;
2922
2923   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2924
2925   if (!value_start) {
2926     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2927         param_name);
2928     return;
2929   }
2930
2931   value_start += strlen (param_name);
2932   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2933     value_start++;
2934
2935   value_end = strchr (value_start, '<');
2936   if (!value_end) {
2937     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2938     return;
2939   }
2940
2941   value_length = value_end - value_start;
2942   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2943           || (value_start[value_length - 1] == '\t')))
2944     value_length--;
2945
2946   if (value_start[i] == '+' || value_start[i] == '-')
2947     i++;
2948   while (i < value_length) {
2949     if (value_start[i] < '0' || value_start[i] > '9') {
2950       GST_ERROR_OBJECT (qtdemux,
2951           "error: incorrect value, integer was expected\n");
2952       return;
2953     }
2954     i++;
2955   }
2956
2957   if (value_length >= value_length_max || value_length < 1) {
2958     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2959     return;
2960   }
2961
2962   strncpy (init_view_ret, value_start, value_length_max);
2963   init_view_ret[value_length] = '\0';
2964
2965   *value = strtol (init_view_ret, &endptr, 10);
2966   if (endptr == init_view_ret) {
2967     GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n");
2968     return;
2969   }
2970
2971   return;
2972 }
2973
2974 static void
2975 _get_string_value_from_xml_string (GstQTDemux * qtdemux,
2976     const char *xml_str, const char *param_name, char **value)
2977 {
2978   char *value_start, *value_end;
2979   const short value_length_max = 256;
2980   int value_length = 0;
2981
2982   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2983
2984   if (!value_start) {
2985     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2986         param_name);
2987     return;
2988   }
2989
2990   value_start += strlen (param_name);
2991   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2992     value_start++;
2993
2994   value_end = strchr (value_start, '<');
2995   if (!value_end) {
2996     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2997     return;
2998   }
2999
3000   value_length = value_end - value_start;
3001   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
3002           || (value_start[value_length - 1] == '\t')))
3003     value_length--;
3004
3005   if (value_length >= value_length_max || value_length < 1) {
3006     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
3007     return;
3008   }
3009
3010   *value = strndup(value_start, value_length);
3011
3012   return;
3013 }
3014
3015 static void
3016 _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
3017     const char *xml_str, const char *param_name, gboolean * value)
3018 {
3019   char *value_start, *value_end;
3020   int value_length = 0;
3021
3022   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
3023
3024   if (!value_start) {
3025     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
3026         param_name);
3027     return;
3028   }
3029
3030   value_start += strlen (param_name);
3031   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
3032     value_start++;
3033
3034   value_end = strchr (value_start, '<');
3035   if (!value_end) {
3036     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
3037     return;
3038   }
3039
3040   value_length = value_end - value_start;
3041   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
3042           || (value_start[value_length - 1] == '\t')))
3043     value_length--;
3044
3045   if (value_length < 1) {
3046     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
3047     return;
3048   }
3049
3050   *value = g_strstr_len(value_start, value_length, "true") ? TRUE : FALSE;
3051
3052   return;
3053 }
3054
3055 static void
3056 _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux, const char *xmlStr)
3057 {
3058   const char is_spherical_str[] = "<GSpherical:Spherical>";
3059   const char is_stitched_str[] = "<GSpherical:Stitched>";
3060   const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
3061   const char projection_type_str[] = "<GSpherical:ProjectionType>";
3062   const char stereo_mode_str[] = "<GSpherical:StereoMode>";
3063   const char source_count_str[] = "<GSpherical:SourceCount>";
3064   const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
3065   const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
3066   const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
3067   const char timestamp_str[] = "<GSpherical:Timestamp>";
3068   const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
3069   const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
3070   const char cropped_area_image_width_str[] =
3071       "<GSpherical:CroppedAreaImageWidthPixels>";
3072   const char cropped_area_image_height_str[] =
3073       "<GSpherical:CroppedAreaImageHeightPixels>";
3074   const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
3075   const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
3076
3077   QtDemuxSphericalMetadata * spherical_metadata = qtdemux->spherical_metadata;
3078
3079   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
3080       (gboolean *) & spherical_metadata->is_spherical);
3081   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
3082       (gboolean *) & spherical_metadata->is_stitched);
3083
3084   if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
3085     _get_string_value_from_xml_string (qtdemux, xmlStr,
3086         stitching_software_str, &spherical_metadata->stitching_software);
3087     _get_string_value_from_xml_string (qtdemux, xmlStr,
3088         projection_type_str, &spherical_metadata->projection_type);
3089     _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
3090         &spherical_metadata->stereo_mode);
3091     _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
3092         &spherical_metadata->source_count);
3093     _get_int_value_from_xml_string (qtdemux, xmlStr,
3094         init_view_heading_str, &spherical_metadata->init_view_heading);
3095     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
3096         &spherical_metadata->init_view_pitch);
3097     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
3098         &spherical_metadata->init_view_roll);
3099     _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
3100         &spherical_metadata->timestamp);
3101     _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
3102         &spherical_metadata->full_pano_width_pixels);
3103     _get_int_value_from_xml_string (qtdemux, xmlStr,
3104         full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
3105     _get_int_value_from_xml_string (qtdemux, xmlStr,
3106         cropped_area_image_width_str,
3107         &spherical_metadata->cropped_area_image_width);
3108     _get_int_value_from_xml_string (qtdemux, xmlStr,
3109         cropped_area_image_height_str,
3110         &spherical_metadata->cropped_area_image_height);
3111     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
3112         &spherical_metadata->cropped_area_left);
3113     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
3114         &spherical_metadata->cropped_area_top);
3115   }
3116
3117   return;
3118 }
3119
3120 static void
3121 gst_tag_register_spherical_tags (void) {
3122   gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
3123       G_TYPE_INT,
3124       _("tag-spherical"),
3125       _("Flag indicating if the video is a spherical video"),
3126       NULL);
3127   gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
3128       G_TYPE_INT,
3129       _("tag-stitched"),
3130       _("Flag indicating if the video is stitched"),
3131       NULL);
3132   gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
3133       G_TYPE_STRING,
3134       _("tag-stitching-software"),
3135       _("Software used to stitch the spherical video"),
3136       NULL);
3137   gst_tag_register ("projection_type", GST_TAG_FLAG_META,
3138       G_TYPE_STRING,
3139       _("tag-projection-type"),
3140       _("Projection type used in the video frames"),
3141       NULL);
3142   gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
3143       G_TYPE_STRING,
3144       _("tag-stereo-mode"),
3145       _("Description of stereoscopic 3D layout"),
3146       NULL);
3147   gst_tag_register ("source_count", GST_TAG_FLAG_META,
3148       G_TYPE_INT,
3149       _("tag-source-count"),
3150       _("Number of cameras used to create the spherical video"),
3151       NULL);
3152   gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
3153       G_TYPE_INT,
3154       _("tag-init-view-heading"),
3155       _("The heading angle of the initial view in degrees"),
3156       NULL);
3157   gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
3158       G_TYPE_INT,
3159       _("tag-init-view-pitch"),
3160       _("The pitch angle of the initial view in degrees"),
3161       NULL);
3162   gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
3163       G_TYPE_INT,
3164       _("tag-init-view-roll"),
3165       _("The roll angle of the initial view in degrees"),
3166       NULL);
3167   gst_tag_register ("timestamp", GST_TAG_FLAG_META,
3168       G_TYPE_INT,
3169       _("tag-timestamp"),
3170       _("Epoch timestamp of when the first frame in the video was recorded"),
3171       NULL);
3172   gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
3173       G_TYPE_INT,
3174       _("tag-full-pano-width"),
3175       _("Width of the encoded video frame in pixels"),
3176       NULL);
3177   gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
3178       G_TYPE_INT,
3179       _("tag-full-pano-height"),
3180       _("Height of the encoded video frame in pixels"),
3181       NULL);
3182   gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
3183       G_TYPE_INT,
3184       _("tag-cropped-area-image-width"),
3185       _("Width of the video frame to display (e.g. cropping)"),
3186       NULL);
3187   gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
3188       G_TYPE_INT,
3189       _("tag-cropped-area-image-height"),
3190       _("Height of the video frame to display (e.g. cropping)"),
3191       NULL);
3192   gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
3193       G_TYPE_INT,
3194       _("tag-cropped-area-left"),
3195       _("Column where the left edge of the image was cropped from the"
3196           " full sized panorama"),
3197       NULL);
3198   gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
3199       G_TYPE_INT,
3200       _("tag-cropped-area-top"),
3201       _("Row where the top edge of the image was cropped from the"
3202           " full sized panorama"),
3203       NULL);
3204   gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
3205       G_TYPE_INT,
3206       _("tag-ambisonic-type"),
3207       _("Specifies the type of ambisonic audio represented"),
3208       NULL);
3209   gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
3210       G_TYPE_INT,
3211       _("tag-ambisonic-format"),
3212       _("Specifies the ambisonic audio format"),
3213       NULL);
3214   gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
3215       G_TYPE_INT,
3216       _("tag-ambisonic-order"),
3217       _("Specifies the ambisonic audio channel order"),
3218       NULL);
3219
3220   return;
3221 }
3222
3223 static void
3224 _send_spherical_metadata_msg_to_bus (GstQTDemux * qtdemux)
3225 {
3226   GstTagList *taglist;
3227   QtDemuxSphericalMetadata *spherical_metadata = qtdemux->spherical_metadata;
3228
3229   GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
3230       spherical_metadata->is_spherical);
3231   GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
3232       spherical_metadata->is_stitched);
3233   GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
3234       spherical_metadata->stitching_software);
3235   GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
3236       spherical_metadata->projection_type);
3237   GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
3238       spherical_metadata->stereo_mode);
3239   GST_DEBUG_OBJECT (qtdemux, "source_count %d",
3240       spherical_metadata->source_count);
3241   GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
3242       spherical_metadata->init_view_heading);
3243   GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
3244       spherical_metadata->init_view_pitch);
3245   GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
3246       spherical_metadata->init_view_roll);
3247   GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
3248   GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
3249       spherical_metadata->full_pano_width_pixels);
3250   GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
3251       spherical_metadata->full_pano_height_pixels);
3252   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
3253       spherical_metadata->cropped_area_image_width);
3254   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
3255       spherical_metadata->cropped_area_image_height);
3256   GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
3257       spherical_metadata->cropped_area_left);
3258   GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
3259       spherical_metadata->cropped_area_top);
3260   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
3261       spherical_metadata->ambisonic_type);
3262   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
3263       spherical_metadata->ambisonic_order);
3264   GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
3265       spherical_metadata->ambisonic_format);
3266
3267   taglist = gst_tag_list_new_empty ();
3268   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3269       "is_spherical", spherical_metadata->is_spherical,
3270       "is_stitched", spherical_metadata->is_stitched,
3271       "source_count", spherical_metadata->source_count,
3272       "init_view_heading", spherical_metadata->init_view_heading,
3273       "init_view_pitch", spherical_metadata->init_view_pitch,
3274       "init_view_roll", spherical_metadata->init_view_roll,
3275       "timestamp", spherical_metadata->timestamp,
3276       "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
3277       "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
3278       "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
3279       "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
3280       "cropped_area_left", spherical_metadata->cropped_area_left,
3281       "cropped_area_top", spherical_metadata->cropped_area_top,
3282       "ambisonic_type", spherical_metadata->ambisonic_type,
3283       "ambisonic_format", spherical_metadata->ambisonic_format,
3284       "ambisonic_order", spherical_metadata->ambisonic_order,
3285       NULL);
3286
3287   if (spherical_metadata->stitching_software)
3288     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3289         "stitching_software", spherical_metadata->stitching_software,
3290         NULL);
3291   if (spherical_metadata->projection_type)
3292     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3293         "projection_type", spherical_metadata->projection_type,
3294         NULL);
3295   if (spherical_metadata->stereo_mode)
3296     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3297         "stereo_mode", spherical_metadata->stereo_mode,
3298         NULL);
3299
3300   gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3301           gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
3302                   gst_tag_list_copy (taglist)));
3303
3304   gst_tag_list_unref(taglist);
3305
3306   return;
3307 }
3308
3309 static void
3310 qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3311 {
3312   guint offset = 0;
3313
3314   guint8 version = 0;
3315   guint8 ambisonic_type  = 0;
3316   guint32 ambisonic_order = 0;
3317   guint8 ambisonic_channel_ordering = 0;
3318   guint8 ambisonic_normalization = 0;
3319   guint32 num_channels = 0;
3320   guint32 channel_map[49] = { 0 };      /* Up to 6th order */
3321
3322   int i;
3323
3324   GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
3325
3326   qtdemux->header_size += length;
3327   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3328
3329   if (length <= offset + 16) {
3330     GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
3331     return;
3332   }
3333
3334   version = QT_UINT8 (buffer + offset);
3335   ambisonic_type = QT_UINT8 (buffer + offset + 1);
3336   ambisonic_order = QT_UINT32 (buffer + offset + 2);
3337   ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
3338   ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
3339   num_channels = QT_UINT32 (buffer + offset + 8);
3340   for (i = 0; i < num_channels; ++i)
3341     channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
3342
3343   GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
3344   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
3345   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
3346   GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
3347       ambisonic_channel_ordering);
3348   GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
3349       ambisonic_normalization);
3350   GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
3351   for (i = 0; i < num_channels; ++i)
3352     GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
3353
3354   if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
3355     if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
3356       qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
3357
3358     if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
3359       if (num_channels == 4) {
3360         qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
3361
3362         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
3363             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
3364             && (channel_map[0] == 0) && (channel_map[1] == 1)
3365             && (channel_map[2] == 2) && (channel_map[3] == 3))
3366           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
3367
3368         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
3369             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
3370             && (channel_map[0] == 0) && (channel_map[1] == 3)
3371             && (channel_map[2] == 1) && (channel_map[3] == 2))
3372           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
3373       }
3374     }
3375   }
3376
3377   return;
3378 }
3379 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3380
3381 static void
3382 qtdemux_update_default_sample_encryption_settings (GstQTDemux * qtdemux,
3383     QtDemuxCencSampleSetInfo * info, guint32 is_encrypted, guint8 iv_size,
3384     const guint8 * kid)
3385 {
3386   GstBuffer *kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
3387   gst_buffer_fill (kid_buf, 0, kid, 16);
3388   if (info->default_properties)
3389     gst_structure_free (info->default_properties);
3390   info->default_properties =
3391       gst_structure_new ("application/x-cenc",
3392       "iv_size", G_TYPE_UINT, iv_size,
3393       "encrypted", G_TYPE_BOOLEAN, (is_encrypted == 1),
3394       "kid", GST_TYPE_BUFFER, kid_buf, NULL);
3395   GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
3396       "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
3397   gst_buffer_unref (kid_buf);
3398 }
3399
3400 static gboolean
3401 qtdemux_update_default_piff_encryption_settings (GstQTDemux * qtdemux,
3402     QtDemuxCencSampleSetInfo * info, GstByteReader * br)
3403 {
3404   guint32 algorithm_id = 0;
3405   const guint8 *kid;
3406   gboolean is_encrypted = TRUE;
3407   guint8 iv_size = 8;
3408
3409   if (!gst_byte_reader_get_uint24_le (br, &algorithm_id)) {
3410     GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
3411     return FALSE;
3412   }
3413
3414   algorithm_id >>= 8;
3415   if (algorithm_id == 0) {
3416     is_encrypted = FALSE;
3417   } else if (algorithm_id == 1) {
3418     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
3419   } else if (algorithm_id == 2) {
3420     GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
3421   }
3422
3423   if (!gst_byte_reader_get_uint8 (br, &iv_size))
3424     return FALSE;
3425
3426   if (!gst_byte_reader_get_data (br, 16, &kid))
3427     return FALSE;
3428
3429   qtdemux_update_default_sample_encryption_settings (qtdemux, info,
3430       is_encrypted, iv_size, kid);
3431   gst_structure_set (info->default_properties, "piff_algorithm_id",
3432       G_TYPE_UINT, algorithm_id, NULL);
3433   return TRUE;
3434 }
3435
3436
3437 static void
3438 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
3439     guint offset)
3440 {
3441   GstByteReader br;
3442   guint8 version;
3443   guint32 flags = 0;
3444   guint i;
3445   guint iv_size = 8;
3446   QtDemuxStream *stream;
3447   GstStructure *structure;
3448   QtDemuxCencSampleSetInfo *ss_info = NULL;
3449   const gchar *system_id;
3450   gboolean uses_sub_sample_encryption = FALSE;
3451   guint32 sample_count;
3452
3453   if (QTDEMUX_N_STREAMS (qtdemux) == 0)
3454     return;
3455
3456   stream = QTDEMUX_NTH_STREAM (qtdemux, 0);
3457
3458   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
3459   if (!gst_structure_has_name (structure, "application/x-cenc")) {
3460     GST_WARNING_OBJECT (qtdemux,
3461         "Attempting PIFF box parsing on an unencrypted stream.");
3462     return;
3463   }
3464
3465   gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
3466       G_TYPE_STRING, &system_id, NULL);
3467   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
3468
3469   stream->protected = TRUE;
3470   stream->protection_scheme_type = FOURCC_cenc;
3471
3472   if (!stream->protection_scheme_info)
3473     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
3474
3475   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3476   if (!ss_info->default_properties) {
3477     ss_info->default_properties =
3478         gst_structure_new ("application/x-cenc",
3479         "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE,
3480         NULL);
3481
3482   }
3483
3484   if (ss_info->crypto_info) {
3485     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3486     g_ptr_array_free (ss_info->crypto_info, TRUE);
3487     ss_info->crypto_info = NULL;
3488   }
3489
3490   /* skip UUID */
3491   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
3492
3493   if (!gst_byte_reader_get_uint8 (&br, &version)) {
3494     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
3495     return;
3496   }
3497
3498   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
3499     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
3500     return;
3501   }
3502
3503   if ((flags & 0x000001)) {
3504     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, ss_info,
3505             &br))
3506       return;
3507   } else if ((flags & 0x000002)) {
3508     uses_sub_sample_encryption = TRUE;
3509   }
3510
3511   if (!gst_structure_get_uint (ss_info->default_properties, "iv_size",
3512           &iv_size)) {
3513     GST_ERROR_OBJECT (qtdemux, "Error getting encryption IV size field");
3514     return;
3515   }
3516
3517   if (!gst_byte_reader_get_uint32_be (&br, &sample_count)) {
3518     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
3519     return;
3520   }
3521
3522   ss_info->crypto_info =
3523       g_ptr_array_new_full (sample_count,
3524       (GDestroyNotify) qtdemux_gst_structure_free);
3525
3526   for (i = 0; i < sample_count; ++i) {
3527     GstStructure *properties;
3528     guint8 *data;
3529     GstBuffer *buf;
3530
3531     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3532     if (properties == NULL) {
3533       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3534       qtdemux->cenc_aux_sample_count = i;
3535       return;
3536     }
3537
3538     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
3539       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
3540       gst_structure_free (properties);
3541       qtdemux->cenc_aux_sample_count = i;
3542       return;
3543     }
3544     buf = gst_buffer_new_wrapped (data, iv_size);
3545     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3546     gst_buffer_unref (buf);
3547
3548     if (uses_sub_sample_encryption) {
3549       guint16 n_subsamples;
3550       const GValue *kid_buf_value;
3551
3552       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
3553           || n_subsamples == 0) {
3554         GST_ERROR_OBJECT (qtdemux,
3555             "failed to get subsample count for sample %u", i);
3556         gst_structure_free (properties);
3557         qtdemux->cenc_aux_sample_count = i;
3558         return;
3559       }
3560       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3561       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
3562         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3563             i);
3564         gst_structure_free (properties);
3565         qtdemux->cenc_aux_sample_count = i;
3566         return;
3567       }
3568       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3569
3570       kid_buf_value =
3571           gst_structure_get_value (ss_info->default_properties, "kid");
3572
3573       gst_structure_set (properties,
3574           "subsample_count", G_TYPE_UINT, n_subsamples,
3575           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3576       gst_structure_set_value (properties, "kid", kid_buf_value);
3577       gst_buffer_unref (buf);
3578     } else {
3579       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3580     }
3581
3582     g_ptr_array_add (ss_info->crypto_info, properties);
3583   }
3584
3585   qtdemux->cenc_aux_sample_count = sample_count;
3586 }
3587
3588 static void
3589 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3590 {
3591   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
3592     0x97, 0xA9, 0x42, 0xE8,
3593     0x9C, 0x71, 0x99, 0x94,
3594     0x91, 0xE3, 0xAF, 0xAC
3595   };
3596   static const guint8 playready_uuid[] = {
3597     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
3598     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
3599   };
3600
3601   static const guint8 piff_sample_encryption_uuid[] = {
3602     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3603     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3604   };
3605
3606 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3607   static const guint8 spherical_uuid[] = {
3608     0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
3609     0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd
3610   };
3611 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3612
3613   guint offset;
3614
3615   /* counts as header data */
3616   qtdemux->header_size += length;
3617
3618   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3619
3620   if (length <= offset + 16) {
3621     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3622     return;
3623   }
3624
3625 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3626   if (memcmp (buffer + offset, spherical_uuid, 16) == 0) {
3627     const char *contents;
3628
3629     GST_DEBUG_OBJECT (qtdemux, "spherical uuid was found");
3630     contents = (char *) (buffer + offset + 16);
3631     GST_DEBUG_OBJECT (qtdemux, "contents: %s\n", contents);
3632
3633     if (qtdemux->spherical_metadata)
3634       _parse_spatial_video_metadata_from_xml_string (qtdemux, contents);
3635
3636     return;
3637   }
3638 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3639
3640   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3641     GstBuffer *buf;
3642     GstTagList *taglist;
3643
3644     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3645         length - offset - 16, NULL);
3646     taglist = gst_tag_list_from_xmp_buffer (buf);
3647     gst_buffer_unref (buf);
3648
3649     /* make sure we have a usable taglist */
3650     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3651
3652     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3653
3654   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3655     int len;
3656     const gunichar2 *s_utf16;
3657     char *contents;
3658
3659     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3660     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3661     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3662     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3663
3664     g_free (contents);
3665
3666     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3667         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3668         (NULL));
3669   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3670     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3671   } else {
3672     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3673         GST_READ_UINT32_LE (buffer + offset),
3674         GST_READ_UINT32_LE (buffer + offset + 4),
3675         GST_READ_UINT32_LE (buffer + offset + 8),
3676         GST_READ_UINT32_LE (buffer + offset + 12));
3677   }
3678 }
3679
3680 static void
3681 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3682 {
3683   GstSidxParser sidx_parser;
3684   GstIsoffParserResult res;
3685   guint consumed;
3686
3687   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3688
3689   res =
3690       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3691       &consumed);
3692   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3693   if (res == GST_ISOFF_QT_PARSER_DONE) {
3694     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3695   }
3696   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3697 }
3698
3699 /* caller verifies at least 8 bytes in buf */
3700 static void
3701 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3702     guint64 * plength, guint32 * pfourcc)
3703 {
3704   guint64 length;
3705   guint32 fourcc;
3706
3707   length = QT_UINT32 (data);
3708   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3709   fourcc = QT_FOURCC (data + 4);
3710   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3711
3712   if (length == 0) {
3713     length = G_MAXUINT64;
3714   } else if (length == 1 && size >= 16) {
3715     /* this means we have an extended size, which is the 64 bit value of
3716      * the next 8 bytes */
3717     length = QT_UINT64 (data + 8);
3718     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3719   }
3720
3721   if (plength)
3722     *plength = length;
3723   if (pfourcc)
3724     *pfourcc = fourcc;
3725 }
3726
3727 static gboolean
3728 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3729 {
3730   guint32 version = 0;
3731   GstClockTime duration = 0;
3732
3733   if (!gst_byte_reader_get_uint32_be (br, &version))
3734     goto failed;
3735
3736   version >>= 24;
3737   if (version == 1) {
3738     if (!gst_byte_reader_get_uint64_be (br, &duration))
3739       goto failed;
3740   } else {
3741     guint32 dur = 0;
3742
3743     if (!gst_byte_reader_get_uint32_be (br, &dur))
3744       goto failed;
3745     duration = dur;
3746   }
3747
3748   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3749   qtdemux->duration = duration;
3750
3751   return TRUE;
3752
3753 failed:
3754   {
3755     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3756     return FALSE;
3757   }
3758 }
3759
3760 static gboolean
3761 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3762     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3763 {
3764   if (!stream->parsed_trex && qtdemux->moov_node) {
3765     GNode *mvex, *trex;
3766     GstByteReader trex_data;
3767
3768     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3769     if (mvex) {
3770       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3771           &trex_data);
3772       while (trex) {
3773         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3774
3775         /* skip version/flags */
3776         if (!gst_byte_reader_skip (&trex_data, 4))
3777           goto next;
3778         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3779           goto next;
3780         if (id != stream->track_id)
3781           goto next;
3782         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3783           goto next;
3784         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3785           goto next;
3786         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3787           goto next;
3788         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3789           goto next;
3790
3791         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3792             "duration %d,  size %d, flags 0x%x", stream->track_id,
3793             dur, size, flags);
3794
3795         stream->parsed_trex = TRUE;
3796         stream->def_sample_description_index = sdi;
3797         stream->def_sample_duration = dur;
3798         stream->def_sample_size = size;
3799         stream->def_sample_flags = flags;
3800
3801       next:
3802         /* iterate all siblings */
3803         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3804             &trex_data);
3805       }
3806     }
3807   }
3808
3809   *ds_duration = stream->def_sample_duration;
3810   *ds_size = stream->def_sample_size;
3811   *ds_flags = stream->def_sample_flags;
3812
3813   /* even then, above values are better than random ... */
3814   if (G_UNLIKELY (!stream->parsed_trex)) {
3815     GST_WARNING_OBJECT (qtdemux,
3816         "failed to find fragment defaults for stream %d", stream->track_id);
3817     return FALSE;
3818   }
3819
3820   return TRUE;
3821 }
3822
3823 /* This method should be called whenever a more accurate duration might
3824  * have been found. It will update all relevant variables if/where needed
3825  */
3826 static void
3827 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3828 {
3829   guint i;
3830   guint64 movdur;
3831   GstClockTime prevdur;
3832
3833   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3834
3835   if (movdur > qtdemux->duration) {
3836     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3837     GST_DEBUG_OBJECT (qtdemux,
3838         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3839         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3840     qtdemux->duration = movdur;
3841     GST_DEBUG_OBJECT (qtdemux,
3842         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3843         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3844         GST_TIME_ARGS (qtdemux->segment.stop));
3845     if (qtdemux->segment.duration == prevdur) {
3846       /* If the current segment has duration/stop identical to previous duration
3847        * update them also (because they were set at that point in time with
3848        * the wrong duration */
3849       /* We convert the value *from* the timescale version to avoid rounding errors */
3850       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3851       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3852       qtdemux->segment.duration = fixeddur;
3853       qtdemux->segment.stop = fixeddur;
3854     }
3855   }
3856
3857   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
3858     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
3859
3860     movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3861     if (movdur > stream->duration) {
3862       GST_DEBUG_OBJECT (qtdemux,
3863           "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3864           GST_TIME_ARGS (duration));
3865       stream->duration = movdur;
3866       /* internal duration tracking state has been updated above, so */
3867       /* preserve an open-ended dummy segment rather than repeatedly updating
3868        * it and spamming downstream accordingly with segment events */
3869       if (stream->dummy_segment &&
3870           GST_CLOCK_TIME_IS_VALID (stream->segments[0].duration)) {
3871         /* Update all dummy values to new duration */
3872         stream->segments[0].stop_time = duration;
3873         stream->segments[0].duration = duration;
3874         stream->segments[0].media_stop = duration;
3875
3876         /* let downstream know we possibly have a new stop time */
3877         if (stream->segment_index != -1) {
3878           GstClockTime pos;
3879
3880           if (qtdemux->segment.rate >= 0) {
3881             pos = stream->segment.start;
3882           } else {
3883             pos = stream->segment.stop;
3884           }
3885
3886           gst_qtdemux_stream_update_segment (qtdemux, stream,
3887               stream->segment_index, pos, NULL, NULL);
3888         }
3889       }
3890     }
3891   }
3892 }
3893
3894 static gboolean
3895 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3896     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3897     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3898     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3899     gboolean has_tfdt)
3900 {
3901   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3902   guint64 timestamp;
3903   gint32 data_offset = 0;
3904   guint32 flags = 0, first_flags = 0, samples_count = 0;
3905   gint i;
3906   guint8 *data;
3907   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3908   QtDemuxSample *sample;
3909   gboolean ismv = FALSE;
3910   gint64 initial_offset;
3911
3912   GST_LOG_OBJECT (qtdemux, "parsing trun track-id %d; "
3913       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3914       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3915       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3916
3917   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3918     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3919     return TRUE;
3920   }
3921
3922   /* presence of stss or not can't really tell us much,
3923    * and flags and so on tend to be marginally reliable in these files */
3924   if (stream->subtype == FOURCC_soun) {
3925     GST_DEBUG_OBJECT (qtdemux,
3926         "sound track in fragmented file; marking all keyframes");
3927     stream->all_keyframe = TRUE;
3928   }
3929
3930   if (!gst_byte_reader_skip (trun, 1) ||
3931       !gst_byte_reader_get_uint24_be (trun, &flags))
3932     goto fail;
3933
3934   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3935     goto fail;
3936
3937   if (flags & TR_DATA_OFFSET) {
3938     /* note this is really signed */
3939     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3940       goto fail;
3941     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3942     /* default base offset = first byte of moof */
3943     if (*base_offset == -1) {
3944       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3945       *base_offset = moof_offset;
3946     }
3947     *running_offset = *base_offset + data_offset;
3948   } else {
3949     /* if no offset at all, that would mean data starts at moof start,
3950      * which is a bit wrong and is ismv crappy way, so compensate
3951      * assuming data is in mdat following moof */
3952     if (*base_offset == -1) {
3953       *base_offset = moof_offset + moof_length + 8;
3954       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3955       ismv = TRUE;
3956     }
3957     if (*running_offset == -1)
3958       *running_offset = *base_offset;
3959   }
3960
3961   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3962       *running_offset);
3963   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3964       data_offset, flags, samples_count);
3965
3966   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3967     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3968       GST_DEBUG_OBJECT (qtdemux,
3969           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3970       flags ^= TR_FIRST_SAMPLE_FLAGS;
3971     } else {
3972       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3973         goto fail;
3974       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3975     }
3976   }
3977
3978   /* FIXME ? spec says other bits should also be checked to determine
3979    * entry size (and prefix size for that matter) */
3980   entry_size = 0;
3981   dur_offset = size_offset = 0;
3982   if (flags & TR_SAMPLE_DURATION) {
3983     GST_LOG_OBJECT (qtdemux, "entry duration present");
3984     dur_offset = entry_size;
3985     entry_size += 4;
3986   }
3987   if (flags & TR_SAMPLE_SIZE) {
3988     GST_LOG_OBJECT (qtdemux, "entry size present");
3989     size_offset = entry_size;
3990     entry_size += 4;
3991   }
3992   if (flags & TR_SAMPLE_FLAGS) {
3993     GST_LOG_OBJECT (qtdemux, "entry flags present");
3994     flags_offset = entry_size;
3995     entry_size += 4;
3996   }
3997   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3998     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3999     ct_offset = entry_size;
4000     entry_size += 4;
4001   }
4002
4003   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
4004     goto fail;
4005   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
4006
4007   if (stream->n_samples + samples_count >=
4008       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
4009     goto index_too_big;
4010
4011   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
4012       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
4013       (stream->n_samples + samples_count) *
4014       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
4015
4016   /* create a new array of samples if it's the first sample parsed */
4017   if (stream->n_samples == 0) {
4018     g_assert (stream->samples == NULL);
4019     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
4020     /* or try to reallocate it with space enough to insert the new samples */
4021   } else
4022     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
4023         stream->n_samples + samples_count);
4024   if (stream->samples == NULL)
4025     goto out_of_memory;
4026
4027   if (qtdemux->fragment_start != -1) {
4028     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
4029     qtdemux->fragment_start = -1;
4030   } else {
4031     if (stream->n_samples == 0) {
4032       if (decode_ts > 0) {
4033         timestamp = decode_ts;
4034       } else if (stream->pending_seek != NULL) {
4035         /* if we don't have a timestamp from a tfdt box, we'll use the one
4036          * from the mfra seek table */
4037         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
4038             GST_TIME_ARGS (stream->pending_seek->ts));
4039
4040         /* FIXME: this is not fully correct, the timestamp refers to the random
4041          * access sample refered to in the tfra entry, which may not necessarily
4042          * be the first sample in the tfrag/trun (but hopefully/usually is) */
4043         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
4044       } else {
4045         timestamp = 0;
4046       }
4047
4048       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
4049       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
4050           GST_TIME_ARGS (gst_ts));
4051     } else {
4052       /* subsequent fragments extend stream */
4053       timestamp =
4054           stream->samples[stream->n_samples - 1].timestamp +
4055           stream->samples[stream->n_samples - 1].duration;
4056
4057       /* If this is a GST_FORMAT_BYTES stream and there's a significant
4058        * difference (1 sec.) between decode_ts and timestamp, prefer the
4059        * former */
4060       if (has_tfdt && !qtdemux->upstream_format_is_time
4061           && ABSDIFF (decode_ts, timestamp) >
4062           MAX (stream->duration_last_moof / 2,
4063               GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
4064         GST_INFO_OBJECT (qtdemux,
4065             "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
4066             ") are significantly different (more than %" GST_TIME_FORMAT
4067             "), using decode_ts",
4068             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
4069             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
4070             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
4071                     MAX (stream->duration_last_moof / 2,
4072                         GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
4073         timestamp = decode_ts;
4074       }
4075
4076       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
4077       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
4078           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
4079     }
4080   }
4081
4082   initial_offset = *running_offset;
4083
4084   sample = stream->samples + stream->n_samples;
4085   for (i = 0; i < samples_count; i++) {
4086     guint32 dur, size, sflags, ct;
4087
4088     /* first read sample data */
4089     if (flags & TR_SAMPLE_DURATION) {
4090       dur = QT_UINT32 (data + dur_offset);
4091     } else {
4092       dur = d_sample_duration;
4093     }
4094     if (flags & TR_SAMPLE_SIZE) {
4095       size = QT_UINT32 (data + size_offset);
4096     } else {
4097       size = d_sample_size;
4098     }
4099     if (flags & TR_FIRST_SAMPLE_FLAGS) {
4100       if (i == 0) {
4101         sflags = first_flags;
4102       } else {
4103         sflags = d_sample_flags;
4104       }
4105     } else if (flags & TR_SAMPLE_FLAGS) {
4106       sflags = QT_UINT32 (data + flags_offset);
4107     } else {
4108       sflags = d_sample_flags;
4109     }
4110     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
4111       ct = QT_UINT32 (data + ct_offset);
4112     } else {
4113       ct = 0;
4114     }
4115     data += entry_size;
4116
4117     /* fill the sample information */
4118     sample->offset = *running_offset;
4119     sample->pts_offset = ct;
4120     sample->size = size;
4121     sample->timestamp = timestamp;
4122     sample->duration = dur;
4123     /* sample-is-difference-sample */
4124     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
4125      * now idea how it relates to bitfield other than massive LE/BE confusion */
4126     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
4127     *running_offset += size;
4128     timestamp += dur;
4129     stream->duration_moof += dur;
4130     sample++;
4131   }
4132
4133   /* Update total duration if needed */
4134   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
4135
4136   /* Pre-emptively figure out size of mdat based on trun information.
4137    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
4138    * size, else we will still be able to use this when dealing with gap'ed
4139    * input */
4140   qtdemux->mdatleft = *running_offset - initial_offset;
4141   qtdemux->mdatoffset = initial_offset;
4142   qtdemux->mdatsize = qtdemux->mdatleft;
4143
4144   stream->n_samples += samples_count;
4145   stream->n_samples_moof += samples_count;
4146
4147   if (stream->pending_seek != NULL)
4148     stream->pending_seek = NULL;
4149
4150   return TRUE;
4151
4152 fail:
4153   {
4154     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
4155     return FALSE;
4156   }
4157 out_of_memory:
4158   {
4159     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
4160         stream->n_samples);
4161     return FALSE;
4162   }
4163 index_too_big:
4164   {
4165     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
4166         "be larger than %uMB (broken file?)", stream->n_samples,
4167         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
4168     return FALSE;
4169   }
4170 }
4171
4172 /* find stream with @id */
4173 static inline QtDemuxStream *
4174 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
4175 {
4176   QtDemuxStream *stream;
4177   gint i;
4178
4179   /* check */
4180   if (G_UNLIKELY (!id)) {
4181     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
4182     return NULL;
4183   }
4184
4185   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4186     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4187     if (stream->track_id == id)
4188       return stream;
4189   }
4190   if (qtdemux->mss_mode) {
4191     /* mss should have only 1 stream anyway */
4192     return QTDEMUX_NTH_STREAM (qtdemux, 0);
4193   }
4194
4195   return NULL;
4196 }
4197
4198 static gboolean
4199 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
4200     guint32 * fragment_number)
4201 {
4202   if (!gst_byte_reader_skip (mfhd, 4))
4203     goto fail;
4204   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
4205     goto fail;
4206   return TRUE;
4207 fail:
4208   {
4209     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
4210     return FALSE;
4211   }
4212 }
4213
4214 static gboolean
4215 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
4216     QtDemuxStream ** stream, guint32 * default_sample_duration,
4217     guint32 * default_sample_size, guint32 * default_sample_flags,
4218     gint64 * base_offset)
4219 {
4220   guint32 flags = 0;
4221   guint32 track_id = 0;
4222
4223   if (!gst_byte_reader_skip (tfhd, 1) ||
4224       !gst_byte_reader_get_uint24_be (tfhd, &flags))
4225     goto invalid_track;
4226
4227   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
4228     goto invalid_track;
4229
4230   *stream = qtdemux_find_stream (qtdemux, track_id);
4231   if (G_UNLIKELY (!*stream))
4232     goto unknown_stream;
4233
4234   if (flags & TF_DEFAULT_BASE_IS_MOOF)
4235     *base_offset = qtdemux->moof_offset;
4236
4237   if (flags & TF_BASE_DATA_OFFSET)
4238     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
4239       goto invalid_track;
4240
4241   /* obtain stream defaults */
4242   qtdemux_parse_trex (qtdemux, *stream,
4243       default_sample_duration, default_sample_size, default_sample_flags);
4244
4245   (*stream)->stsd_sample_description_id =
4246       (*stream)->def_sample_description_index - 1;
4247
4248   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
4249     guint32 sample_description_index;
4250     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
4251       goto invalid_track;
4252     (*stream)->stsd_sample_description_id = sample_description_index - 1;
4253   }
4254
4255   if (qtdemux->mss_mode) {
4256     /* mss has no stsd entry */
4257     (*stream)->stsd_sample_description_id = 0;
4258   }
4259
4260   if (flags & TF_DEFAULT_SAMPLE_DURATION)
4261     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
4262       goto invalid_track;
4263
4264   if (flags & TF_DEFAULT_SAMPLE_SIZE)
4265     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
4266       goto invalid_track;
4267
4268   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
4269     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
4270       goto invalid_track;
4271
4272   return TRUE;
4273
4274 invalid_track:
4275   {
4276     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
4277     return FALSE;
4278   }
4279 unknown_stream:
4280   {
4281     GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
4282     return TRUE;
4283   }
4284 }
4285
4286 static gboolean
4287 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
4288     guint64 * decode_time)
4289 {
4290   guint32 version = 0;
4291
4292   if (!gst_byte_reader_get_uint32_be (br, &version))
4293     return FALSE;
4294
4295   version >>= 24;
4296   if (version == 1) {
4297     if (!gst_byte_reader_get_uint64_be (br, decode_time))
4298       goto failed;
4299   } else {
4300     guint32 dec_time = 0;
4301     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
4302       goto failed;
4303     *decode_time = dec_time;
4304   }
4305
4306   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
4307       *decode_time);
4308
4309   return TRUE;
4310
4311 failed:
4312   {
4313     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
4314     return FALSE;
4315   }
4316 }
4317
4318 /* Returns a pointer to a GstStructure containing the properties of
4319  * the stream sample identified by @sample_index. The caller must unref
4320  * the returned object after use. Returns NULL if unsuccessful. */
4321 static GstStructure *
4322 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
4323     QtDemuxStream * stream, guint sample_index)
4324 {
4325   QtDemuxCencSampleSetInfo *info = NULL;
4326
4327   g_return_val_if_fail (stream != NULL, NULL);
4328   g_return_val_if_fail (stream->protected, NULL);
4329   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
4330
4331   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4332
4333   /* Currently, cenc properties for groups of samples are not supported, so
4334    * simply return a copy of the default sample properties */
4335   return gst_structure_copy (info->default_properties);
4336 }
4337
4338 /* Parses the sizes of sample auxiliary information contained within a stream,
4339  * as given in a saiz box. Returns array of sample_count guint8 size values,
4340  * or NULL on failure */
4341 static guint8 *
4342 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
4343     GstByteReader * br, guint32 * sample_count)
4344 {
4345   guint32 flags = 0;
4346   guint8 *info_sizes;
4347   guint8 default_info_size;
4348
4349   g_return_val_if_fail (qtdemux != NULL, NULL);
4350   g_return_val_if_fail (stream != NULL, NULL);
4351   g_return_val_if_fail (br != NULL, NULL);
4352   g_return_val_if_fail (sample_count != NULL, NULL);
4353
4354   if (!gst_byte_reader_get_uint32_be (br, &flags))
4355     return NULL;
4356
4357   if (flags & 0x1) {
4358     /* aux_info_type and aux_info_type_parameter are ignored */
4359     if (!gst_byte_reader_skip (br, 8))
4360       return NULL;
4361   }
4362
4363   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
4364     return NULL;
4365   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
4366
4367   if (!gst_byte_reader_get_uint32_be (br, sample_count))
4368     return NULL;
4369   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
4370
4371
4372   if (default_info_size == 0) {
4373     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
4374       return NULL;
4375     }
4376   } else {
4377     info_sizes = g_new (guint8, *sample_count);
4378     memset (info_sizes, default_info_size, *sample_count);
4379   }
4380
4381   return info_sizes;
4382 }
4383
4384 /* Parses the offset of sample auxiliary information contained within a stream,
4385  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
4386 static gboolean
4387 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
4388     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
4389     guint64 * offset)
4390 {
4391   guint8 version = 0;
4392   guint32 flags = 0;
4393   guint32 aux_info_type = 0;
4394   guint32 aux_info_type_parameter = 0;
4395   guint32 entry_count;
4396   guint32 off_32;
4397   guint64 off_64;
4398   const guint8 *aux_info_type_data = NULL;
4399
4400   g_return_val_if_fail (qtdemux != NULL, FALSE);
4401   g_return_val_if_fail (stream != NULL, FALSE);
4402   g_return_val_if_fail (br != NULL, FALSE);
4403   g_return_val_if_fail (offset != NULL, FALSE);
4404
4405   if (!gst_byte_reader_get_uint8 (br, &version))
4406     return FALSE;
4407
4408   if (!gst_byte_reader_get_uint24_be (br, &flags))
4409     return FALSE;
4410
4411   if (flags & 0x1) {
4412
4413     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
4414       return FALSE;
4415     aux_info_type = QT_FOURCC (aux_info_type_data);
4416
4417     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
4418       return FALSE;
4419   } else if (stream->protected) {
4420     aux_info_type = stream->protection_scheme_type;
4421   } else {
4422     aux_info_type = CUR_STREAM (stream)->fourcc;
4423   }
4424
4425   if (info_type)
4426     *info_type = aux_info_type;
4427   if (info_type_parameter)
4428     *info_type_parameter = aux_info_type_parameter;
4429
4430   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
4431       "aux_info_type_parameter:  %#06x",
4432       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
4433
4434   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
4435     return FALSE;
4436
4437   if (entry_count != 1) {
4438     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
4439     return FALSE;
4440   }
4441
4442   if (version == 0) {
4443     if (!gst_byte_reader_get_uint32_be (br, &off_32))
4444       return FALSE;
4445     *offset = (guint64) off_32;
4446   } else {
4447     if (!gst_byte_reader_get_uint64_be (br, &off_64))
4448       return FALSE;
4449     *offset = off_64;
4450   }
4451
4452   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
4453   return TRUE;
4454 }
4455
4456 static void
4457 qtdemux_gst_structure_free (GstStructure * gststructure)
4458 {
4459   if (gststructure) {
4460     gst_structure_free (gststructure);
4461   }
4462 }
4463
4464 /* Parses auxiliary information relating to samples protected using Common
4465  * Encryption (cenc); the format of this information is defined in
4466  * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
4467 static gboolean
4468 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
4469     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
4470 {
4471   QtDemuxCencSampleSetInfo *ss_info = NULL;
4472   guint8 size;
4473   gint i;
4474   GPtrArray *old_crypto_info = NULL;
4475   guint old_entries = 0;
4476
4477   g_return_val_if_fail (qtdemux != NULL, FALSE);
4478   g_return_val_if_fail (stream != NULL, FALSE);
4479   g_return_val_if_fail (br != NULL, FALSE);
4480   g_return_val_if_fail (stream->protected, FALSE);
4481   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
4482
4483   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4484
4485   if (ss_info->crypto_info) {
4486     old_crypto_info = ss_info->crypto_info;
4487     /* Count number of non-null entries remaining at the tail end */
4488     for (i = old_crypto_info->len - 1; i >= 0; i--) {
4489       if (g_ptr_array_index (old_crypto_info, i) == NULL)
4490         break;
4491       old_entries++;
4492     }
4493   }
4494
4495   ss_info->crypto_info =
4496       g_ptr_array_new_full (sample_count + old_entries,
4497       (GDestroyNotify) qtdemux_gst_structure_free);
4498
4499   /* We preserve old entries because we parse the next moof in advance
4500    * of consuming all samples from the previous moof, and otherwise
4501    * we'd discard the corresponding crypto info for the samples
4502    * from the previous fragment. */
4503   if (old_entries) {
4504     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
4505         old_entries);
4506     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
4507       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
4508               i));
4509       g_ptr_array_index (old_crypto_info, i) = NULL;
4510     }
4511   }
4512
4513   if (old_crypto_info) {
4514     /* Everything now belongs to the new array */
4515     g_ptr_array_free (old_crypto_info, TRUE);
4516   }
4517
4518   for (i = 0; i < sample_count; ++i) {
4519     GstStructure *properties;
4520     guint16 n_subsamples = 0;
4521     guint8 *data;
4522     guint iv_size;
4523     GstBuffer *buf;
4524
4525     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
4526     if (properties == NULL) {
4527       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
4528       return FALSE;
4529     }
4530     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
4531       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
4532       gst_structure_free (properties);
4533       return FALSE;
4534     }
4535     if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
4536       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4537       gst_structure_free (properties);
4538       return FALSE;
4539     }
4540     buf = gst_buffer_new_wrapped (data, iv_size);
4541     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
4542     gst_buffer_unref (buf);
4543     size = info_sizes[i];
4544     if (size > iv_size) {
4545       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4546           || !(n_subsamples > 0)) {
4547         gst_structure_free (properties);
4548         GST_ERROR_OBJECT (qtdemux,
4549             "failed to get subsample count for sample %u", i);
4550         return FALSE;
4551       }
4552       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4553       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4554         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4555             i);
4556         gst_structure_free (properties);
4557         return FALSE;
4558       }
4559       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4560       if (!buf) {
4561         gst_structure_free (properties);
4562         return FALSE;
4563       }
4564       gst_structure_set (properties,
4565           "subsample_count", G_TYPE_UINT, n_subsamples,
4566           "subsamples", GST_TYPE_BUFFER, buf, NULL);
4567       gst_buffer_unref (buf);
4568     } else {
4569       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4570     }
4571     g_ptr_array_add (ss_info->crypto_info, properties);
4572   }
4573   return TRUE;
4574 }
4575
4576 /* Converts a UUID in raw byte form to a string representation, as defined in
4577  * RFC 4122. The caller takes ownership of the returned string and is
4578  * responsible for freeing it after use. */
4579 static gchar *
4580 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4581 {
4582   const guint8 *uuid = (const guint8 *) uuid_bytes;
4583
4584   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4585       "%02x%02x-%02x%02x%02x%02x%02x%02x",
4586       uuid[0], uuid[1], uuid[2], uuid[3],
4587       uuid[4], uuid[5], uuid[6], uuid[7],
4588       uuid[8], uuid[9], uuid[10], uuid[11],
4589       uuid[12], uuid[13], uuid[14], uuid[15]);
4590 }
4591
4592 /* Parses a Protection System Specific Header box (pssh), as defined in the
4593  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4594  * information needed by a specific content protection system in order to
4595  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4596  * otherwise. */
4597 static gboolean
4598 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4599 {
4600   gchar *sysid_string;
4601   guint32 pssh_size = QT_UINT32 (node->data);
4602   GstBuffer *pssh = NULL;
4603   GstEvent *event = NULL;
4604   guint32 parent_box_type;
4605   gint i;
4606
4607   if (G_UNLIKELY (pssh_size < 32U)) {
4608     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4609     return FALSE;
4610   }
4611
4612   sysid_string =
4613       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4614
4615   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4616
4617   pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
4618   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4619       gst_buffer_get_size (pssh));
4620
4621   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4622
4623   /* Push an event containing the pssh box onto the queues of all streams. */
4624   event = gst_event_new_protection (sysid_string, pssh,
4625       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4626   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4627     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4628     GST_TRACE_OBJECT (qtdemux,
4629         "adding protection event for stream %s and system %s",
4630         stream->stream_id, sysid_string);
4631     g_queue_push_tail (&stream->protection_scheme_event_queue,
4632         gst_event_ref (event));
4633   }
4634   g_free (sysid_string);
4635   gst_event_unref (event);
4636   gst_buffer_unref (pssh);
4637   return TRUE;
4638 }
4639
4640 static gboolean
4641 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4642     guint64 moof_offset, QtDemuxStream * stream)
4643 {
4644   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4645   GNode *uuid_node;
4646   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4647   GNode *saiz_node, *saio_node, *pssh_node;
4648   GstByteReader saiz_data, saio_data;
4649   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4650   gint64 base_offset, running_offset;
4651   guint32 frag_num;
4652   GstClockTime min_dts = GST_CLOCK_TIME_NONE;
4653
4654   /* NOTE @stream ignored */
4655
4656   moof_node = g_node_new ((guint8 *) buffer);
4657   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4658   qtdemux_node_dump (qtdemux, moof_node);
4659
4660   /* Get fragment number from mfhd and check it's valid */
4661   mfhd_node =
4662       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4663   if (mfhd_node == NULL)
4664     goto missing_mfhd;
4665   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4666     goto fail;
4667   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4668
4669   /* unknown base_offset to start with */
4670   base_offset = running_offset = -1;
4671   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4672   while (traf_node) {
4673     guint64 decode_time = 0;
4674
4675     /* Fragment Header node */
4676     tfhd_node =
4677         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4678         &tfhd_data);
4679     if (!tfhd_node)
4680       goto missing_tfhd;
4681     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4682             &ds_size, &ds_flags, &base_offset))
4683       goto missing_tfhd;
4684
4685     /* The following code assumes at most a single set of sample auxiliary
4686      * data in the fragment (consisting of a saiz box and a corresponding saio
4687      * box); in theory, however, there could be multiple sets of sample
4688      * auxiliary data in a fragment. */
4689     saiz_node =
4690         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4691         &saiz_data);
4692     if (saiz_node) {
4693       guint32 info_type = 0;
4694       guint64 offset = 0;
4695       guint32 info_type_parameter = 0;
4696
4697       g_free (qtdemux->cenc_aux_info_sizes);
4698
4699       qtdemux->cenc_aux_info_sizes =
4700           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4701           &qtdemux->cenc_aux_sample_count);
4702       if (qtdemux->cenc_aux_info_sizes == NULL) {
4703         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4704         goto fail;
4705       }
4706       saio_node =
4707           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4708           &saio_data);
4709       if (!saio_node) {
4710         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4711         g_free (qtdemux->cenc_aux_info_sizes);
4712         qtdemux->cenc_aux_info_sizes = NULL;
4713         goto fail;
4714       }
4715
4716       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4717                   &info_type, &info_type_parameter, &offset))) {
4718         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4719         g_free (qtdemux->cenc_aux_info_sizes);
4720         qtdemux->cenc_aux_info_sizes = NULL;
4721         goto fail;
4722       }
4723       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4724         offset += (guint64) (base_offset - qtdemux->moof_offset);
4725       if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4726         GstByteReader br;
4727         if (offset > length) {
4728           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4729           qtdemux->cenc_aux_info_offset = offset;
4730         } else {
4731           gst_byte_reader_init (&br, buffer + offset, length - offset);
4732           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4733                   qtdemux->cenc_aux_info_sizes,
4734                   qtdemux->cenc_aux_sample_count)) {
4735             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4736             g_free (qtdemux->cenc_aux_info_sizes);
4737             qtdemux->cenc_aux_info_sizes = NULL;
4738             goto fail;
4739           }
4740         }
4741       }
4742     }
4743
4744     tfdt_node =
4745         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4746         &tfdt_data);
4747     if (tfdt_node) {
4748       /* We'll use decode_time to interpolate timestamps
4749        * in case the input timestamps are missing */
4750       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4751
4752       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4753           " (%" GST_TIME_FORMAT ")", decode_time,
4754           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4755                   decode_time) : GST_CLOCK_TIME_NONE));
4756
4757       /* Discard the fragment buffer timestamp info to avoid using it.
4758        * Rely on tfdt instead as it is more accurate than the timestamp
4759        * that is fetched from a manifest/playlist and is usually
4760        * less accurate. */
4761       qtdemux->fragment_start = -1;
4762     }
4763
4764     if (G_UNLIKELY (!stream)) {
4765       /* we lost track of offset, we'll need to regain it,
4766        * but can delay complaining until later or avoid doing so altogether */
4767       base_offset = -2;
4768       goto next;
4769     }
4770     if (G_UNLIKELY (base_offset < -1))
4771       goto lost_offset;
4772
4773     min_dts = MIN (min_dts, QTSTREAMTIME_TO_GSTTIME (stream, decode_time));
4774
4775     if (!qtdemux->pullbased) {
4776       /* Sample tables can grow enough to be problematic if the system memory
4777        * is very low (e.g. embedded devices) and the videos very long
4778        * (~8 MiB/hour for 25-30 fps video + typical AAC audio frames).
4779        * Fortunately, we can easily discard them for each new fragment when
4780        * we know qtdemux will not receive seeks outside of the current fragment.
4781        * adaptivedemux honors this assumption.
4782        * This optimization is also useful for applications that use qtdemux as
4783        * a push-based simple demuxer, like Media Source Extensions. */
4784       gst_qtdemux_stream_flush_samples_data (stream);
4785     }
4786
4787     /* initialise moof sample data */
4788     stream->n_samples_moof = 0;
4789     stream->duration_last_moof = stream->duration_moof;
4790     stream->duration_moof = 0;
4791
4792     /* Track Run node */
4793     trun_node =
4794         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4795         &trun_data);
4796     while (trun_node) {
4797       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4798           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4799           &running_offset, decode_time, (tfdt_node != NULL));
4800       /* iterate all siblings */
4801       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4802           &trun_data);
4803     }
4804
4805     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4806     if (uuid_node) {
4807       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4808       guint32 box_length = QT_UINT32 (uuid_buffer);
4809
4810       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4811     }
4812
4813     /* if no new base_offset provided for next traf,
4814      * base is end of current traf */
4815     base_offset = running_offset;
4816     running_offset = -1;
4817
4818     if (stream->n_samples_moof && stream->duration_moof)
4819       stream->new_caps = TRUE;
4820
4821   next:
4822     /* iterate all siblings */
4823     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4824   }
4825
4826   /* parse any protection system info */
4827   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4828   while (pssh_node) {
4829     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4830     qtdemux_parse_pssh (qtdemux, pssh_node);
4831     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4832   }
4833
4834   if (!qtdemux->upstream_format_is_time && !qtdemux->first_moof_already_parsed
4835       && !qtdemux->received_seek && GST_CLOCK_TIME_IS_VALID (min_dts)
4836       && min_dts != 0) {
4837     /* Unless the user has explictly requested another seek, perform an
4838      * internal seek to the time specified in the tfdt.
4839      *
4840      * This way if the user opens a file where the first tfdt is 1 hour
4841      * into the presentation, they will not have to wait 1 hour for run
4842      * time to catch up and actual playback to start. */
4843     gint i;
4844
4845     GST_DEBUG_OBJECT (qtdemux, "First fragment has a non-zero tfdt, "
4846         "performing an internal seek to %" GST_TIME_FORMAT,
4847         GST_TIME_ARGS (min_dts));
4848
4849     qtdemux->segment.start = min_dts;
4850     qtdemux->segment.time = qtdemux->segment.position = min_dts;
4851
4852     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
4853       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
4854       stream->time_position = min_dts;
4855     }
4856
4857     /* Before this code was run a segment was already sent when the moov was
4858      * parsed... which is OK -- some apps (mostly tests) expect a segment to
4859      * be emitted after a moov, and we can emit a second segment anyway for
4860      * special cases like this. */
4861     qtdemux->need_segment = TRUE;
4862   }
4863
4864   qtdemux->first_moof_already_parsed = TRUE;
4865
4866   g_node_destroy (moof_node);
4867   return TRUE;
4868
4869 missing_tfhd:
4870   {
4871     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4872     goto fail;
4873   }
4874 missing_mfhd:
4875   {
4876     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4877     goto fail;
4878   }
4879 lost_offset:
4880   {
4881     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4882     goto fail;
4883   }
4884 fail:
4885   {
4886     g_node_destroy (moof_node);
4887     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4888         (_("This file is corrupt and cannot be played.")), (NULL));
4889     return FALSE;
4890   }
4891 }
4892
4893 #if 0
4894 /* might be used if some day we actually use mfra & co
4895  * for random access to fragments,
4896  * but that will require quite some modifications and much less relying
4897  * on a sample array */
4898 #endif
4899
4900 static gboolean
4901 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4902 {
4903   QtDemuxStream *stream;
4904   guint32 ver_flags, track_id, len, num_entries, i;
4905   guint value_size, traf_size, trun_size, sample_size;
4906   guint64 time = 0, moof_offset = 0;
4907 #if 0
4908   GstBuffer *buf = NULL;
4909   GstFlowReturn ret;
4910 #endif
4911   GstByteReader tfra;
4912
4913   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4914
4915   if (!gst_byte_reader_skip (&tfra, 8))
4916     return FALSE;
4917
4918   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4919     return FALSE;
4920
4921   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4922       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4923       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4924     return FALSE;
4925
4926   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4927
4928   stream = qtdemux_find_stream (qtdemux, track_id);
4929   if (stream == NULL)
4930     goto unknown_trackid;
4931
4932   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4933   sample_size = (len & 3) + 1;
4934   trun_size = ((len & 12) >> 2) + 1;
4935   traf_size = ((len & 48) >> 4) + 1;
4936
4937   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4938       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4939
4940   if (num_entries == 0)
4941     goto no_samples;
4942
4943   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4944           value_size + value_size + traf_size + trun_size + sample_size))
4945     goto corrupt_file;
4946
4947   g_free (stream->ra_entries);
4948   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4949   stream->n_ra_entries = num_entries;
4950
4951   for (i = 0; i < num_entries; i++) {
4952     qt_atom_parser_get_offset (&tfra, value_size, &time);
4953     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4954     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4955     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4956     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4957
4958     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4959
4960     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4961         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4962
4963     stream->ra_entries[i].ts = time;
4964     stream->ra_entries[i].moof_offset = moof_offset;
4965
4966     /* don't want to go through the entire file and read all moofs at startup */
4967 #if 0
4968     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4969     if (ret != GST_FLOW_OK)
4970       goto corrupt_file;
4971     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4972         moof_offset, stream);
4973     gst_buffer_unref (buf);
4974 #endif
4975   }
4976
4977   check_update_duration (qtdemux, time);
4978
4979   return TRUE;
4980
4981 /* ERRORS */
4982 unknown_trackid:
4983   {
4984     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4985     return FALSE;
4986   }
4987 corrupt_file:
4988   {
4989     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4990     return FALSE;
4991   }
4992 no_samples:
4993   {
4994     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4995     return FALSE;
4996   }
4997 }
4998
4999 static gboolean
5000 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
5001 {
5002   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
5003   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
5004   GstBuffer *mfro = NULL, *mfra = NULL;
5005   GstFlowReturn flow;
5006   gboolean ret = FALSE;
5007   GNode *mfra_node, *tfra_node;
5008   guint64 mfra_offset = 0;
5009   guint32 fourcc, mfra_size;
5010   gint64 len;
5011
5012   /* query upstream size in bytes */
5013   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
5014     goto size_query_failed;
5015
5016   /* mfro box should be at the very end of the file */
5017   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
5018   if (flow != GST_FLOW_OK)
5019     goto exit;
5020
5021   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
5022
5023   fourcc = QT_FOURCC (mfro_map.data + 4);
5024   if (fourcc != FOURCC_mfro)
5025     goto exit;
5026
5027   GST_INFO_OBJECT (qtdemux, "Found mfro box");
5028   if (mfro_map.size < 16)
5029     goto invalid_mfro_size;
5030
5031   mfra_size = QT_UINT32 (mfro_map.data + 12);
5032   if (mfra_size >= len)
5033     goto invalid_mfra_size;
5034
5035   mfra_offset = len - mfra_size;
5036
5037   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
5038       mfra_offset, mfra_size);
5039
5040   /* now get and parse mfra box */
5041   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
5042   if (flow != GST_FLOW_OK)
5043     goto broken_file;
5044
5045   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
5046
5047   mfra_node = g_node_new ((guint8 *) mfra_map.data);
5048   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
5049
5050   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
5051
5052   while (tfra_node) {
5053     qtdemux_parse_tfra (qtdemux, tfra_node);
5054     /* iterate all siblings */
5055     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
5056   }
5057   g_node_destroy (mfra_node);
5058
5059   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
5060   ret = TRUE;
5061
5062 exit:
5063
5064   if (mfro) {
5065     if (mfro_map.memory != NULL)
5066       gst_buffer_unmap (mfro, &mfro_map);
5067     gst_buffer_unref (mfro);
5068   }
5069   if (mfra) {
5070     if (mfra_map.memory != NULL)
5071       gst_buffer_unmap (mfra, &mfra_map);
5072     gst_buffer_unref (mfra);
5073   }
5074   return ret;
5075
5076 /* ERRORS */
5077 size_query_failed:
5078   {
5079     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
5080     goto exit;
5081   }
5082 invalid_mfro_size:
5083   {
5084     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
5085     goto exit;
5086   }
5087 invalid_mfra_size:
5088   {
5089     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
5090     goto exit;
5091   }
5092 broken_file:
5093   {
5094     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
5095     goto exit;
5096   }
5097 }
5098
5099 static guint64
5100 add_offset (guint64 offset, guint64 advance)
5101 {
5102   /* Avoid 64-bit overflow by clamping */
5103   if (offset > G_MAXUINT64 - advance)
5104     return G_MAXUINT64;
5105   return offset + advance;
5106 }
5107
5108 static GstFlowReturn
5109 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
5110 {
5111   guint64 length = 0;
5112   guint32 fourcc = 0;
5113   GstBuffer *buf = NULL;
5114   GstFlowReturn ret = GST_FLOW_OK;
5115   guint64 cur_offset = qtdemux->offset;
5116   GstMapInfo map;
5117
5118   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
5119   if (G_UNLIKELY (ret != GST_FLOW_OK))
5120     goto beach;
5121   gst_buffer_map (buf, &map, GST_MAP_READ);
5122   if (G_LIKELY (map.size >= 8))
5123     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
5124   gst_buffer_unmap (buf, &map);
5125   gst_buffer_unref (buf);
5126
5127   /* maybe we already got most we needed, so only consider this eof */
5128   if (G_UNLIKELY (length == 0)) {
5129     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
5130         (_("Invalid atom size.")),
5131         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
5132             GST_FOURCC_ARGS (fourcc)));
5133     ret = GST_FLOW_EOS;
5134     goto beach;
5135   }
5136
5137   switch (fourcc) {
5138     case FOURCC_moof:
5139       /* record for later parsing when needed */
5140       if (!qtdemux->moof_offset) {
5141         qtdemux->moof_offset = qtdemux->offset;
5142       }
5143       if (qtdemux_pull_mfro_mfra (qtdemux)) {
5144         /* FIXME */
5145       } else {
5146         qtdemux->offset += length;      /* skip moof and keep going */
5147       }
5148       if (qtdemux->got_moov) {
5149         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
5150         ret = GST_FLOW_EOS;
5151         goto beach;
5152       }
5153       break;
5154     case FOURCC_mdat:
5155     case FOURCC_free:
5156     case FOURCC_skip:
5157     case FOURCC_wide:
5158     case FOURCC_PICT:
5159     case FOURCC_pnot:
5160     {
5161       GST_LOG_OBJECT (qtdemux,
5162           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
5163           GST_FOURCC_ARGS (fourcc), cur_offset);
5164       qtdemux->offset = add_offset (qtdemux->offset, length);
5165       break;
5166     }
5167     case FOURCC_moov:
5168     {
5169       GstBuffer *moov = NULL;
5170
5171       if (qtdemux->got_moov) {
5172         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
5173         qtdemux->offset = add_offset (qtdemux->offset, length);
5174         goto beach;
5175       }
5176
5177       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
5178       if (ret != GST_FLOW_OK)
5179         goto beach;
5180       gst_buffer_map (moov, &map, GST_MAP_READ);
5181
5182       if (length != map.size) {
5183         /* Some files have a 'moov' atom at the end of the file which contains
5184          * a terminal 'free' atom where the body of the atom is missing.
5185          * Check for, and permit, this special case.
5186          */
5187         if (map.size >= 8) {
5188           guint8 *final_data = map.data + (map.size - 8);
5189           guint32 final_length = QT_UINT32 (final_data);
5190           guint32 final_fourcc = QT_FOURCC (final_data + 4);
5191
5192           if (final_fourcc == FOURCC_free
5193               && map.size + final_length - 8 == length) {
5194             /* Ok, we've found that special case. Allocate a new buffer with
5195              * that free atom actually present. */
5196             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
5197             gst_buffer_fill (newmoov, 0, map.data, map.size);
5198             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
5199             gst_buffer_unmap (moov, &map);
5200             gst_buffer_unref (moov);
5201             moov = newmoov;
5202             gst_buffer_map (moov, &map, GST_MAP_READ);
5203           }
5204         }
5205       }
5206
5207       if (length != map.size) {
5208         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5209             (_("This file is incomplete and cannot be played.")),
5210             ("We got less than expected (received %" G_GSIZE_FORMAT
5211                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
5212                 (guint) length, cur_offset));
5213         gst_buffer_unmap (moov, &map);
5214         gst_buffer_unref (moov);
5215         ret = GST_FLOW_ERROR;
5216         goto beach;
5217       }
5218       qtdemux->offset += length;
5219
5220       qtdemux_parse_moov (qtdemux, map.data, length);
5221       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
5222
5223       qtdemux_parse_tree (qtdemux);
5224       if (qtdemux->moov_node_compressed) {
5225         g_node_destroy (qtdemux->moov_node_compressed);
5226         g_free (qtdemux->moov_node->data);
5227       }
5228       qtdemux->moov_node_compressed = NULL;
5229       g_node_destroy (qtdemux->moov_node);
5230       qtdemux->moov_node = NULL;
5231       gst_buffer_unmap (moov, &map);
5232       gst_buffer_unref (moov);
5233       qtdemux->got_moov = TRUE;
5234
5235       break;
5236     }
5237     case FOURCC_ftyp:
5238     {
5239       GstBuffer *ftyp = NULL;
5240
5241       /* extract major brand; might come in handy for ISO vs QT issues */
5242       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
5243       if (ret != GST_FLOW_OK)
5244         goto beach;
5245       qtdemux->offset += length;
5246       gst_buffer_map (ftyp, &map, GST_MAP_READ);
5247       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
5248       gst_buffer_unmap (ftyp, &map);
5249       gst_buffer_unref (ftyp);
5250       break;
5251     }
5252     case FOURCC_uuid:
5253     {
5254       GstBuffer *uuid = NULL;
5255
5256       /* uuid are extension atoms */
5257       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
5258       if (ret != GST_FLOW_OK)
5259         goto beach;
5260       qtdemux->offset += length;
5261       gst_buffer_map (uuid, &map, GST_MAP_READ);
5262       qtdemux_parse_uuid (qtdemux, map.data, map.size);
5263       gst_buffer_unmap (uuid, &map);
5264       gst_buffer_unref (uuid);
5265       break;
5266     }
5267     case FOURCC_sidx:
5268     {
5269       GstBuffer *sidx = NULL;
5270       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
5271       if (ret != GST_FLOW_OK)
5272         goto beach;
5273       qtdemux->offset += length;
5274       gst_buffer_map (sidx, &map, GST_MAP_READ);
5275       qtdemux_parse_sidx (qtdemux, map.data, map.size);
5276       gst_buffer_unmap (sidx, &map);
5277       gst_buffer_unref (sidx);
5278       break;
5279     }
5280     default:
5281     {
5282       GstBuffer *unknown = NULL;
5283
5284       GST_LOG_OBJECT (qtdemux,
5285           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
5286           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
5287           cur_offset);
5288       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
5289       if (ret != GST_FLOW_OK)
5290         goto beach;
5291       gst_buffer_map (unknown, &map, GST_MAP_READ);
5292       GST_MEMDUMP ("Unknown tag", map.data, map.size);
5293       gst_buffer_unmap (unknown, &map);
5294       gst_buffer_unref (unknown);
5295       qtdemux->offset += length;
5296       break;
5297     }
5298   }
5299
5300 beach:
5301   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
5302     /* digested all data, show what we have */
5303 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
5304     if (qtdemux->spherical_metadata)
5305       _send_spherical_metadata_msg_to_bus (qtdemux);
5306 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
5307     qtdemux_prepare_streams (qtdemux);
5308     QTDEMUX_EXPOSE_LOCK (qtdemux);
5309     ret = qtdemux_expose_streams (qtdemux);
5310     QTDEMUX_EXPOSE_UNLOCK (qtdemux);
5311
5312     qtdemux->state = QTDEMUX_STATE_MOVIE;
5313     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
5314         qtdemux->state);
5315     return ret;
5316   }
5317   return ret;
5318 }
5319
5320 /* Seeks to the previous keyframe of the indexed stream and
5321  * aligns other streams with respect to the keyframe timestamp
5322  * of indexed stream. Only called in case of Reverse Playback
5323  */
5324 static GstFlowReturn
5325 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
5326 {
5327   guint32 seg_idx = 0, k_index = 0;
5328   guint32 ref_seg_idx, ref_k_index;
5329   GstClockTime k_pos = 0, last_stop = 0;
5330   QtDemuxSegment *seg = NULL;
5331   QtDemuxStream *ref_str = NULL;
5332   guint64 seg_media_start_mov;  /* segment media start time in mov format */
5333   guint64 target_ts;
5334   gint i;
5335
5336   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
5337    * and finally align all the other streams on that timestamp with their
5338    * respective keyframes */
5339   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
5340     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
5341
5342     /* No candidate yet, take the first stream */
5343     if (!ref_str) {
5344       ref_str = str;
5345       continue;
5346     }
5347
5348     /* So that stream has a segment, we prefer video streams */
5349     if (str->subtype == FOURCC_vide) {
5350       ref_str = str;
5351       break;
5352     }
5353   }
5354
5355   if (G_UNLIKELY (!ref_str)) {
5356     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
5357     goto eos;
5358   }
5359
5360   if (G_UNLIKELY (!ref_str->from_sample)) {
5361     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
5362     goto eos;
5363   }
5364
5365   /* So that stream has been playing from from_sample to to_sample. We will
5366    * get the timestamp of the previous sample and search for a keyframe before
5367    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
5368   if (ref_str->subtype == FOURCC_vide) {
5369     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
5370         ref_str->from_sample - 1, FALSE);
5371   } else {
5372     if (ref_str->from_sample >= 10)
5373       k_index = ref_str->from_sample - 10;
5374     else
5375       k_index = 0;
5376   }
5377
5378   target_ts =
5379       ref_str->samples[k_index].timestamp +
5380       ref_str->samples[k_index].pts_offset;
5381
5382   /* get current segment for that stream */
5383   seg = &ref_str->segments[ref_str->segment_index];
5384   /* Use segment start in original timescale for comparisons */
5385   seg_media_start_mov = seg->trak_media_start;
5386
5387   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
5388       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT,
5389       k_index, target_ts, seg_media_start_mov,
5390       GST_TIME_ARGS (seg->media_start));
5391
5392   /* Crawl back through segments to find the one containing this I frame */
5393   while (target_ts < seg_media_start_mov) {
5394     GST_DEBUG_OBJECT (qtdemux,
5395         "keyframe position (sample %u) is out of segment %u " " target %"
5396         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
5397         ref_str->segment_index, target_ts, seg_media_start_mov);
5398
5399     if (G_UNLIKELY (!ref_str->segment_index)) {
5400       /* Reached first segment, let's consider it's EOS */
5401       goto eos;
5402     }
5403     ref_str->segment_index--;
5404     seg = &ref_str->segments[ref_str->segment_index];
5405     /* Use segment start in original timescale for comparisons */
5406     seg_media_start_mov = seg->trak_media_start;
5407   }
5408   /* Calculate time position of the keyframe and where we should stop */
5409   k_pos =
5410       QTSTREAMTIME_TO_GSTTIME (ref_str,
5411       target_ts - seg->trak_media_start) + seg->time;
5412   last_stop =
5413       QTSTREAMTIME_TO_GSTTIME (ref_str,
5414       ref_str->samples[ref_str->from_sample].timestamp -
5415       seg->trak_media_start) + seg->time;
5416
5417   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
5418       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
5419       k_index, GST_TIME_ARGS (k_pos));
5420
5421   /* Set last_stop with the keyframe timestamp we pushed of that stream */
5422   qtdemux->segment.position = last_stop;
5423   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
5424       GST_TIME_ARGS (last_stop));
5425
5426   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
5427     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
5428     goto eos;
5429   }
5430
5431   ref_seg_idx = ref_str->segment_index;
5432   ref_k_index = k_index;
5433
5434   /* Align them all on this */
5435   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
5436     guint32 index = 0;
5437     GstClockTime seg_time = 0;
5438     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
5439
5440     /* aligning reference stream again might lead to backing up to yet another
5441      * keyframe (due to timestamp rounding issues),
5442      * potentially putting more load on downstream; so let's try to avoid */
5443     if (str == ref_str) {
5444       seg_idx = ref_seg_idx;
5445       seg = &str->segments[seg_idx];
5446       k_index = ref_k_index;
5447       GST_DEBUG_OBJECT (qtdemux, "reference track-id %u segment %d, "
5448           "sample at index %d", str->track_id, ref_str->segment_index, k_index);
5449     } else {
5450       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
5451       GST_DEBUG_OBJECT (qtdemux,
5452           "track-id %u align segment %d for keyframe pos %" GST_TIME_FORMAT,
5453           str->track_id, seg_idx, GST_TIME_ARGS (k_pos));
5454
5455       /* get segment and time in the segment */
5456       seg = &str->segments[seg_idx];
5457       seg_time = k_pos - seg->time;
5458
5459       /* get the media time in the segment.
5460        * No adjustment for empty "filler" segments */
5461       if (seg->media_start != GST_CLOCK_TIME_NONE)
5462         seg_time += seg->media_start;
5463
5464       /* get the index of the sample with media time */
5465       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
5466       GST_DEBUG_OBJECT (qtdemux,
5467           "track-id %u sample for %" GST_TIME_FORMAT " at %u", str->track_id,
5468           GST_TIME_ARGS (seg_time), index);
5469
5470       /* find previous keyframe */
5471       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
5472     }
5473
5474     /* Remember until where we want to go */
5475     str->to_sample = str->from_sample - 1;
5476     /* Define our time position */
5477     target_ts =
5478         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
5479     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
5480     if (seg->media_start != GST_CLOCK_TIME_NONE)
5481       str->time_position -= seg->media_start;
5482
5483     /* Now seek back in time */
5484     gst_qtdemux_move_stream (qtdemux, str, k_index);
5485     GST_DEBUG_OBJECT (qtdemux, "track-id %u keyframe at %u, time position %"
5486         GST_TIME_FORMAT " playing from sample %u to %u", str->track_id, k_index,
5487         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
5488   }
5489
5490   return GST_FLOW_OK;
5491
5492 eos:
5493   return GST_FLOW_EOS;
5494 }
5495
5496 /*
5497  * Gets the current qt segment start, stop and position for the
5498  * given time offset. This is used in update_segment()
5499  */
5500 static void
5501 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5502     QtDemuxStream * stream, GstClockTime offset,
5503     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5504 {
5505   GstClockTime seg_time;
5506   GstClockTime start, stop, time;
5507   QtDemuxSegment *segment;
5508
5509   segment = &stream->segments[stream->segment_index];
5510
5511   /* get time in this segment */
5512   seg_time = (offset - segment->time) * segment->rate;
5513
5514   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5515       GST_TIME_ARGS (seg_time));
5516
5517   if (G_UNLIKELY (seg_time > segment->duration)) {
5518     GST_LOG_OBJECT (stream->pad,
5519         "seg_time > segment->duration %" GST_TIME_FORMAT,
5520         GST_TIME_ARGS (segment->duration));
5521     seg_time = segment->duration;
5522   }
5523
5524   /* qtdemux->segment.stop is in outside-time-realm, whereas
5525    * segment->media_stop is in track-time-realm.
5526    *
5527    * In order to compare the two, we need to bring segment.stop
5528    * into the track-time-realm
5529    *
5530    * FIXME - does this comment still hold? Don't see any conversion here */
5531
5532   stop = qtdemux->segment.stop;
5533   if (stop == GST_CLOCK_TIME_NONE)
5534     stop = qtdemux->segment.duration;
5535   if (stop == GST_CLOCK_TIME_NONE)
5536     stop = segment->media_stop;
5537   else
5538     stop =
5539         MIN (segment->media_stop, stop - segment->time + segment->media_start);
5540
5541   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5542     start = segment->time + seg_time;
5543     time = offset;
5544     stop = start - seg_time + segment->duration;
5545   } else if (qtdemux->segment.rate >= 0) {
5546     start = MIN (segment->media_start + seg_time, stop);
5547     time = offset;
5548   } else {
5549     if (segment->media_start >= qtdemux->segment.start) {
5550       time = segment->time;
5551     } else {
5552       time = segment->time + (qtdemux->segment.start - segment->media_start);
5553     }
5554
5555     start = MAX (segment->media_start, qtdemux->segment.start);
5556     stop = MIN (segment->media_start + seg_time, stop);
5557   }
5558
5559   *_start = start;
5560   *_stop = stop;
5561   *_time = time;
5562 }
5563
5564 /*
5565  * Updates the qt segment used for the stream and pushes a new segment event
5566  * downstream on this stream's pad.
5567  */
5568 static gboolean
5569 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5570     gint seg_idx, GstClockTime offset, GstClockTime * _start,
5571     GstClockTime * _stop)
5572 {
5573   QtDemuxSegment *segment;
5574   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5575   gdouble rate;
5576   GstEvent *event;
5577
5578   /* update the current segment */
5579   stream->segment_index = seg_idx;
5580
5581   /* get the segment */
5582   segment = &stream->segments[seg_idx];
5583
5584   if (G_UNLIKELY (offset < segment->time)) {
5585     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5586         GST_TIME_ARGS (segment->time));
5587     return FALSE;
5588   }
5589
5590   /* segment lies beyond total indicated duration */
5591   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5592           segment->time > qtdemux->segment.duration)) {
5593     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5594         " < segment->time %" GST_TIME_FORMAT,
5595         GST_TIME_ARGS (qtdemux->segment.duration),
5596         GST_TIME_ARGS (segment->time));
5597     return FALSE;
5598   }
5599
5600   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5601       &start, &stop, &time);
5602
5603   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5604       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5605       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5606
5607   /* combine global rate with that of the segment */
5608   rate = segment->rate * qtdemux->segment.rate;
5609
5610   /* Copy flags from main segment */
5611   stream->segment.flags = qtdemux->segment.flags;
5612
5613   /* update the segment values used for clipping */
5614   stream->segment.offset = qtdemux->segment.offset;
5615   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5616   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5617   stream->segment.rate = rate;
5618   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5619       stream->cslg_shift);
5620   stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5621       stream->cslg_shift);
5622   stream->segment.time = time;
5623   stream->segment.position = stream->segment.start;
5624
5625   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5626       &stream->segment);
5627
5628   /* now prepare and send the segment */
5629   if (stream->pad) {
5630     event = gst_event_new_segment (&stream->segment);
5631     if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
5632       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5633     }
5634     gst_pad_push_event (stream->pad, event);
5635     /* assume we can send more data now */
5636     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5637     /* clear to send tags on this pad now */
5638     gst_qtdemux_push_tags (qtdemux, stream);
5639   }
5640
5641   if (_start)
5642     *_start = start;
5643   if (_stop)
5644     *_stop = stop;
5645
5646   return TRUE;
5647 }
5648
5649 /* activate the given segment number @seg_idx of @stream at time @offset.
5650  * @offset is an absolute global position over all the segments.
5651  *
5652  * This will push out a NEWSEGMENT event with the right values and
5653  * position the stream index to the first decodable sample before
5654  * @offset.
5655  */
5656 static gboolean
5657 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5658     guint32 seg_idx, GstClockTime offset)
5659 {
5660   QtDemuxSegment *segment;
5661   guint32 index, kf_index;
5662   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5663
5664   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5665       seg_idx, GST_TIME_ARGS (offset));
5666
5667   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5668           &start, &stop))
5669     return FALSE;
5670
5671   segment = &stream->segments[stream->segment_index];
5672
5673   /* in the fragmented case, we pick a fragment that starts before our
5674    * desired position and rely on downstream to wait for a keyframe
5675    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5676    * tfra entries tells us which trun/sample the key unit is in, but we don't
5677    * make use of this additional information at the moment) */
5678   if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
5679     stream->to_sample = G_MAXUINT32;
5680     return TRUE;
5681   } else {
5682     /* well, it will be taken care of below */
5683     qtdemux->fragmented_seek_pending = FALSE;
5684     /* FIXME ideally the do_fragmented_seek can be done right here,
5685      * rather than at loop level
5686      * (which might even allow handling edit lists in a fragmented file) */
5687   }
5688
5689   /* We don't need to look for a sample in push-based */
5690   if (!qtdemux->pullbased)
5691     return TRUE;
5692
5693   /* and move to the keyframe before the indicated media time of the
5694    * segment */
5695   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5696     if (qtdemux->segment.rate >= 0) {
5697       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5698       stream->to_sample = G_MAXUINT32;
5699       GST_DEBUG_OBJECT (stream->pad,
5700           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5701           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5702           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5703     } else {
5704       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5705       stream->to_sample = index;
5706       GST_DEBUG_OBJECT (stream->pad,
5707           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5708           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5709           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5710     }
5711   } else {
5712     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5713         "this is an empty segment");
5714     return TRUE;
5715   }
5716
5717   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5718    * encountered an error and printed a message so we return appropriately */
5719   if (index == -1)
5720     return FALSE;
5721
5722   /* we're at the right spot */
5723   if (index == stream->sample_index) {
5724     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5725     return TRUE;
5726   }
5727
5728   /* find keyframe of the target index */
5729   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5730
5731 /* *INDENT-OFF* */
5732 /* indent does stupid stuff with stream->samples[].timestamp */
5733
5734   /* if we move forwards, we don't have to go back to the previous
5735    * keyframe since we already sent that. We can also just jump to
5736    * the keyframe right before the target index if there is one. */
5737   if (index > stream->sample_index) {
5738     /* moving forwards check if we move past a keyframe */
5739     if (kf_index > stream->sample_index) {
5740       GST_DEBUG_OBJECT (stream->pad,
5741            "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5742            GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5743            GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5744       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5745     } else {
5746       GST_DEBUG_OBJECT (stream->pad,
5747           "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5748           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5749           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5750     }
5751   } else {
5752     GST_DEBUG_OBJECT (stream->pad,
5753         "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5754         GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5755         GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5756     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5757   }
5758
5759 /* *INDENT-ON* */
5760
5761   return TRUE;
5762 }
5763
5764 /* prepare to get the current sample of @stream, getting essential values.
5765  *
5766  * This function will also prepare and send the segment when needed.
5767  *
5768  * Return FALSE if the stream is EOS.
5769  *
5770  * PULL-BASED
5771  */
5772 static gboolean
5773 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5774     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5775     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5776     gboolean * keyframe)
5777 {
5778   QtDemuxSample *sample;
5779   GstClockTime time_position;
5780   guint32 seg_idx;
5781
5782   g_return_val_if_fail (stream != NULL, FALSE);
5783
5784   time_position = stream->time_position;
5785   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5786     goto eos;
5787
5788   seg_idx = stream->segment_index;
5789   if (G_UNLIKELY (seg_idx == -1)) {
5790     /* find segment corresponding to time_position if we are looking
5791      * for a segment. */
5792     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5793   }
5794
5795   /* different segment, activate it, sample_index will be set. */
5796   if (G_UNLIKELY (stream->segment_index != seg_idx))
5797     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5798
5799   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->
5800               segments[stream->segment_index]))) {
5801     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5802
5803     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5804         " prepare empty sample");
5805
5806     *empty = TRUE;
5807     *pts = *dts = time_position;
5808     *duration = seg->duration - (time_position - seg->time);
5809
5810     return TRUE;
5811   }
5812
5813   *empty = FALSE;
5814
5815   if (stream->sample_index == -1)
5816     stream->sample_index = 0;
5817
5818   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5819       stream->sample_index, stream->n_samples);
5820
5821   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5822     if (!qtdemux->fragmented)
5823       goto eos;
5824
5825     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5826     do {
5827       GstFlowReturn flow;
5828
5829       GST_OBJECT_LOCK (qtdemux);
5830       flow = qtdemux_add_fragmented_samples (qtdemux);
5831       GST_OBJECT_UNLOCK (qtdemux);
5832
5833       if (flow != GST_FLOW_OK)
5834         goto eos;
5835     }
5836     while (stream->sample_index >= stream->n_samples);
5837   }
5838
5839   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5840     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5841         stream->sample_index);
5842     return FALSE;
5843   }
5844
5845   /* now get the info for the sample we're at */
5846   sample = &stream->samples[stream->sample_index];
5847
5848   *dts = QTSAMPLE_DTS (stream, sample);
5849   *pts = QTSAMPLE_PTS (stream, sample);
5850   *offset = sample->offset;
5851   *size = sample->size;
5852   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5853   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5854
5855   return TRUE;
5856
5857   /* special cases */
5858 eos:
5859   {
5860     stream->time_position = GST_CLOCK_TIME_NONE;
5861     return FALSE;
5862   }
5863 }
5864
5865 /* move to the next sample in @stream.
5866  *
5867  * Moves to the next segment when needed.
5868  */
5869 static void
5870 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5871 {
5872   QtDemuxSample *sample;
5873   QtDemuxSegment *segment;
5874
5875   /* get current segment */
5876   segment = &stream->segments[stream->segment_index];
5877
5878   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5879     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5880     goto next_segment;
5881   }
5882
5883   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5884     /* Mark the stream as EOS */
5885     GST_DEBUG_OBJECT (qtdemux,
5886         "reached max allowed sample %u, mark EOS", stream->to_sample);
5887     stream->time_position = GST_CLOCK_TIME_NONE;
5888     return;
5889   }
5890
5891   /* move to next sample */
5892   stream->sample_index++;
5893   stream->offset_in_sample = 0;
5894
5895   /* reached the last sample, we need the next segment */
5896   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5897     goto next_segment;
5898
5899   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5900     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5901         stream->sample_index);
5902     return;
5903   }
5904
5905   /* get next sample */
5906   sample = &stream->samples[stream->sample_index];
5907
5908   /* see if we are past the segment */
5909   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5910     goto next_segment;
5911
5912   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5913     /* inside the segment, update time_position, looks very familiar to
5914      * GStreamer segments, doesn't it? */
5915     stream->time_position =
5916         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5917   } else {
5918     /* not yet in segment, time does not yet increment. This means
5919      * that we are still prerolling keyframes to the decoder so it can
5920      * decode the first sample of the segment. */
5921     stream->time_position = segment->time;
5922   }
5923   return;
5924
5925   /* move to the next segment */
5926 next_segment:
5927   {
5928     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5929
5930     if (stream->segment_index == stream->n_segments - 1) {
5931       /* are we at the end of the last segment, we're EOS */
5932       stream->time_position = GST_CLOCK_TIME_NONE;
5933     } else {
5934       /* else we're only at the end of the current segment */
5935       stream->time_position = segment->stop_time;
5936     }
5937     /* make sure we select a new segment */
5938
5939     /* accumulate previous segments */
5940     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5941       stream->accumulated_base +=
5942           (stream->segment.stop -
5943           stream->segment.start) / ABS (stream->segment.rate);
5944
5945     stream->segment_index = -1;
5946   }
5947 }
5948
5949 static void
5950 gst_qtdemux_sync_streams (GstQTDemux * demux)
5951 {
5952   gint i;
5953
5954   if (QTDEMUX_N_STREAMS (demux) <= 1)
5955     return;
5956
5957   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
5958     QtDemuxStream *stream;
5959     GstClockTime end_time;
5960
5961     stream = QTDEMUX_NTH_STREAM (demux, i);
5962
5963     if (!stream->pad)
5964       continue;
5965
5966     /* TODO advance time on subtitle streams here, if any some day */
5967
5968     /* some clips/trailers may have unbalanced streams at the end,
5969      * so send EOS on shorter stream to prevent stalling others */
5970
5971     /* do not mess with EOS if SEGMENT seeking */
5972     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5973       continue;
5974
5975     if (demux->pullbased) {
5976       /* loop mode is sample time based */
5977       if (!STREAM_IS_EOS (stream))
5978         continue;
5979     } else {
5980       /* push mode is byte position based */
5981       if (stream->n_samples &&
5982           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5983         continue;
5984     }
5985
5986     if (stream->sent_eos)
5987       continue;
5988
5989     /* only act if some gap */
5990     end_time = stream->segments[stream->n_segments - 1].stop_time;
5991     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5992         ", stream end: %" GST_TIME_FORMAT,
5993         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5994     if (GST_CLOCK_TIME_IS_VALID (end_time)
5995         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5996       GstEvent *event;
5997
5998       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5999           GST_PAD_NAME (stream->pad));
6000       stream->sent_eos = TRUE;
6001       event = gst_event_new_eos ();
6002       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
6003         gst_event_set_seqnum (event, demux->segment_seqnum);
6004       gst_pad_push_event (stream->pad, event);
6005     }
6006   }
6007 }
6008
6009 /* EOS and NOT_LINKED need to be combined. This means that we return:
6010  *
6011  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
6012  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
6013  */
6014 static GstFlowReturn
6015 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
6016     GstFlowReturn ret)
6017 {
6018   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
6019
6020   if (stream->pad)
6021     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
6022         ret);
6023   else
6024     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
6025
6026   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
6027   return ret;
6028 }
6029
6030 /* the input buffer metadata must be writable. Returns NULL when the buffer is
6031  * completely clipped
6032  *
6033  * Should be used only with raw buffers */
6034 static GstBuffer *
6035 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6036     GstBuffer * buf)
6037 {
6038   guint64 start, stop, cstart, cstop, diff;
6039   GstClockTime pts, duration;
6040   gsize size, osize;
6041   gint num_rate, denom_rate;
6042   gint frame_size;
6043   gboolean clip_data;
6044   guint offset;
6045
6046   osize = size = gst_buffer_get_size (buf);
6047   offset = 0;
6048
6049   /* depending on the type, setup the clip parameters */
6050   if (stream->subtype == FOURCC_soun) {
6051     frame_size = CUR_STREAM (stream)->bytes_per_frame;
6052     num_rate = GST_SECOND;
6053     denom_rate = (gint) CUR_STREAM (stream)->rate;
6054     clip_data = TRUE;
6055   } else if (stream->subtype == FOURCC_vide) {
6056     frame_size = size;
6057     num_rate = CUR_STREAM (stream)->fps_n;
6058     denom_rate = CUR_STREAM (stream)->fps_d;
6059     clip_data = FALSE;
6060   } else
6061     goto wrong_type;
6062
6063   if (frame_size <= 0)
6064     goto bad_frame_size;
6065
6066   /* we can only clip if we have a valid pts */
6067   pts = GST_BUFFER_PTS (buf);
6068   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
6069     goto no_pts;
6070
6071   duration = GST_BUFFER_DURATION (buf);
6072
6073   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
6074     duration =
6075         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
6076   }
6077
6078   start = pts;
6079   stop = start + duration;
6080
6081   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
6082               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
6083     goto clipped;
6084
6085   /* see if some clipping happened */
6086   diff = cstart - start;
6087   if (diff > 0) {
6088     pts += diff;
6089     duration -= diff;
6090
6091     if (clip_data) {
6092       /* bring clipped time to samples and to bytes */
6093       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
6094       diff *= frame_size;
6095
6096       GST_DEBUG_OBJECT (qtdemux,
6097           "clipping start to %" GST_TIME_FORMAT " %"
6098           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
6099
6100       offset = diff;
6101       size -= diff;
6102     }
6103   }
6104   diff = stop - cstop;
6105   if (diff > 0) {
6106     duration -= diff;
6107
6108     if (clip_data) {
6109       /* bring clipped time to samples and then to bytes */
6110       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
6111       diff *= frame_size;
6112       GST_DEBUG_OBJECT (qtdemux,
6113           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
6114           " bytes", GST_TIME_ARGS (cstop), diff);
6115       size -= diff;
6116     }
6117   }
6118
6119   if (offset != 0 || size != osize)
6120     gst_buffer_resize (buf, offset, size);
6121
6122   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
6123   GST_BUFFER_PTS (buf) = pts;
6124   GST_BUFFER_DURATION (buf) = duration;
6125
6126   return buf;
6127
6128   /* dropped buffer */
6129 wrong_type:
6130   {
6131     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6132     return buf;
6133   }
6134 bad_frame_size:
6135   {
6136     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
6137     return buf;
6138   }
6139 no_pts:
6140   {
6141     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
6142     return buf;
6143   }
6144 clipped:
6145   {
6146     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
6147     gst_buffer_unref (buf);
6148     return NULL;
6149   }
6150 }
6151
6152 static GstBuffer *
6153 gst_qtdemux_align_buffer (GstQTDemux * demux,
6154     GstBuffer * buffer, gsize alignment)
6155 {
6156   GstMapInfo map;
6157
6158   gst_buffer_map (buffer, &map, GST_MAP_READ);
6159
6160   if (map.size < sizeof (guintptr)) {
6161     gst_buffer_unmap (buffer, &map);
6162     return buffer;
6163   }
6164
6165   if (((guintptr) map.data) & (alignment - 1)) {
6166     GstBuffer *new_buffer;
6167     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
6168
6169     new_buffer = gst_buffer_new_allocate (NULL,
6170         gst_buffer_get_size (buffer), &params);
6171
6172     /* Copy data "by hand", so ensure alignment is kept: */
6173     gst_buffer_fill (new_buffer, 0, map.data, map.size);
6174
6175     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
6176     GST_DEBUG_OBJECT (demux,
6177         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
6178         alignment);
6179
6180     gst_buffer_unmap (buffer, &map);
6181     gst_buffer_unref (buffer);
6182
6183     return new_buffer;
6184   }
6185
6186   gst_buffer_unmap (buffer, &map);
6187   return buffer;
6188 }
6189
6190 static guint8 *
6191 convert_to_s334_1a (const guint8 * ccpair, guint8 ccpair_size, guint field,
6192     gsize * res)
6193 {
6194   guint8 *storage;
6195   gsize i;
6196
6197   /* We are converting from pairs to triplets */
6198   *res = ccpair_size / 2 * 3;
6199   storage = g_malloc (*res);
6200   for (i = 0; i * 2 < ccpair_size; i += 1) {
6201     /* FIXME: Use line offset 0 as we simply can't know here */
6202     if (field == 1)
6203       storage[i * 3] = 0x80 | 0x00;
6204     else
6205       storage[i * 3] = 0x00 | 0x00;
6206     storage[i * 3 + 1] = ccpair[i * 2];
6207     storage[i * 3 + 2] = ccpair[i * 2 + 1];
6208   }
6209
6210   return storage;
6211 }
6212
6213 static guint8 *
6214 extract_cc_from_data (QtDemuxStream * stream, const guint8 * data, gsize size,
6215     gsize * cclen)
6216 {
6217   guint8 *res = NULL;
6218   guint32 atom_length, fourcc;
6219   QtDemuxStreamStsdEntry *stsd_entry;
6220
6221   GST_MEMDUMP ("caption atom", data, size);
6222
6223   /* There might be multiple atoms */
6224
6225   *cclen = 0;
6226   if (size < 8)
6227     goto invalid_cdat;
6228   atom_length = QT_UINT32 (data);
6229   fourcc = QT_FOURCC (data + 4);
6230   if (G_UNLIKELY (atom_length > size || atom_length == 8))
6231     goto invalid_cdat;
6232
6233   GST_DEBUG_OBJECT (stream->pad, "here");
6234
6235   /* Check if we have somethig compatible */
6236   stsd_entry = CUR_STREAM (stream);
6237   switch (stsd_entry->fourcc) {
6238     case FOURCC_c608:{
6239       guint8 *cdat = NULL, *cdt2 = NULL;
6240       gsize cdat_size = 0, cdt2_size = 0;
6241       /* Should be cdat or cdt2 */
6242       if (fourcc != FOURCC_cdat && fourcc != FOURCC_cdt2) {
6243         GST_WARNING_OBJECT (stream->pad,
6244             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA608",
6245             GST_FOURCC_ARGS (fourcc));
6246         goto invalid_cdat;
6247       }
6248
6249       /* Convert to S334-1 Annex A byte triplet */
6250       if (fourcc == FOURCC_cdat)
6251         cdat = convert_to_s334_1a (data + 8, atom_length - 8, 1, &cdat_size);
6252       else
6253         cdt2 = convert_to_s334_1a (data + 8, atom_length - 8, 2, &cdt2_size);
6254       GST_DEBUG_OBJECT (stream->pad, "size:%" G_GSIZE_FORMAT " atom_length:%u",
6255           size, atom_length);
6256
6257       /* Check for another atom ? */
6258       if (size > atom_length + 8) {
6259         guint32 new_atom_length = QT_UINT32 (data + atom_length);
6260         if (size >= atom_length + new_atom_length) {
6261           fourcc = QT_FOURCC (data + atom_length + 4);
6262           if (fourcc == FOURCC_cdat) {
6263             if (cdat == NULL)
6264               cdat =
6265                   convert_to_s334_1a (data + atom_length + 8,
6266                   new_atom_length - 8, 1, &cdat_size);
6267             else
6268               GST_WARNING_OBJECT (stream->pad,
6269                   "Got multiple [cdat] atoms in a c608 sample. This is unsupported for now. Please file a bug");
6270           } else {
6271             if (cdt2 == NULL)
6272               cdt2 =
6273                   convert_to_s334_1a (data + atom_length + 8,
6274                   new_atom_length - 8, 2, &cdt2_size);
6275             else
6276               GST_WARNING_OBJECT (stream->pad,
6277                   "Got multiple [cdt2] atoms in a c608 sample. This is unsupported for now. Please file a bug");
6278           }
6279         }
6280       }
6281
6282       *cclen = cdat_size + cdt2_size;
6283       res = g_malloc (*cclen);
6284       if (cdat_size)
6285         memcpy (res, cdat, cdat_size);
6286       if (cdt2_size)
6287         memcpy (res + cdat_size, cdt2, cdt2_size);
6288       g_free (cdat);
6289       g_free (cdt2);
6290     }
6291       break;
6292     case FOURCC_c708:
6293       if (fourcc != FOURCC_ccdp) {
6294         GST_WARNING_OBJECT (stream->pad,
6295             "Unknown data atom (%" GST_FOURCC_FORMAT ") for CEA708",
6296             GST_FOURCC_ARGS (fourcc));
6297         goto invalid_cdat;
6298       }
6299       *cclen = atom_length - 8;
6300       res = g_memdup (data + 8, *cclen);
6301       break;
6302     default:
6303       /* Keep this here in case other closed caption formats are added */
6304       g_assert_not_reached ();
6305       break;
6306   }
6307
6308   GST_MEMDUMP ("Output", res, *cclen);
6309   return res;
6310
6311   /* Errors */
6312 invalid_cdat:
6313   GST_WARNING ("[cdat] atom is too small or invalid");
6314   return NULL;
6315 }
6316
6317 /* the input buffer metadata must be writable,
6318  * but time/duration etc not yet set and need not be preserved */
6319 static GstBuffer *
6320 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6321     GstBuffer * buf)
6322 {
6323   GstMapInfo map;
6324   guint nsize = 0;
6325   gchar *str;
6326
6327   /* not many cases for now */
6328   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
6329     /* send a one time dvd clut event */
6330     if (stream->pending_event && stream->pad)
6331       gst_pad_push_event (stream->pad, stream->pending_event);
6332     stream->pending_event = NULL;
6333   }
6334
6335   if (G_UNLIKELY (stream->subtype != FOURCC_text
6336           && stream->subtype != FOURCC_sbtl &&
6337           stream->subtype != FOURCC_subp && stream->subtype != FOURCC_clcp)) {
6338     return buf;
6339   }
6340
6341   gst_buffer_map (buf, &map, GST_MAP_READ);
6342
6343   /* empty buffer is sent to terminate previous subtitle */
6344   if (map.size <= 2) {
6345     gst_buffer_unmap (buf, &map);
6346     gst_buffer_unref (buf);
6347     return NULL;
6348   }
6349   if (stream->subtype == FOURCC_subp) {
6350     /* That's all the processing needed for subpictures */
6351     gst_buffer_unmap (buf, &map);
6352     return buf;
6353   }
6354
6355   if (stream->subtype == FOURCC_clcp) {
6356     guint8 *cc;
6357     gsize cclen = 0;
6358     /* For closed caption, we need to extract the information from the
6359      * [cdat],[cdt2] or [ccdp] atom */
6360     cc = extract_cc_from_data (stream, map.data, map.size, &cclen);
6361     gst_buffer_unmap (buf, &map);
6362     gst_buffer_unref (buf);
6363     if (cc) {
6364       buf = _gst_buffer_new_wrapped (cc, cclen, g_free);
6365     } else {
6366       /* Conversion failed or there's nothing */
6367       buf = NULL;
6368     }
6369     return buf;
6370   }
6371
6372   nsize = GST_READ_UINT16_BE (map.data);
6373   nsize = MIN (nsize, map.size - 2);
6374
6375   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
6376       nsize, map.size);
6377
6378   /* takes care of UTF-8 validation or UTF-16 recognition,
6379    * no other encoding expected */
6380   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
6381   gst_buffer_unmap (buf, &map);
6382   if (str) {
6383     gst_buffer_unref (buf);
6384     buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
6385   } else {
6386     /* this should not really happen unless the subtitle is corrupted */
6387     gst_buffer_unref (buf);
6388     buf = NULL;
6389   }
6390
6391   /* FIXME ? convert optional subsequent style info to markup */
6392
6393   return buf;
6394 }
6395
6396 static GstFlowReturn
6397 gst_qtdemux_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6398     GstBuffer * buf)
6399 {
6400   GstFlowReturn ret = GST_FLOW_OK;
6401   GstClockTime pts, duration;
6402
6403   if (stream->need_clip)
6404     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6405
6406   if (G_UNLIKELY (buf == NULL))
6407     goto exit;
6408
6409   if (G_UNLIKELY (stream->discont)) {
6410     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6411     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6412     stream->discont = FALSE;
6413   } else {
6414     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6415   }
6416
6417   GST_LOG_OBJECT (qtdemux,
6418       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6419       ", duration %" GST_TIME_FORMAT " on pad %s",
6420       GST_TIME_ARGS (GST_BUFFER_DTS (buf)),
6421       GST_TIME_ARGS (GST_BUFFER_PTS (buf)),
6422       GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
6423
6424   if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
6425     GstStructure *crypto_info;
6426     QtDemuxCencSampleSetInfo *info =
6427         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6428     gint index;
6429     GstEvent *event;
6430
6431     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6432       GST_TRACE_OBJECT (stream->pad, "pushing protection event: %"
6433           GST_PTR_FORMAT, event);
6434       gst_pad_push_event (stream->pad, event);
6435     }
6436
6437     if (info->crypto_info == NULL) {
6438       GST_DEBUG_OBJECT (qtdemux,
6439           "cenc metadata hasn't been parsed yet, pushing buffer as if it wasn't encrypted");
6440     } else {
6441       /* The end of the crypto_info array matches our n_samples position,
6442        * so count backward from there */
6443       index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6444       if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6445         /* steal structure from array */
6446         crypto_info = g_ptr_array_index (info->crypto_info, index);
6447         g_ptr_array_index (info->crypto_info, index) = NULL;
6448         GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6449             info->crypto_info->len);
6450         if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6451           GST_ERROR_OBJECT (qtdemux,
6452               "failed to attach cenc metadata to buffer");
6453       } else {
6454         GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6455             index, stream->sample_index);
6456       }
6457     }
6458   }
6459
6460   if (stream->alignment > 1)
6461     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6462
6463   pts = GST_BUFFER_PTS (buf);
6464   duration = GST_BUFFER_DURATION (buf);
6465
6466   ret = gst_pad_push (stream->pad, buf);
6467
6468   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6469     /* mark position in stream, we'll need this to know when to send GAP event */
6470     stream->segment.position = pts + duration;
6471   }
6472
6473 exit:
6474
6475   return ret;
6476 }
6477
6478 static GstFlowReturn
6479 gst_qtdemux_split_and_push_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
6480     GstBuffer * buf)
6481 {
6482   GstFlowReturn ret = GST_FLOW_OK;
6483
6484   if (stream->subtype == FOURCC_clcp
6485       && CUR_STREAM (stream)->fourcc == FOURCC_c608 && stream->need_split) {
6486     GstMapInfo map;
6487     guint n_output_buffers, n_field1 = 0, n_field2 = 0;
6488     guint n_triplets, i;
6489     guint field1_off = 0, field2_off = 0;
6490
6491     /* We have to split CEA608 buffers so that each outgoing buffer contains
6492      * one byte pair per field according to the framerate of the video track.
6493      *
6494      * If there is only a single byte pair per field we don't have to do
6495      * anything
6496      */
6497
6498     gst_buffer_map (buf, &map, GST_MAP_READ);
6499
6500     n_triplets = map.size / 3;
6501     for (i = 0; i < n_triplets; i++) {
6502       if (map.data[3 * i] & 0x80)
6503         n_field1++;
6504       else
6505         n_field2++;
6506     }
6507
6508     g_assert (n_field1 || n_field2);
6509
6510     /* If there's more than 1 frame we have to split, otherwise we can just
6511      * pass through */
6512     if (n_field1 > 1 || n_field2 > 1) {
6513       n_output_buffers =
6514           gst_util_uint64_scale (GST_BUFFER_DURATION (buf),
6515           CUR_STREAM (stream)->fps_n, GST_SECOND * CUR_STREAM (stream)->fps_d);
6516
6517       for (i = 0; i < n_output_buffers; i++) {
6518         GstBuffer *outbuf =
6519             gst_buffer_new_and_alloc ((n_field1 ? 3 : 0) + (n_field2 ? 3 : 0));
6520         GstMapInfo outmap;
6521         guint8 *outptr;
6522
6523         gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
6524         outptr = outmap.data;
6525
6526         if (n_field1) {
6527           gboolean found = FALSE;
6528
6529           while (map.data + field1_off < map.data + map.size) {
6530             if (map.data[field1_off] & 0x80) {
6531               memcpy (outptr, &map.data[field1_off], 3);
6532               field1_off += 3;
6533               found = TRUE;
6534               break;
6535             }
6536             field1_off += 3;
6537           }
6538
6539           if (!found) {
6540             const guint8 empty[] = { 0x80, 0x80, 0x80 };
6541
6542             memcpy (outptr, empty, 3);
6543           }
6544
6545           outptr += 3;
6546         }
6547
6548         if (n_field2) {
6549           gboolean found = FALSE;
6550
6551           while (map.data + field2_off < map.data + map.size) {
6552             if ((map.data[field2_off] & 0x80) == 0) {
6553               memcpy (outptr, &map.data[field2_off], 3);
6554               field2_off += 3;
6555               found = TRUE;
6556               break;
6557             }
6558             field2_off += 3;
6559           }
6560
6561           if (!found) {
6562             const guint8 empty[] = { 0x00, 0x80, 0x80 };
6563
6564             memcpy (outptr, empty, 3);
6565           }
6566
6567           outptr += 3;
6568         }
6569
6570         gst_buffer_unmap (outbuf, &outmap);
6571
6572         GST_BUFFER_PTS (outbuf) =
6573             GST_BUFFER_PTS (buf) + gst_util_uint64_scale (i,
6574             GST_SECOND * CUR_STREAM (stream)->fps_d,
6575             CUR_STREAM (stream)->fps_n);
6576         GST_BUFFER_DURATION (outbuf) =
6577             gst_util_uint64_scale (GST_SECOND, CUR_STREAM (stream)->fps_d,
6578             CUR_STREAM (stream)->fps_n);
6579         GST_BUFFER_OFFSET (outbuf) = -1;
6580         GST_BUFFER_OFFSET_END (outbuf) = -1;
6581
6582         ret = gst_qtdemux_push_buffer (qtdemux, stream, outbuf);
6583
6584         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED)
6585           break;
6586       }
6587       gst_buffer_unmap (buf, &map);
6588       gst_buffer_unref (buf);
6589     } else {
6590       gst_buffer_unmap (buf, &map);
6591       ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6592     }
6593   } else {
6594     ret = gst_qtdemux_push_buffer (qtdemux, stream, buf);
6595   }
6596
6597   return ret;
6598 }
6599
6600 /* Sets a buffer's attributes properly and pushes it downstream.
6601  * Also checks for additional actions and custom processing that may
6602  * need to be done first.
6603  */
6604 static GstFlowReturn
6605 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
6606     QtDemuxStream * stream, GstBuffer * buf,
6607     GstClockTime dts, GstClockTime pts, GstClockTime duration,
6608     gboolean keyframe, GstClockTime position, guint64 byte_position)
6609 {
6610   GstFlowReturn ret = GST_FLOW_OK;
6611
6612   /* offset the timestamps according to the edit list */
6613
6614   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
6615     gchar *url;
6616     GstMapInfo map;
6617
6618     gst_buffer_map (buf, &map, GST_MAP_READ);
6619     url = g_strndup ((gchar *) map.data, map.size);
6620     gst_buffer_unmap (buf, &map);
6621     if (url != NULL && strlen (url) != 0) {
6622       /* we have RTSP redirect now */
6623       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
6624           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
6625               gst_structure_new ("redirect",
6626                   "new-location", G_TYPE_STRING, url, NULL)));
6627       qtdemux->posted_redirect = TRUE;
6628     } else {
6629       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6630           "posting");
6631     }
6632     g_free (url);
6633   }
6634
6635   /* position reporting */
6636   if (qtdemux->segment.rate >= 0) {
6637     qtdemux->segment.position = position;
6638     gst_qtdemux_sync_streams (qtdemux);
6639   }
6640
6641   if (G_UNLIKELY (!stream->pad)) {
6642     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6643     gst_buffer_unref (buf);
6644     goto exit;
6645   }
6646
6647   /* send out pending buffers */
6648   while (stream->buffers) {
6649     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6650
6651     if (G_UNLIKELY (stream->discont)) {
6652       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6653       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6654       stream->discont = FALSE;
6655     } else {
6656       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6657     }
6658
6659     if (stream->alignment > 1)
6660       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6661     gst_pad_push (stream->pad, buffer);
6662
6663     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6664   }
6665
6666   /* we're going to modify the metadata */
6667   buf = gst_buffer_make_writable (buf);
6668
6669   if (G_UNLIKELY (stream->need_process))
6670     buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
6671
6672   if (!buf) {
6673     goto exit;
6674   }
6675
6676   GST_BUFFER_DTS (buf) = dts;
6677   GST_BUFFER_PTS (buf) = pts;
6678   GST_BUFFER_DURATION (buf) = duration;
6679   GST_BUFFER_OFFSET (buf) = -1;
6680   GST_BUFFER_OFFSET_END (buf) = -1;
6681
6682   if (!keyframe) {
6683     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6684     stream->on_keyframe = FALSE;
6685   } else {
6686     stream->on_keyframe = TRUE;
6687   }
6688
6689   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6690     gst_buffer_append_memory (buf,
6691         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6692
6693   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6694     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6695   }
6696 #if 0
6697   if (G_UNLIKELY (qtdemux->element_index)) {
6698     GstClockTime stream_time;
6699
6700     stream_time =
6701         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6702         timestamp);
6703     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6704       GST_LOG_OBJECT (qtdemux,
6705           "adding association %" GST_TIME_FORMAT "-> %"
6706           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6707       gst_index_add_association (qtdemux->element_index,
6708           qtdemux->index_id,
6709           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6710           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6711           GST_FORMAT_BYTES, byte_position, NULL);
6712     }
6713   }
6714 #endif
6715
6716   ret = gst_qtdemux_split_and_push_buffer (qtdemux, stream, buf);
6717
6718 exit:
6719   return ret;
6720 }
6721
6722 static const QtDemuxRandomAccessEntry *
6723 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6724     GstClockTime pos, gboolean after)
6725 {
6726   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6727   guint n_entries = stream->n_ra_entries;
6728   guint i;
6729
6730   /* we assume the table is sorted */
6731   for (i = 0; i < n_entries; ++i) {
6732     if (entries[i].ts > pos)
6733       break;
6734   }
6735
6736   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6737    * probably okay to assume that the index lists the very first fragment */
6738   if (i == 0)
6739     return &entries[0];
6740
6741   if (after)
6742     return &entries[i];
6743   else
6744     return &entries[i - 1];
6745 }
6746
6747 static gboolean
6748 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6749 {
6750   const QtDemuxRandomAccessEntry *best_entry = NULL;
6751   gint i;
6752
6753   GST_OBJECT_LOCK (qtdemux);
6754
6755   g_assert (QTDEMUX_N_STREAMS (qtdemux) > 0);
6756
6757   /* first see if we can determine where to go to using mfra,
6758    * before we start clearing things */
6759   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6760     const QtDemuxRandomAccessEntry *entry;
6761     QtDemuxStream *stream;
6762     gboolean is_audio_or_video;
6763
6764     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6765
6766     if (stream->ra_entries == NULL)
6767       continue;
6768
6769     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6770       is_audio_or_video = TRUE;
6771     else
6772       is_audio_or_video = FALSE;
6773
6774     entry =
6775         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6776         stream->time_position, !is_audio_or_video);
6777
6778     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6779         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6780
6781     stream->pending_seek = entry;
6782
6783     /* decide position to jump to just based on audio/video tracks, not subs */
6784     if (!is_audio_or_video)
6785       continue;
6786
6787     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6788       best_entry = entry;
6789   }
6790
6791   /* no luck, will handle seek otherwise */
6792   if (best_entry == NULL) {
6793     GST_OBJECT_UNLOCK (qtdemux);
6794     return FALSE;
6795   }
6796
6797   /* ok, now we can prepare for processing as of located moof */
6798   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6799     QtDemuxStream *stream;
6800
6801     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6802
6803     g_free (stream->samples);
6804     stream->samples = NULL;
6805     stream->n_samples = 0;
6806     stream->stbl_index = -1;    /* no samples have yet been parsed */
6807     stream->sample_index = -1;
6808
6809     if (stream->protection_scheme_info) {
6810       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6811       if (stream->protection_scheme_type == FOURCC_cenc) {
6812         QtDemuxCencSampleSetInfo *info =
6813             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6814         if (info->crypto_info) {
6815           g_ptr_array_free (info->crypto_info, TRUE);
6816           info->crypto_info = NULL;
6817         }
6818       }
6819     }
6820   }
6821
6822   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6823       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6824       GST_TIME_ARGS (QTDEMUX_NTH_STREAM (qtdemux, 0)->time_position),
6825       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6826
6827   qtdemux->moof_offset = best_entry->moof_offset;
6828
6829   qtdemux_add_fragmented_samples (qtdemux);
6830
6831   GST_OBJECT_UNLOCK (qtdemux);
6832   return TRUE;
6833 }
6834
6835 static GstFlowReturn
6836 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6837 {
6838   GstFlowReturn ret = GST_FLOW_OK;
6839   GstBuffer *buf = NULL;
6840   QtDemuxStream *stream, *target_stream = NULL;
6841   GstClockTime min_time;
6842   guint64 offset = 0;
6843   GstClockTime dts = GST_CLOCK_TIME_NONE;
6844   GstClockTime pts = GST_CLOCK_TIME_NONE;
6845   GstClockTime duration = 0;
6846   gboolean keyframe = FALSE;
6847   guint sample_size = 0;
6848   gboolean empty = 0;
6849   guint size;
6850   gint i;
6851
6852   if (qtdemux->fragmented_seek_pending) {
6853     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6854     if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
6855       GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6856       qtdemux->fragmented_seek_pending = FALSE;
6857     } else {
6858       GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
6859     }
6860   }
6861
6862   /* Figure out the next stream sample to output, min_time is expressed in
6863    * global time and runs over the edit list segments. */
6864   min_time = G_MAXUINT64;
6865   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6866     GstClockTime position;
6867
6868     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6869     position = stream->time_position;
6870
6871     /* position of -1 is EOS */
6872     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6873       min_time = position;
6874       target_stream = stream;
6875     }
6876   }
6877   /* all are EOS */
6878   if (G_UNLIKELY (target_stream == NULL)) {
6879     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6880     goto eos;
6881   }
6882
6883   /* check for segment end */
6884   if (G_UNLIKELY (qtdemux->segment.stop != -1
6885           && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6886               || (qtdemux->segment.rate < 0
6887                   && qtdemux->segment.start > min_time))
6888           && target_stream->on_keyframe)) {
6889     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6890     target_stream->time_position = GST_CLOCK_TIME_NONE;
6891     goto eos_stream;
6892   }
6893
6894   /* gap events for subtitle streams */
6895   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
6896     stream = QTDEMUX_NTH_STREAM (qtdemux, i);
6897     if (stream->pad && (stream->subtype == FOURCC_subp
6898             || stream->subtype == FOURCC_text
6899             || stream->subtype == FOURCC_sbtl)) {
6900       /* send one second gap events until the stream catches up */
6901       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6902       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6903           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6904           stream->segment.position + GST_SECOND < min_time) {
6905         GstEvent *gap =
6906             gst_event_new_gap (stream->segment.position, GST_SECOND);
6907         gst_pad_push_event (stream->pad, gap);
6908         stream->segment.position += GST_SECOND;
6909       }
6910     }
6911   }
6912
6913   stream = target_stream;
6914   /* fetch info for the current sample of this stream */
6915   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6916               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6917     goto eos_stream;
6918
6919   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6920   if (stream->new_caps) {
6921     gst_qtdemux_configure_stream (qtdemux, stream);
6922     qtdemux_do_allocation (stream, qtdemux);
6923   }
6924
6925   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6926   if (G_UNLIKELY (qtdemux->segment.
6927           flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6928     if (stream->subtype == FOURCC_vide && !keyframe) {
6929       GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on track-id %u",
6930           stream->track_id);
6931       goto next;
6932     }
6933   }
6934
6935   GST_DEBUG_OBJECT (qtdemux,
6936       "pushing from track-id %u, empty %d offset %" G_GUINT64_FORMAT
6937       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6938       ", duration %" GST_TIME_FORMAT, stream->track_id, empty, offset,
6939       sample_size, GST_TIME_ARGS (dts), GST_TIME_ARGS (pts),
6940       GST_TIME_ARGS (duration));
6941
6942   if (G_UNLIKELY (empty)) {
6943     /* empty segment, push a gap if there's a second or more
6944      * difference and move to the next one */
6945     if ((pts + duration - stream->segment.position) >= GST_SECOND)
6946       gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6947     stream->segment.position = pts + duration;
6948     goto next;
6949   }
6950
6951   /* hmm, empty sample, skip and move to next sample */
6952   if (G_UNLIKELY (sample_size <= 0))
6953     goto next;
6954
6955   /* last pushed sample was out of boundary, goto next sample */
6956   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6957     goto next;
6958
6959   if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6960     size = sample_size;
6961   } else {
6962     GST_DEBUG_OBJECT (qtdemux,
6963         "size %d larger than stream max_buffer_size %d, trimming",
6964         sample_size, stream->max_buffer_size);
6965     size =
6966         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6967   }
6968
6969   if (qtdemux->cenc_aux_info_offset > 0) {
6970     GstMapInfo map;
6971     GstByteReader br;
6972     GstBuffer *aux_info = NULL;
6973
6974     /* pull the data stored before the sample */
6975     ret =
6976         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6977         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6978     if (G_UNLIKELY (ret != GST_FLOW_OK))
6979       goto beach;
6980     gst_buffer_map (aux_info, &map, GST_MAP_READ);
6981     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6982     gst_byte_reader_init (&br, map.data + 8, map.size);
6983     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6984             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6985       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6986       gst_buffer_unmap (aux_info, &map);
6987       gst_buffer_unref (aux_info);
6988       ret = GST_FLOW_ERROR;
6989       goto beach;
6990     }
6991     gst_buffer_unmap (aux_info, &map);
6992     gst_buffer_unref (aux_info);
6993   }
6994
6995   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6996       offset);
6997
6998   if (stream->use_allocator) {
6999     /* if we have a per-stream allocator, use it */
7000     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
7001   }
7002
7003   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
7004       size, &buf);
7005   if (G_UNLIKELY (ret != GST_FLOW_OK))
7006     goto beach;
7007
7008   if (size != sample_size) {
7009     pts += gst_util_uint64_scale_int (GST_SECOND,
7010         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
7011         stream->timescale);
7012     dts +=
7013         gst_util_uint64_scale_int (GST_SECOND,
7014         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
7015         stream->timescale);
7016     duration =
7017         gst_util_uint64_scale_int (GST_SECOND,
7018         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
7019   }
7020
7021   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
7022       dts, pts, duration, keyframe, min_time, offset);
7023
7024   if (size != sample_size) {
7025     QtDemuxSample *sample = &stream->samples[stream->sample_index];
7026     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
7027
7028     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
7029         sample->timestamp +
7030         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
7031     if (time_position >= segment->media_start) {
7032       /* inside the segment, update time_position, looks very familiar to
7033        * GStreamer segments, doesn't it? */
7034       stream->time_position = (time_position - segment->media_start) +
7035           segment->time;
7036     } else {
7037       /* not yet in segment, time does not yet increment. This means
7038        * that we are still prerolling keyframes to the decoder so it can
7039        * decode the first sample of the segment. */
7040       stream->time_position = segment->time;
7041     }
7042   }
7043
7044   /* combine flows */
7045   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
7046   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
7047    * we have no more data for the pad to push */
7048   if (ret == GST_FLOW_EOS)
7049     ret = GST_FLOW_OK;
7050
7051   stream->offset_in_sample += size;
7052   if (stream->offset_in_sample >= sample_size) {
7053     gst_qtdemux_advance_sample (qtdemux, stream);
7054   }
7055   goto beach;
7056
7057 next:
7058   gst_qtdemux_advance_sample (qtdemux, stream);
7059
7060 beach:
7061   return ret;
7062
7063   /* special cases */
7064 eos:
7065   {
7066     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
7067     ret = GST_FLOW_EOS;
7068     goto beach;
7069   }
7070 eos_stream:
7071   {
7072     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
7073     /* EOS will be raised if all are EOS */
7074     ret = GST_FLOW_OK;
7075     goto beach;
7076   }
7077 }
7078
7079 static void
7080 gst_qtdemux_loop (GstPad * pad)
7081 {
7082   GstQTDemux *qtdemux;
7083   guint64 cur_offset;
7084   GstFlowReturn ret;
7085
7086   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
7087
7088   cur_offset = qtdemux->offset;
7089   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
7090       cur_offset, qt_demux_state_string (qtdemux->state));
7091
7092   switch (qtdemux->state) {
7093     case QTDEMUX_STATE_INITIAL:
7094     case QTDEMUX_STATE_HEADER:
7095       ret = gst_qtdemux_loop_state_header (qtdemux);
7096       break;
7097     case QTDEMUX_STATE_MOVIE:
7098       ret = gst_qtdemux_loop_state_movie (qtdemux);
7099       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
7100         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
7101       }
7102       break;
7103     default:
7104       /* ouch */
7105       goto invalid_state;
7106   }
7107
7108   /* if something went wrong, pause */
7109   if (ret != GST_FLOW_OK)
7110     goto pause;
7111
7112 done:
7113   gst_object_unref (qtdemux);
7114   return;
7115
7116   /* ERRORS */
7117 invalid_state:
7118   {
7119     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
7120         (NULL), ("streaming stopped, invalid state"));
7121     gst_pad_pause_task (pad);
7122     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
7123     goto done;
7124   }
7125 pause:
7126   {
7127     const gchar *reason = gst_flow_get_name (ret);
7128
7129     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
7130
7131     gst_pad_pause_task (pad);
7132
7133     /* fatal errors need special actions */
7134     /* check EOS */
7135     if (ret == GST_FLOW_EOS) {
7136       if (QTDEMUX_N_STREAMS (qtdemux) == 0) {
7137         /* we have no streams, post an error */
7138         gst_qtdemux_post_no_playable_stream_error (qtdemux);
7139       }
7140       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
7141         gint64 stop;
7142
7143         if ((stop = qtdemux->segment.stop) == -1)
7144           stop = qtdemux->segment.duration;
7145
7146         if (qtdemux->segment.rate >= 0) {
7147           GstMessage *message;
7148           GstEvent *event;
7149
7150           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
7151           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
7152               GST_FORMAT_TIME, stop);
7153           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
7154           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
7155             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
7156             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7157           }
7158           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
7159           gst_qtdemux_push_event (qtdemux, event);
7160         } else {
7161           GstMessage *message;
7162           GstEvent *event;
7163
7164           /*  For Reverse Playback */
7165           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
7166           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
7167               GST_FORMAT_TIME, qtdemux->segment.start);
7168           event = gst_event_new_segment_done (GST_FORMAT_TIME,
7169               qtdemux->segment.start);
7170           if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID) {
7171             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
7172             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7173           }
7174           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
7175           gst_qtdemux_push_event (qtdemux, event);
7176         }
7177       } else {
7178         GstEvent *event;
7179
7180         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
7181         event = gst_event_new_eos ();
7182         if (qtdemux->segment_seqnum != GST_SEQNUM_INVALID)
7183           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
7184         gst_qtdemux_push_event (qtdemux, event);
7185       }
7186     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
7187       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
7188       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
7189     }
7190     goto done;
7191   }
7192 }
7193
7194 /*
7195  * has_next_entry
7196  *
7197  * Returns if there are samples to be played.
7198  */
7199 static gboolean
7200 has_next_entry (GstQTDemux * demux)
7201 {
7202   QtDemuxStream *stream;
7203   gint i;
7204
7205   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
7206
7207   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7208     stream = QTDEMUX_NTH_STREAM (demux, i);
7209
7210     if (stream->sample_index == -1) {
7211       stream->sample_index = 0;
7212       stream->offset_in_sample = 0;
7213     }
7214
7215     if (stream->sample_index >= stream->n_samples) {
7216       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7217       continue;
7218     }
7219     GST_DEBUG_OBJECT (demux, "Found a sample");
7220     return TRUE;
7221   }
7222
7223   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
7224   return FALSE;
7225 }
7226
7227 /*
7228  * next_entry_size
7229  *
7230  * Returns the size of the first entry at the current offset.
7231  * If -1, there are none (which means EOS or empty file).
7232  */
7233 static guint64
7234 next_entry_size (GstQTDemux * demux)
7235 {
7236   QtDemuxStream *stream, *target_stream = NULL;
7237   guint64 smalloffs = (guint64) - 1;
7238   QtDemuxSample *sample;
7239   gint i;
7240
7241   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
7242       demux->offset);
7243
7244   for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7245     stream = QTDEMUX_NTH_STREAM (demux, i);
7246
7247     if (stream->sample_index == -1) {
7248       stream->sample_index = 0;
7249       stream->offset_in_sample = 0;
7250     }
7251
7252     if (stream->sample_index >= stream->n_samples) {
7253       GST_LOG_OBJECT (demux, "track-id %u samples exhausted", stream->track_id);
7254       continue;
7255     }
7256
7257     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
7258       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
7259           stream->sample_index);
7260       return -1;
7261     }
7262
7263     sample = &stream->samples[stream->sample_index];
7264
7265     GST_LOG_OBJECT (demux,
7266         "Checking track-id %u (sample_index:%d / offset:%" G_GUINT64_FORMAT
7267         " / size:%" G_GUINT32_FORMAT ")", stream->track_id,
7268         stream->sample_index, sample->offset, sample->size);
7269
7270     if (((smalloffs == -1)
7271             || (sample->offset < smalloffs)) && (sample->size)) {
7272       smalloffs = sample->offset;
7273       target_stream = stream;
7274     }
7275   }
7276
7277   if (!target_stream)
7278     return -1;
7279
7280   GST_LOG_OBJECT (demux,
7281       "track-id %u offset %" G_GUINT64_FORMAT " demux->offset :%"
7282       G_GUINT64_FORMAT, target_stream->track_id, smalloffs, demux->offset);
7283
7284   stream = target_stream;
7285   sample = &stream->samples[stream->sample_index];
7286
7287   if (sample->offset >= demux->offset) {
7288     demux->todrop = sample->offset - demux->offset;
7289     return sample->size + demux->todrop;
7290   }
7291
7292   GST_DEBUG_OBJECT (demux,
7293       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
7294   return -1;
7295 }
7296
7297 static void
7298 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
7299 {
7300   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
7301
7302   gst_element_post_message (GST_ELEMENT_CAST (demux),
7303       gst_message_new_element (GST_OBJECT_CAST (demux),
7304           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
7305 }
7306
7307 static gboolean
7308 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
7309 {
7310   GstEvent *event;
7311   gboolean res = 0;
7312
7313   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
7314
7315   event =
7316       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
7317       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
7318       GST_SEEK_TYPE_NONE, -1);
7319
7320   /* store seqnum to drop flush events, they don't need to reach downstream */
7321   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
7322   res = gst_pad_push_event (demux->sinkpad, event);
7323   demux->offset_seek_seqnum = GST_SEQNUM_INVALID;
7324
7325   return res;
7326 }
7327
7328 /* check for seekable upstream, above and beyond a mere query */
7329 static void
7330 gst_qtdemux_check_seekability (GstQTDemux * demux)
7331 {
7332   GstQuery *query;
7333   gboolean seekable = FALSE;
7334   gint64 start = -1, stop = -1;
7335
7336   if (demux->upstream_size)
7337     return;
7338
7339   if (demux->upstream_format_is_time)
7340     return;
7341
7342   query = gst_query_new_seeking (GST_FORMAT_BYTES);
7343   if (!gst_pad_peer_query (demux->sinkpad, query)) {
7344     GST_DEBUG_OBJECT (demux, "seeking query failed");
7345     goto done;
7346   }
7347
7348   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
7349
7350   /* try harder to query upstream size if we didn't get it the first time */
7351   if (seekable && stop == -1) {
7352     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
7353     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
7354   }
7355
7356   /* if upstream doesn't know the size, it's likely that it's not seekable in
7357    * practice even if it technically may be seekable */
7358   if (seekable && (start != 0 || stop <= start)) {
7359     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
7360     seekable = FALSE;
7361   }
7362
7363 done:
7364   gst_query_unref (query);
7365
7366   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
7367       G_GUINT64_FORMAT ")", seekable, start, stop);
7368   demux->upstream_seekable = seekable;
7369   demux->upstream_size = seekable ? stop : -1;
7370 }
7371
7372 static void
7373 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
7374 {
7375   g_return_if_fail (bytes <= demux->todrop);
7376
7377   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
7378   gst_adapter_flush (demux->adapter, bytes);
7379   demux->neededbytes -= bytes;
7380   demux->offset += bytes;
7381   demux->todrop -= bytes;
7382 }
7383
7384 /* PUSH-MODE only: Send a segment, if not done already. */
7385 static void
7386 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
7387 {
7388   if (G_UNLIKELY (demux->need_segment)) {
7389     gint i;
7390
7391     if (!demux->upstream_format_is_time) {
7392       gst_qtdemux_map_and_push_segments (demux, &demux->segment);
7393     } else {
7394       GstEvent *segment_event;
7395       segment_event = gst_event_new_segment (&demux->segment);
7396       if (demux->segment_seqnum != GST_SEQNUM_INVALID)
7397         gst_event_set_seqnum (segment_event, demux->segment_seqnum);
7398       gst_qtdemux_push_event (demux, segment_event);
7399     }
7400
7401     demux->need_segment = FALSE;
7402
7403     /* clear to send tags on all streams */
7404     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7405       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7406       gst_qtdemux_push_tags (demux, stream);
7407       if (CUR_STREAM (stream)->sparse) {
7408         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
7409         gst_pad_push_event (stream->pad,
7410             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
7411       }
7412     }
7413   }
7414 }
7415
7416 /* Used for push mode only. */
7417 static void
7418 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
7419     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
7420 {
7421   GstClockTime ts, dur;
7422
7423   ts = pos;
7424   dur =
7425       stream->segments[segment_index].duration - (pos -
7426       stream->segments[segment_index].time);
7427   stream->time_position += dur;
7428
7429   /* Only gaps with a duration of at least one second are propagated.
7430    * Same workaround as in pull mode.
7431    * (See 2e45926a96ec5298c6ef29bf912e5e6a06dc3e0e) */
7432   if (dur >= GST_SECOND) {
7433     GstEvent *gap;
7434     gap = gst_event_new_gap (ts, dur);
7435
7436     GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
7437         "segment: %" GST_PTR_FORMAT, gap);
7438     gst_pad_push_event (stream->pad, gap);
7439   }
7440 }
7441
7442 static GstFlowReturn
7443 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
7444 {
7445   GstQTDemux *demux;
7446
7447   demux = GST_QTDEMUX (parent);
7448
7449   GST_DEBUG_OBJECT (demux,
7450       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
7451       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
7452       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
7453       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
7454       gst_buffer_get_size (inbuf), demux->offset);
7455
7456   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
7457     gboolean is_gap_input = FALSE;
7458     gint i;
7459
7460     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
7461
7462     for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7463       QTDEMUX_NTH_STREAM (demux, i)->discont = TRUE;
7464     }
7465
7466     /* Check if we can land back on our feet in the case where upstream is
7467      * handling the seeking/pushing of samples with gaps in between (like
7468      * in the case of trick-mode DASH for example) */
7469     if (demux->upstream_format_is_time
7470         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
7471       for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
7472         guint32 res;
7473         QtDemuxStream *stream = QTDEMUX_NTH_STREAM (demux, i);
7474         GST_LOG_OBJECT (demux,
7475             "track-id #%u , checking if offset %" G_GUINT64_FORMAT
7476             " is a sample start", stream->track_id, GST_BUFFER_OFFSET (inbuf));
7477         res =
7478             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
7479             stream, GST_BUFFER_OFFSET (inbuf));
7480         if (res != -1) {
7481           QtDemuxSample *sample = &stream->samples[res];
7482           GST_LOG_OBJECT (demux,
7483               "Checking if sample %d from track-id %u is valid (offset:%"
7484               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res,
7485               stream->track_id, sample->offset, sample->size);
7486           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
7487             GST_LOG_OBJECT (demux,
7488                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
7489                 res);
7490             is_gap_input = TRUE;
7491             /* We can go back to standard playback mode */
7492             demux->state = QTDEMUX_STATE_MOVIE;
7493             /* Remember which sample this stream is at */
7494             stream->sample_index = res;
7495             /* Finally update all push-based values to the expected values */
7496             demux->neededbytes = stream->samples[res].size;
7497             demux->offset = GST_BUFFER_OFFSET (inbuf);
7498             demux->mdatleft =
7499                 demux->mdatsize - demux->offset + demux->mdatoffset;
7500             demux->todrop = 0;
7501           }
7502         }
7503       }
7504       if (!is_gap_input) {
7505         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
7506         /* Reset state if it's a real discont */
7507         demux->neededbytes = 16;
7508         demux->state = QTDEMUX_STATE_INITIAL;
7509         demux->offset = GST_BUFFER_OFFSET (inbuf);
7510         gst_adapter_clear (demux->adapter);
7511       }
7512     }
7513     /* Reverse fragmented playback, need to flush all we have before
7514      * consuming a new fragment.
7515      * The samples array have the timestamps calculated by accumulating the
7516      * durations but this won't work for reverse playback of fragments as
7517      * the timestamps of a subsequent fragment should be smaller than the
7518      * previously received one. */
7519     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
7520       gst_qtdemux_process_adapter (demux, TRUE);
7521       g_ptr_array_foreach (demux->active_streams,
7522           (GFunc) gst_qtdemux_stream_flush_samples_data, NULL);
7523     }
7524   }
7525
7526   gst_adapter_push (demux->adapter, inbuf);
7527
7528   GST_DEBUG_OBJECT (demux,
7529       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
7530       demux->neededbytes, gst_adapter_available (demux->adapter));
7531
7532   return gst_qtdemux_process_adapter (demux, FALSE);
7533 }
7534
7535 static GstFlowReturn
7536 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
7537 {
7538   GstFlowReturn ret = GST_FLOW_OK;
7539
7540   /* we never really mean to buffer that much */
7541   if (demux->neededbytes == -1) {
7542     goto eos;
7543   }
7544
7545   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
7546       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
7547
7548 #ifndef GST_DISABLE_GST_DEBUG
7549     {
7550       guint64 discont_offset, distance_from_discont;
7551
7552       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
7553       distance_from_discont =
7554           gst_adapter_distance_from_discont (demux->adapter);
7555
7556       GST_DEBUG_OBJECT (demux,
7557           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
7558           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
7559           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
7560           demux->offset, discont_offset, distance_from_discont);
7561     }
7562 #endif
7563
7564     switch (demux->state) {
7565       case QTDEMUX_STATE_INITIAL:{
7566         const guint8 *data;
7567         guint32 fourcc;
7568         guint64 size;
7569
7570         gst_qtdemux_check_seekability (demux);
7571
7572         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7573
7574         /* get fourcc/length, set neededbytes */
7575         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7576             &size, &fourcc);
7577         gst_adapter_unmap (demux->adapter);
7578         data = NULL;
7579         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7580             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7581         if (size == 0) {
7582           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7583               (_("This file is invalid and cannot be played.")),
7584               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7585                   GST_FOURCC_ARGS (fourcc)));
7586           ret = GST_FLOW_ERROR;
7587           break;
7588         }
7589         if (fourcc == FOURCC_mdat) {
7590           gint next_entry = next_entry_size (demux);
7591           if (QTDEMUX_N_STREAMS (demux) > 0 && (next_entry != -1
7592                   || !demux->fragmented)) {
7593             /* we have the headers, start playback */
7594             demux->state = QTDEMUX_STATE_MOVIE;
7595             demux->neededbytes = next_entry;
7596             demux->mdatleft = size;
7597             demux->mdatsize = demux->mdatleft;
7598           } else {
7599             /* no headers yet, try to get them */
7600             guint bs;
7601             gboolean res;
7602             guint64 old, target;
7603
7604           buffer_data:
7605             old = demux->offset;
7606             target = old + size;
7607
7608             /* try to jump over the atom with a seek */
7609             /* only bother if it seems worth doing so,
7610              * and avoids possible upstream/server problems */
7611             if (demux->upstream_seekable &&
7612                 demux->upstream_size > 4 * (1 << 20)) {
7613               res = qtdemux_seek_offset (demux, target);
7614             } else {
7615               GST_DEBUG_OBJECT (demux, "skipping seek");
7616               res = FALSE;
7617             }
7618
7619             if (res) {
7620               GST_DEBUG_OBJECT (demux, "seek success");
7621               /* remember the offset fo the first mdat so we can seek back to it
7622                * after we have the headers */
7623               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7624                 demux->first_mdat = old;
7625                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7626                     demux->first_mdat);
7627               }
7628               /* seek worked, continue reading */
7629               demux->offset = target;
7630               demux->neededbytes = 16;
7631               demux->state = QTDEMUX_STATE_INITIAL;
7632             } else {
7633               /* seek failed, need to buffer */
7634               demux->offset = old;
7635               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7636               /* there may be multiple mdat (or alike) buffers */
7637               /* sanity check */
7638               if (demux->mdatbuffer)
7639                 bs = gst_buffer_get_size (demux->mdatbuffer);
7640               else
7641                 bs = 0;
7642               if (size + bs > 10 * (1 << 20))
7643                 goto no_moov;
7644               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7645               demux->neededbytes = size;
7646               if (!demux->mdatbuffer)
7647                 demux->mdatoffset = demux->offset;
7648             }
7649           }
7650         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7651           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7652               (_("This file is invalid and cannot be played.")),
7653               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7654                   GST_FOURCC_ARGS (fourcc), size));
7655           ret = GST_FLOW_ERROR;
7656           break;
7657         } else {
7658           /* this means we already started buffering and still no moov header,
7659            * let's continue buffering everything till we get moov */
7660           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7661                   || fourcc == FOURCC_moof))
7662             goto buffer_data;
7663           demux->neededbytes = size;
7664           demux->state = QTDEMUX_STATE_HEADER;
7665         }
7666         break;
7667       }
7668       case QTDEMUX_STATE_HEADER:{
7669         const guint8 *data;
7670         guint32 fourcc;
7671
7672         GST_DEBUG_OBJECT (demux, "In header");
7673
7674         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7675
7676         /* parse the header */
7677         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7678             &fourcc);
7679         if (fourcc == FOURCC_moov) {
7680           /* in usual fragmented setup we could try to scan for more
7681            * and end up at the the moov (after mdat) again */
7682           if (demux->got_moov && QTDEMUX_N_STREAMS (demux) > 0 &&
7683               (!demux->fragmented
7684                   || demux->last_moov_offset == demux->offset)) {
7685             GST_DEBUG_OBJECT (demux,
7686                 "Skipping moov atom as we have (this) one already");
7687           } else {
7688             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7689
7690             if (demux->got_moov && demux->fragmented) {
7691               GST_DEBUG_OBJECT (demux,
7692                   "Got a second moov, clean up data from old one");
7693               if (demux->moov_node_compressed) {
7694                 g_node_destroy (demux->moov_node_compressed);
7695                 if (demux->moov_node)
7696                   g_free (demux->moov_node->data);
7697               }
7698               demux->moov_node_compressed = NULL;
7699               if (demux->moov_node)
7700                 g_node_destroy (demux->moov_node);
7701               demux->moov_node = NULL;
7702             }
7703
7704             demux->last_moov_offset = demux->offset;
7705
7706             /* Update streams with new moov */
7707             gst_qtdemux_stream_concat (demux,
7708                 demux->old_streams, demux->active_streams);
7709
7710             qtdemux_parse_moov (demux, data, demux->neededbytes);
7711             qtdemux_node_dump (demux, demux->moov_node);
7712             qtdemux_parse_tree (demux);
7713             qtdemux_prepare_streams (demux);
7714             QTDEMUX_EXPOSE_LOCK (demux);
7715             qtdemux_expose_streams (demux);
7716             QTDEMUX_EXPOSE_UNLOCK (demux);
7717
7718             demux->got_moov = TRUE;
7719
7720             gst_qtdemux_check_send_pending_segment (demux);
7721
7722             if (demux->moov_node_compressed) {
7723               g_node_destroy (demux->moov_node_compressed);
7724               g_free (demux->moov_node->data);
7725             }
7726             demux->moov_node_compressed = NULL;
7727             g_node_destroy (demux->moov_node);
7728             demux->moov_node = NULL;
7729             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7730           }
7731         } else if (fourcc == FOURCC_moof) {
7732           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7733             guint64 dist = 0;
7734             GstClockTime prev_pts;
7735             guint64 prev_offset;
7736             guint64 adapter_discont_offset, adapter_discont_dist;
7737
7738             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7739
7740             /*
7741              * The timestamp of the moof buffer is relevant as some scenarios
7742              * won't have the initial timestamp in the atoms. Whenever a new
7743              * buffer has started, we get that buffer's PTS and use it as a base
7744              * timestamp for the trun entries.
7745              *
7746              * To keep track of the current buffer timestamp and starting point
7747              * we use gst_adapter_prev_pts that gives us the PTS and the distance
7748              * from the beggining of the buffer, with the distance and demux->offset
7749              * we know if it is still the same buffer or not.
7750              */
7751             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7752             prev_offset = demux->offset - dist;
7753             if (demux->fragment_start_offset == -1
7754                 || prev_offset > demux->fragment_start_offset) {
7755               demux->fragment_start_offset = prev_offset;
7756               demux->fragment_start = prev_pts;
7757               GST_DEBUG_OBJECT (demux,
7758                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7759                   GST_TIME_FORMAT, demux->fragment_start_offset,
7760                   GST_TIME_ARGS (demux->fragment_start));
7761             }
7762
7763             /* We can't use prev_offset() here because this would require
7764              * upstream to set consistent and correct offsets on all buffers
7765              * since the discont. Nothing ever did that in the past and we
7766              * would break backwards compatibility here then.
7767              * Instead take the offset we had at the last discont and count
7768              * the bytes from there. This works with old code as there would
7769              * be no discont between moov and moof, and also works with
7770              * adaptivedemux which correctly sets offset and will set the
7771              * DISCONT flag accordingly when needed.
7772              *
7773              * We also only do this for upstream TIME segments as otherwise
7774              * there are potential backwards compatibility problems with
7775              * seeking in PUSH mode and upstream providing inconsistent
7776              * timestamps. */
7777             adapter_discont_offset =
7778                 gst_adapter_offset_at_discont (demux->adapter);
7779             adapter_discont_dist =
7780                 gst_adapter_distance_from_discont (demux->adapter);
7781
7782             GST_DEBUG_OBJECT (demux,
7783                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7784                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7785                 demux->offset, adapter_discont_offset, adapter_discont_dist);
7786
7787             if (demux->upstream_format_is_time) {
7788               demux->moof_offset = adapter_discont_offset;
7789               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7790                 demux->moof_offset += adapter_discont_dist;
7791               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7792                 demux->moof_offset = demux->offset;
7793             } else {
7794               demux->moof_offset = demux->offset;
7795             }
7796
7797             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7798                     demux->moof_offset, NULL)) {
7799               gst_adapter_unmap (demux->adapter);
7800               ret = GST_FLOW_ERROR;
7801               goto done;
7802             }
7803
7804             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7805             if (demux->mss_mode && !demux->exposed) {
7806               QTDEMUX_EXPOSE_LOCK (demux);
7807               qtdemux_expose_streams (demux);
7808               QTDEMUX_EXPOSE_UNLOCK (demux);
7809             }
7810
7811             gst_qtdemux_check_send_pending_segment (demux);
7812           } else {
7813             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7814           }
7815         } else if (fourcc == FOURCC_ftyp) {
7816           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7817           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7818         } else if (fourcc == FOURCC_uuid) {
7819           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7820           qtdemux_parse_uuid (demux, data, demux->neededbytes);
7821         } else if (fourcc == FOURCC_sidx) {
7822           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7823           qtdemux_parse_sidx (demux, data, demux->neededbytes);
7824         } else {
7825           switch (fourcc) {
7826             case FOURCC_styp:
7827               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7828                * FALLTHROUGH */
7829             case FOURCC_skip:
7830             case FOURCC_free:
7831               /* [free] and [skip] are padding atoms */
7832               GST_DEBUG_OBJECT (demux,
7833                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7834                   GST_FOURCC_ARGS (fourcc));
7835               break;
7836             default:
7837               GST_WARNING_OBJECT (demux,
7838                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7839                   GST_FOURCC_ARGS (fourcc));
7840               /* Let's jump that one and go back to initial state */
7841               break;
7842           }
7843         }
7844         gst_adapter_unmap (demux->adapter);
7845         data = NULL;
7846
7847         if (demux->mdatbuffer && QTDEMUX_N_STREAMS (demux)) {
7848           gsize remaining_data_size = 0;
7849
7850           /* the mdat was before the header */
7851           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7852               QTDEMUX_N_STREAMS (demux), demux->mdatbuffer);
7853           /* restore our adapter/offset view of things with upstream;
7854            * put preceding buffered data ahead of current moov data.
7855            * This should also handle evil mdat, moov, mdat cases and alike */
7856           gst_adapter_flush (demux->adapter, demux->neededbytes);
7857
7858           /* Store any remaining data after the mdat for later usage */
7859           remaining_data_size = gst_adapter_available (demux->adapter);
7860           if (remaining_data_size > 0) {
7861             g_assert (demux->restoredata_buffer == NULL);
7862             demux->restoredata_buffer =
7863                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7864             demux->restoredata_offset = demux->offset + demux->neededbytes;
7865             GST_DEBUG_OBJECT (demux,
7866                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7867                 G_GUINT64_FORMAT, remaining_data_size,
7868                 demux->restoredata_offset);
7869           }
7870
7871           gst_adapter_push (demux->adapter, demux->mdatbuffer);
7872           demux->mdatbuffer = NULL;
7873           demux->offset = demux->mdatoffset;
7874           demux->neededbytes = next_entry_size (demux);
7875           demux->state = QTDEMUX_STATE_MOVIE;
7876           demux->mdatleft = gst_adapter_available (demux->adapter);
7877           demux->mdatsize = demux->mdatleft;
7878         } else {
7879           GST_DEBUG_OBJECT (demux, "Carrying on normally");
7880           gst_adapter_flush (demux->adapter, demux->neededbytes);
7881
7882           /* only go back to the mdat if there are samples to play */
7883           if (demux->got_moov && demux->first_mdat != -1
7884               && has_next_entry (demux)) {
7885             gboolean res;
7886
7887             /* we need to seek back */
7888             res = qtdemux_seek_offset (demux, demux->first_mdat);
7889             if (res) {
7890               demux->offset = demux->first_mdat;
7891             } else {
7892               GST_DEBUG_OBJECT (demux, "Seek back failed");
7893             }
7894           } else {
7895             demux->offset += demux->neededbytes;
7896           }
7897           demux->neededbytes = 16;
7898           demux->state = QTDEMUX_STATE_INITIAL;
7899         }
7900
7901         break;
7902       }
7903       case QTDEMUX_STATE_BUFFER_MDAT:{
7904         GstBuffer *buf;
7905         guint8 fourcc[4];
7906
7907         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7908             demux->offset);
7909         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7910         gst_buffer_extract (buf, 0, fourcc, 4);
7911         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7912             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7913         if (demux->mdatbuffer)
7914           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7915         else
7916           demux->mdatbuffer = buf;
7917         demux->offset += demux->neededbytes;
7918         demux->neededbytes = 16;
7919         demux->state = QTDEMUX_STATE_INITIAL;
7920         gst_qtdemux_post_progress (demux, 1, 1);
7921
7922         break;
7923       }
7924       case QTDEMUX_STATE_MOVIE:{
7925         QtDemuxStream *stream = NULL;
7926         QtDemuxSample *sample;
7927         GstClockTime dts, pts, duration;
7928         gboolean keyframe;
7929         gint i;
7930
7931         GST_DEBUG_OBJECT (demux,
7932             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7933
7934         if (demux->fragmented) {
7935           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7936               demux->mdatleft);
7937           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7938             /* if needed data starts within this atom,
7939              * then it should not exceed this atom */
7940             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7941               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7942                   (_("This file is invalid and cannot be played.")),
7943                   ("sample data crosses atom boundary"));
7944               ret = GST_FLOW_ERROR;
7945               break;
7946             }
7947             demux->mdatleft -= demux->neededbytes;
7948           } else {
7949             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7950             /* so we are dropping more than left in this atom */
7951             gst_qtdemux_drop_data (demux, demux->mdatleft);
7952             demux->mdatleft = 0;
7953
7954             /* need to resume atom parsing so we do not miss any other pieces */
7955             demux->state = QTDEMUX_STATE_INITIAL;
7956             demux->neededbytes = 16;
7957
7958             /* check if there was any stored post mdat data from previous buffers */
7959             if (demux->restoredata_buffer) {
7960               g_assert (gst_adapter_available (demux->adapter) == 0);
7961
7962               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7963               demux->restoredata_buffer = NULL;
7964               demux->offset = demux->restoredata_offset;
7965             }
7966
7967             break;
7968           }
7969         }
7970
7971         if (demux->todrop) {
7972           if (demux->cenc_aux_info_offset > 0) {
7973             GstByteReader br;
7974             const guint8 *data;
7975
7976             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7977             data = gst_adapter_map (demux->adapter, demux->todrop);
7978             gst_byte_reader_init (&br, data + 8, demux->todrop);
7979             if (!qtdemux_parse_cenc_aux_info (demux,
7980                     QTDEMUX_NTH_STREAM (demux, 0), &br,
7981                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7982               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7983               ret = GST_FLOW_ERROR;
7984               gst_adapter_unmap (demux->adapter);
7985               g_free (demux->cenc_aux_info_sizes);
7986               demux->cenc_aux_info_sizes = NULL;
7987               goto done;
7988             }
7989             demux->cenc_aux_info_offset = 0;
7990             g_free (demux->cenc_aux_info_sizes);
7991             demux->cenc_aux_info_sizes = NULL;
7992             gst_adapter_unmap (demux->adapter);
7993           }
7994           gst_qtdemux_drop_data (demux, demux->todrop);
7995         }
7996
7997         /* first buffer? */
7998         /* initial newsegment sent here after having added pads,
7999          * possible others in sink_event */
8000         gst_qtdemux_check_send_pending_segment (demux);
8001
8002         /* Figure out which stream this packet belongs to */
8003         for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
8004           stream = QTDEMUX_NTH_STREAM (demux, i);
8005           if (stream->sample_index >= stream->n_samples) {
8006             /* reset to be checked below G_UNLIKELY (stream == NULL) */
8007             stream = NULL;
8008             continue;
8009           }
8010           GST_LOG_OBJECT (demux,
8011               "Checking track-id %u (sample_index:%d / offset:%"
8012               G_GUINT64_FORMAT " / size:%d)", stream->track_id,
8013               stream->sample_index,
8014               stream->samples[stream->sample_index].offset,
8015               stream->samples[stream->sample_index].size);
8016
8017           if (stream->samples[stream->sample_index].offset == demux->offset)
8018             break;
8019         }
8020
8021         if (G_UNLIKELY (stream == NULL))
8022           goto unknown_stream;
8023
8024         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
8025
8026         if (stream->new_caps) {
8027           gst_qtdemux_configure_stream (demux, stream);
8028         }
8029
8030         /* Put data in a buffer, set timestamps, caps, ... */
8031         sample = &stream->samples[stream->sample_index];
8032
8033         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
8034           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
8035               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
8036
8037           dts = QTSAMPLE_DTS (stream, sample);
8038           pts = QTSAMPLE_PTS (stream, sample);
8039           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
8040           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
8041
8042           /* check for segment end */
8043           if (G_UNLIKELY (demux->segment.stop != -1
8044                   && demux->segment.stop <= pts && stream->on_keyframe)
8045               && !(demux->upstream_format_is_time && demux->segment.rate < 0)) {
8046             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
8047             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
8048
8049             /* skip this data, stream is EOS */
8050             gst_adapter_flush (demux->adapter, demux->neededbytes);
8051             demux->offset += demux->neededbytes;
8052
8053             /* check if all streams are eos */
8054             ret = GST_FLOW_EOS;
8055             for (i = 0; i < QTDEMUX_N_STREAMS (demux); i++) {
8056               if (!STREAM_IS_EOS (QTDEMUX_NTH_STREAM (demux, i))) {
8057                 ret = GST_FLOW_OK;
8058                 break;
8059               }
8060             }
8061           } else {
8062             GstBuffer *outbuf;
8063
8064             outbuf =
8065                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
8066
8067             /* FIXME: should either be an assert or a plain check */
8068             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
8069
8070             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
8071                 dts, pts, duration, keyframe, dts, demux->offset);
8072           }
8073
8074           /* combine flows */
8075           ret = gst_qtdemux_combine_flows (demux, stream, ret);
8076         } else {
8077           /* skip this data, stream is EOS */
8078           gst_adapter_flush (demux->adapter, demux->neededbytes);
8079         }
8080
8081         stream->sample_index++;
8082         stream->offset_in_sample = 0;
8083
8084         /* update current offset and figure out size of next buffer */
8085         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
8086             demux->offset, demux->neededbytes);
8087         demux->offset += demux->neededbytes;
8088         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
8089             demux->offset);
8090
8091
8092         if (ret == GST_FLOW_EOS) {
8093           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
8094           demux->neededbytes = -1;
8095           goto eos;
8096         }
8097
8098         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
8099           if (demux->fragmented) {
8100             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
8101             /* there may be more to follow, only finish this atom */
8102             demux->todrop = demux->mdatleft;
8103             demux->neededbytes = demux->todrop;
8104             break;
8105           }
8106           goto eos;
8107         }
8108         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
8109           goto non_ok_unlinked_flow;
8110         }
8111         break;
8112       }
8113       default:
8114         goto invalid_state;
8115     }
8116   }
8117
8118   /* when buffering movie data, at least show user something is happening */
8119   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
8120       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
8121     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
8122         demux->neededbytes);
8123   }
8124 done:
8125
8126   return ret;
8127
8128   /* ERRORS */
8129 non_ok_unlinked_flow:
8130   {
8131     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
8132         gst_flow_get_name (ret));
8133     return ret;
8134   }
8135 unknown_stream:
8136   {
8137     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
8138     ret = GST_FLOW_ERROR;
8139     goto done;
8140   }
8141 eos:
8142   {
8143     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
8144     ret = GST_FLOW_EOS;
8145     goto done;
8146   }
8147 invalid_state:
8148   {
8149     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
8150         (NULL), ("qtdemuxer invalid state %d", demux->state));
8151     ret = GST_FLOW_ERROR;
8152     goto done;
8153   }
8154 no_moov:
8155   {
8156     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
8157         (NULL), ("no 'moov' atom within the first 10 MB"));
8158     ret = GST_FLOW_ERROR;
8159     goto done;
8160   }
8161 }
8162
8163 static gboolean
8164 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
8165 {
8166   GstQuery *query;
8167   gboolean pull_mode;
8168
8169   query = gst_query_new_scheduling ();
8170
8171   if (!gst_pad_peer_query (sinkpad, query)) {
8172     gst_query_unref (query);
8173     goto activate_push;
8174   }
8175
8176   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
8177       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
8178   gst_query_unref (query);
8179
8180   if (!pull_mode)
8181     goto activate_push;
8182
8183   GST_DEBUG_OBJECT (sinkpad, "activating pull");
8184   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
8185
8186 activate_push:
8187   {
8188     GST_DEBUG_OBJECT (sinkpad, "activating push");
8189     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
8190   }
8191 }
8192
8193 static gboolean
8194 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
8195     GstPadMode mode, gboolean active)
8196 {
8197   gboolean res;
8198   GstQTDemux *demux = GST_QTDEMUX (parent);
8199
8200   switch (mode) {
8201     case GST_PAD_MODE_PUSH:
8202       demux->pullbased = FALSE;
8203       res = TRUE;
8204       break;
8205     case GST_PAD_MODE_PULL:
8206       if (active) {
8207         demux->pullbased = TRUE;
8208         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
8209             sinkpad, NULL);
8210       } else {
8211         res = gst_pad_stop_task (sinkpad);
8212       }
8213       break;
8214     default:
8215       res = FALSE;
8216       break;
8217   }
8218   return res;
8219 }
8220
8221 #ifdef HAVE_ZLIB
8222 static void *
8223 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
8224 {
8225   guint8 *buffer;
8226   z_stream z;
8227   int ret;
8228
8229   memset (&z, 0, sizeof (z));
8230   z.zalloc = NULL;
8231   z.zfree = NULL;
8232   z.opaque = NULL;
8233
8234   if ((ret = inflateInit (&z)) != Z_OK) {
8235     GST_ERROR ("inflateInit() returned %d", ret);
8236     return NULL;
8237   }
8238
8239   z.next_in = z_buffer;
8240   z.avail_in = z_length;
8241
8242   buffer = (guint8 *) g_malloc (*length);
8243   z.avail_out = *length;
8244   z.next_out = (Bytef *) buffer;
8245   do {
8246     ret = inflate (&z, Z_NO_FLUSH);
8247     if (ret == Z_STREAM_END) {
8248       break;
8249     } else if (ret != Z_OK) {
8250       GST_WARNING ("inflate() returned %d", ret);
8251       break;
8252     }
8253
8254     *length += 4096;
8255     buffer = (guint8 *) g_realloc (buffer, *length);
8256     z.next_out = (Bytef *) (buffer + z.total_out);
8257     z.avail_out += 4096;
8258   } while (z.avail_in > 0);
8259
8260   if (ret != Z_STREAM_END) {
8261     g_free (buffer);
8262     buffer = NULL;
8263     *length = 0;
8264   } else {
8265     *length = z.total_out;
8266   }
8267
8268   inflateEnd (&z);
8269
8270   return buffer;
8271 }
8272 #endif /* HAVE_ZLIB */
8273
8274 static gboolean
8275 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
8276 {
8277   GNode *cmov;
8278
8279   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
8280
8281   /* counts as header data */
8282   qtdemux->header_size += length;
8283
8284   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
8285   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
8286
8287   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
8288   if (cmov) {
8289     guint32 method;
8290     GNode *dcom;
8291     GNode *cmvd;
8292     guint32 dcom_len;
8293
8294     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
8295     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
8296     if (dcom == NULL || cmvd == NULL)
8297       goto invalid_compression;
8298
8299     dcom_len = QT_UINT32 (dcom->data);
8300     if (dcom_len < 12)
8301       goto invalid_compression;
8302
8303     method = QT_FOURCC ((guint8 *) dcom->data + 8);
8304     switch (method) {
8305 #ifdef HAVE_ZLIB
8306       case FOURCC_zlib:{
8307         guint uncompressed_length;
8308         guint compressed_length;
8309         guint8 *buf;
8310         guint32 cmvd_len;
8311
8312         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
8313         if (cmvd_len < 12)
8314           goto invalid_compression;
8315
8316         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
8317         compressed_length = cmvd_len - 12;
8318         GST_LOG ("length = %u", uncompressed_length);
8319
8320         buf =
8321             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
8322             compressed_length, &uncompressed_length);
8323
8324         if (buf) {
8325           qtdemux->moov_node_compressed = qtdemux->moov_node;
8326           qtdemux->moov_node = g_node_new (buf);
8327
8328           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
8329               uncompressed_length);
8330         }
8331         break;
8332       }
8333 #endif /* HAVE_ZLIB */
8334       default:
8335         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
8336             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
8337         break;
8338     }
8339   }
8340   return TRUE;
8341
8342   /* ERRORS */
8343 invalid_compression:
8344   {
8345     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
8346     return FALSE;
8347   }
8348 }
8349
8350 static gboolean
8351 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
8352     const guint8 * end)
8353 {
8354   while (G_UNLIKELY (buf < end)) {
8355     GNode *child;
8356     guint32 len;
8357
8358     if (G_UNLIKELY (buf + 4 > end)) {
8359       GST_LOG_OBJECT (qtdemux, "buffer overrun");
8360       break;
8361     }
8362     len = QT_UINT32 (buf);
8363     if (G_UNLIKELY (len == 0)) {
8364       GST_LOG_OBJECT (qtdemux, "empty container");
8365       break;
8366     }
8367     if (G_UNLIKELY (len < 8)) {
8368       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
8369       break;
8370     }
8371     if (G_UNLIKELY (len > (end - buf))) {
8372       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
8373           (gint) (end - buf));
8374       break;
8375     }
8376
8377     child = g_node_new ((guint8 *) buf);
8378     g_node_append (node, child);
8379     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
8380     qtdemux_parse_node (qtdemux, child, buf, len);
8381
8382     buf += len;
8383   }
8384   return TRUE;
8385 }
8386
8387 static gboolean
8388 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
8389     GNode * xdxt)
8390 {
8391   int len = QT_UINT32 (xdxt->data);
8392   guint8 *buf = xdxt->data;
8393   guint8 *end = buf + len;
8394   GstBuffer *buffer;
8395
8396   /* skip size and type */
8397   buf += 8;
8398   end -= 8;
8399
8400   while (buf < end) {
8401     gint size;
8402     guint32 type;
8403
8404     size = QT_UINT32 (buf);
8405     type = QT_FOURCC (buf + 4);
8406
8407     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
8408
8409     if (buf + size > end || size <= 0)
8410       break;
8411
8412     buf += 8;
8413     size -= 8;
8414
8415     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
8416         GST_FOURCC_ARGS (type));
8417
8418     switch (type) {
8419       case FOURCC_tCtH:
8420         buffer = gst_buffer_new_and_alloc (size);
8421         gst_buffer_fill (buffer, 0, buf, size);
8422         stream->buffers = g_slist_append (stream->buffers, buffer);
8423         GST_LOG_OBJECT (qtdemux, "parsing theora header");
8424         break;
8425       case FOURCC_tCt_:
8426         buffer = gst_buffer_new_and_alloc (size);
8427         gst_buffer_fill (buffer, 0, buf, size);
8428         stream->buffers = g_slist_append (stream->buffers, buffer);
8429         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
8430         break;
8431       case FOURCC_tCtC:
8432         buffer = gst_buffer_new_and_alloc (size);
8433         gst_buffer_fill (buffer, 0, buf, size);
8434         stream->buffers = g_slist_append (stream->buffers, buffer);
8435         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
8436         break;
8437       default:
8438         GST_WARNING_OBJECT (qtdemux,
8439             "unknown theora cookie %" GST_FOURCC_FORMAT,
8440             GST_FOURCC_ARGS (type));
8441         break;
8442     }
8443     buf += size;
8444   }
8445   return TRUE;
8446 }
8447
8448 static gboolean
8449 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
8450     guint length)
8451 {
8452   guint32 fourcc = 0;
8453   guint32 node_length = 0;
8454   const QtNodeType *type;
8455   const guint8 *end;
8456
8457   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
8458
8459   if (G_UNLIKELY (length < 8))
8460     goto not_enough_data;
8461
8462   node_length = QT_UINT32 (buffer);
8463   fourcc = QT_FOURCC (buffer + 4);
8464
8465   /* ignore empty nodes */
8466   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
8467     return TRUE;
8468
8469   type = qtdemux_type_get (fourcc);
8470
8471   end = buffer + length;
8472
8473   GST_LOG_OBJECT (qtdemux,
8474       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
8475       GST_FOURCC_ARGS (fourcc), node_length, type->name);
8476
8477   if (node_length > length)
8478     goto broken_atom_size;
8479
8480   if (type->flags & QT_FLAG_CONTAINER) {
8481     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8482   } else {
8483     switch (fourcc) {
8484       case FOURCC_stsd:
8485       {
8486         if (node_length < 20) {
8487           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
8488           break;
8489         }
8490         GST_DEBUG_OBJECT (qtdemux,
8491             "parsing stsd (sample table, sample description) atom");
8492         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
8493         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8494         break;
8495       }
8496       case FOURCC_mp4a:
8497       case FOURCC_alac:
8498       case FOURCC_fLaC:
8499       {
8500         guint32 version;
8501         guint32 offset;
8502         guint min_size;
8503
8504         /* also read alac (or whatever) in stead of mp4a in the following,
8505          * since a similar layout is used in other cases as well */
8506         if (fourcc == FOURCC_mp4a)
8507           min_size = 20;
8508         else if (fourcc == FOURCC_fLaC)
8509           min_size = 86;
8510         else
8511           min_size = 40;
8512
8513         /* There are two things we might encounter here: a true mp4a atom, and
8514            an mp4a entry in an stsd atom. The latter is what we're interested
8515            in, and it looks like an atom, but isn't really one. The true mp4a
8516            atom is short, so we detect it based on length here. */
8517         if (length < min_size) {
8518           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8519               GST_FOURCC_ARGS (fourcc));
8520           break;
8521         }
8522
8523         /* 'version' here is the sound sample description version. Types 0 and
8524            1 are documented in the QTFF reference, but type 2 is not: it's
8525            described in Apple header files instead (struct SoundDescriptionV2
8526            in Movies.h) */
8527         version = QT_UINT16 (buffer + 16);
8528
8529         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
8530             GST_FOURCC_ARGS (fourcc), version);
8531
8532         /* parse any esds descriptors */
8533         switch (version) {
8534           case 0:
8535             offset = 0x24;
8536             break;
8537           case 1:
8538             offset = 0x34;
8539             break;
8540           case 2:
8541             offset = 0x48;
8542             break;
8543           default:
8544             GST_WARNING_OBJECT (qtdemux,
8545                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
8546                 GST_FOURCC_ARGS (fourcc), version);
8547             offset = 0;
8548             break;
8549         }
8550         if (offset)
8551           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8552         break;
8553       }
8554       case FOURCC_mp4v:
8555       case FOURCC_MP4V:
8556       case FOURCC_fmp4:
8557       case FOURCC_FMP4:
8558       case FOURCC_apcs:
8559       case FOURCC_apch:
8560       case FOURCC_apcn:
8561       case FOURCC_apco:
8562       case FOURCC_ap4h:
8563       case FOURCC_xvid:
8564       case FOURCC_XVID:
8565       case FOURCC_H264:
8566       case FOURCC_avc1:
8567       case FOURCC_avc3:
8568       case FOURCC_H265:
8569       case FOURCC_hvc1:
8570       case FOURCC_hev1:
8571       case FOURCC_mjp2:
8572       case FOURCC_encv:
8573       {
8574         guint32 version;
8575         guint32 str_len;
8576
8577         /* codec_data is contained inside these atoms, which all have
8578          * the same format. */
8579         /* video sample description size is 86 bytes without extension.
8580          * node_length have to be bigger than 86 bytes because video sample
8581          * description can include extenstions such as esds, fiel, glbl, etc. */
8582         if (node_length < 86) {
8583           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8584               " sample description length too short (%u < 86)",
8585               GST_FOURCC_ARGS (fourcc), node_length);
8586           break;
8587         }
8588
8589         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8590             GST_FOURCC_ARGS (fourcc));
8591
8592         /* version (2 bytes) : this is set to 0, unless a compressor has changed
8593          *              its data format.
8594          * revision level (2 bytes) : must be set to 0. */
8595         version = QT_UINT32 (buffer + 16);
8596         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8597
8598         /* compressor name : PASCAL string and informative purposes
8599          * first byte : the number of bytes to be displayed.
8600          *              it has to be less than 32 because it is reserved
8601          *              space of 32 bytes total including itself. */
8602         str_len = QT_UINT8 (buffer + 50);
8603         if (str_len < 32)
8604           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8605               (char *) buffer + 51);
8606         else
8607           GST_WARNING_OBJECT (qtdemux,
8608               "compressorname length too big (%u > 31)", str_len);
8609
8610         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8611             end - buffer);
8612         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8613         break;
8614       }
8615       case FOURCC_meta:
8616       {
8617         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8618
8619         /* You are reading this correctly. QTFF specifies that the
8620          * metadata atom is a short atom, whereas ISO BMFF specifies
8621          * it's a full atom. But since so many people are doing things
8622          * differently, we actually peek into the atom to see which
8623          * variant it is */
8624         if (length < 16) {
8625           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8626               GST_FOURCC_ARGS (fourcc));
8627           break;
8628         }
8629         if (QT_FOURCC (buffer + 12) == FOURCC_hdlr) {
8630           /* Variant 1: What QTFF specifies. 'meta' is a short header which
8631            * starts with a 'hdlr' atom */
8632           qtdemux_parse_container (qtdemux, node, buffer + 8, end);
8633         } else if (QT_UINT32 (buffer + 8) == 0x00000000) {
8634           /* Variant 2: What ISO BMFF specifies. 'meta' is a _full_ atom
8635            * with version/flags both set to zero */
8636           qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8637         } else
8638           GST_WARNING_OBJECT (qtdemux, "Unknown 'meta' atom format");
8639         break;
8640       }
8641       case FOURCC_mp4s:
8642       {
8643         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8644         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8645         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8646         break;
8647       }
8648       case FOURCC_XiTh:
8649       {
8650         guint32 version;
8651         guint32 offset;
8652
8653         if (length < 16) {
8654           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8655               GST_FOURCC_ARGS (fourcc));
8656           break;
8657         }
8658
8659         version = QT_UINT32 (buffer + 12);
8660         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8661
8662         switch (version) {
8663           case 0x00000001:
8664             offset = 0x62;
8665             break;
8666           default:
8667             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8668             offset = 0;
8669             break;
8670         }
8671         if (offset) {
8672           if (length < offset) {
8673             GST_WARNING_OBJECT (qtdemux,
8674                 "skipping too small %" GST_FOURCC_FORMAT " box",
8675                 GST_FOURCC_ARGS (fourcc));
8676             break;
8677           }
8678           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8679         }
8680         break;
8681       }
8682       case FOURCC_in24:
8683       {
8684         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8685         break;
8686       }
8687       case FOURCC_uuid:
8688       {
8689         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8690         break;
8691       }
8692       case FOURCC_enca:
8693       {
8694         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8695         break;
8696       }
8697 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
8698       case FOURCC_SA3D:
8699       {
8700         qtdemux_parse_SA3D (qtdemux, buffer, end - buffer);
8701         break;
8702       }
8703 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
8704       default:
8705         if (!strcmp (type->name, "unknown"))
8706           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8707         break;
8708     }
8709   }
8710   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8711       GST_FOURCC_ARGS (fourcc));
8712   return TRUE;
8713
8714 /* ERRORS */
8715 not_enough_data:
8716   {
8717     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8718         (_("This file is corrupt and cannot be played.")),
8719         ("Not enough data for an atom header, got only %u bytes", length));
8720     return FALSE;
8721   }
8722 broken_atom_size:
8723   {
8724     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8725         (_("This file is corrupt and cannot be played.")),
8726         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8727             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8728             length));
8729     return FALSE;
8730   }
8731 }
8732
8733 static GNode *
8734 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
8735 {
8736   GNode *child;
8737   guint8 *buffer;
8738   guint32 child_fourcc;
8739
8740   for (child = g_node_first_child (node); child;
8741       child = g_node_next_sibling (child)) {
8742     buffer = (guint8 *) child->data;
8743
8744     child_fourcc = QT_FOURCC (buffer + 4);
8745
8746     if (G_UNLIKELY (child_fourcc == fourcc)) {
8747       return child;
8748     }
8749   }
8750   return NULL;
8751 }
8752
8753 static GNode *
8754 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
8755     GstByteReader * parser)
8756 {
8757   GNode *child;
8758   guint8 *buffer;
8759   guint32 child_fourcc, child_len;
8760
8761   for (child = g_node_first_child (node); child;
8762       child = g_node_next_sibling (child)) {
8763     buffer = (guint8 *) child->data;
8764
8765     child_len = QT_UINT32 (buffer);
8766     child_fourcc = QT_FOURCC (buffer + 4);
8767
8768     if (G_UNLIKELY (child_fourcc == fourcc)) {
8769       if (G_UNLIKELY (child_len < (4 + 4)))
8770         return NULL;
8771       /* FIXME: must verify if atom length < parent atom length */
8772       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8773       return child;
8774     }
8775   }
8776   return NULL;
8777 }
8778
8779 static GNode *
8780 qtdemux_tree_get_child_by_index (GNode * node, guint index)
8781 {
8782   return g_node_nth_child (node, index);
8783 }
8784
8785 static GNode *
8786 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
8787     GstByteReader * parser)
8788 {
8789   GNode *child;
8790   guint8 *buffer;
8791   guint32 child_fourcc, child_len;
8792
8793   for (child = g_node_next_sibling (node); child;
8794       child = g_node_next_sibling (child)) {
8795     buffer = (guint8 *) child->data;
8796
8797     child_fourcc = QT_FOURCC (buffer + 4);
8798
8799     if (child_fourcc == fourcc) {
8800       if (parser) {
8801         child_len = QT_UINT32 (buffer);
8802         if (G_UNLIKELY (child_len < (4 + 4)))
8803           return NULL;
8804         /* FIXME: must verify if atom length < parent atom length */
8805         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8806       }
8807       return child;
8808     }
8809   }
8810   return NULL;
8811 }
8812
8813 static GNode *
8814 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8815 {
8816   return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8817 }
8818
8819 static void
8820 qtdemux_do_allocation (QtDemuxStream * stream, GstQTDemux * qtdemux)
8821 {
8822 /* FIXME: This can only reliably work if demuxers have a
8823  * separate streaming thread per srcpad. This should be
8824  * done in a demuxer base class, which integrates parts
8825  * of multiqueue
8826  *
8827  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8828  */
8829 #if 0
8830   GstQuery *query;
8831
8832   query = gst_query_new_allocation (stream->caps, FALSE);
8833
8834   if (!gst_pad_peer_query (stream->pad, query)) {
8835     /* not a problem, just debug a little */
8836     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8837   }
8838
8839   if (stream->allocator)
8840     gst_object_unref (stream->allocator);
8841
8842   if (gst_query_get_n_allocation_params (query) > 0) {
8843     /* try the allocator */
8844     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8845         &stream->params);
8846     stream->use_allocator = TRUE;
8847   } else {
8848     stream->allocator = NULL;
8849     gst_allocation_params_init (&stream->params);
8850     stream->use_allocator = FALSE;
8851   }
8852   gst_query_unref (query);
8853 #endif
8854 }
8855
8856 static gboolean
8857 pad_query (const GValue * item, GValue * value, gpointer user_data)
8858 {
8859   GstPad *pad = g_value_get_object (item);
8860   GstQuery *query = user_data;
8861   gboolean res;
8862
8863   res = gst_pad_peer_query (pad, query);
8864
8865   if (res) {
8866     g_value_set_boolean (value, TRUE);
8867     return FALSE;
8868   }
8869
8870   GST_INFO_OBJECT (pad, "pad peer query failed");
8871   return TRUE;
8872 }
8873
8874 static gboolean
8875 gst_qtdemux_run_query (GstElement * element, GstQuery * query,
8876     GstPadDirection direction)
8877 {
8878   GstIterator *it;
8879   GstIteratorFoldFunction func = pad_query;
8880   GValue res = { 0, };
8881
8882   g_value_init (&res, G_TYPE_BOOLEAN);
8883   g_value_set_boolean (&res, FALSE);
8884
8885   /* Ask neighbor */
8886   if (direction == GST_PAD_SRC)
8887     it = gst_element_iterate_src_pads (element);
8888   else
8889     it = gst_element_iterate_sink_pads (element);
8890
8891   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
8892     gst_iterator_resync (it);
8893
8894   gst_iterator_free (it);
8895
8896   return g_value_get_boolean (&res);
8897 }
8898
8899 static void
8900 gst_qtdemux_request_protection_context (GstQTDemux * qtdemux,
8901     QtDemuxStream * stream)
8902 {
8903   GstQuery *query;
8904   GstContext *ctxt;
8905   GstElement *element = GST_ELEMENT (qtdemux);
8906   GstStructure *st;
8907   gchar **filtered_sys_ids;
8908   GValue event_list = G_VALUE_INIT;
8909   GList *walk;
8910
8911   /* 1. Check if we already have the context. */
8912   if (qtdemux->preferred_protection_system_id != NULL) {
8913     GST_LOG_OBJECT (element,
8914         "already have the protection context, no need to request it again");
8915     return;
8916   }
8917
8918   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8919   filtered_sys_ids = gst_protection_filter_systems_by_available_decryptors (
8920       (const gchar **) qtdemux->protection_system_ids->pdata);
8921
8922   g_ptr_array_remove_index (qtdemux->protection_system_ids,
8923       qtdemux->protection_system_ids->len - 1);
8924   GST_TRACE_OBJECT (qtdemux, "detected %u protection systems, we have "
8925       "decryptors for %u of them, running context request",
8926       qtdemux->protection_system_ids->len,
8927       filtered_sys_ids ? g_strv_length (filtered_sys_ids) : 0);
8928
8929
8930   if (stream->protection_scheme_event_queue.length) {
8931     GST_TRACE_OBJECT (qtdemux, "using stream event queue, length %u",
8932         stream->protection_scheme_event_queue.length);
8933     walk = stream->protection_scheme_event_queue.tail;
8934   } else {
8935     GST_TRACE_OBJECT (qtdemux, "using demuxer event queue, length %u",
8936         qtdemux->protection_event_queue.length);
8937     walk = qtdemux->protection_event_queue.tail;
8938   }
8939
8940   g_value_init (&event_list, GST_TYPE_LIST);
8941   for (; walk; walk = g_list_previous (walk)) {
8942     GValue *event_value = g_new0 (GValue, 1);
8943     g_value_init (event_value, GST_TYPE_EVENT);
8944     g_value_set_boxed (event_value, walk->data);
8945     gst_value_list_append_and_take_value (&event_list, event_value);
8946   }
8947
8948   /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
8949    *      check if downstream already has a context of the specific type
8950    *  2b) Query upstream as above.
8951    */
8952   query = gst_query_new_context ("drm-preferred-decryption-system-id");
8953   st = gst_query_writable_structure (query);
8954   gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8955       "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8956       NULL);
8957   gst_structure_set_value (st, "stream-encryption-events", &event_list);
8958   if (gst_qtdemux_run_query (element, query, GST_PAD_SRC)) {
8959     gst_query_parse_context (query, &ctxt);
8960     GST_INFO_OBJECT (element, "found context (%p) in downstream query", ctxt);
8961     gst_element_set_context (element, ctxt);
8962   } else if (gst_qtdemux_run_query (element, query, GST_PAD_SINK)) {
8963     gst_query_parse_context (query, &ctxt);
8964     GST_INFO_OBJECT (element, "found context (%p) in upstream query", ctxt);
8965     gst_element_set_context (element, ctxt);
8966   } else {
8967     /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
8968      *    the required context type and afterwards check if a
8969      *    usable context was set now as in 1). The message could
8970      *    be handled by the parent bins of the element and the
8971      *    application.
8972      */
8973     GstMessage *msg;
8974
8975     GST_INFO_OBJECT (element, "posting need context message");
8976     msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
8977         "drm-preferred-decryption-system-id");
8978     st = (GstStructure *) gst_message_get_structure (msg);
8979     gst_structure_set (st, "track-id", G_TYPE_UINT, stream->track_id,
8980         "available-stream-encryption-systems", G_TYPE_STRV, filtered_sys_ids,
8981         NULL);
8982
8983     gst_structure_set_value (st, "stream-encryption-events", &event_list);
8984     gst_element_post_message (element, msg);
8985   }
8986
8987   g_strfreev (filtered_sys_ids);
8988   g_value_unset (&event_list);
8989   gst_query_unref (query);
8990 }
8991
8992 static gboolean
8993 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8994     QtDemuxStream * stream)
8995 {
8996   GstStructure *s;
8997   const gchar *selected_system = NULL;
8998
8999   g_return_val_if_fail (qtdemux != NULL, FALSE);
9000   g_return_val_if_fail (stream != NULL, FALSE);
9001   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
9002       FALSE);
9003
9004   if (stream->protection_scheme_type != FOURCC_cenc) {
9005     GST_ERROR_OBJECT (qtdemux,
9006         "unsupported protection scheme: %" GST_FOURCC_FORMAT,
9007         GST_FOURCC_ARGS (stream->protection_scheme_type));
9008     return FALSE;
9009   }
9010   if (qtdemux->protection_system_ids == NULL) {
9011     GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
9012         "cenc protection system information has been found");
9013     return FALSE;
9014   }
9015
9016   gst_qtdemux_request_protection_context (qtdemux, stream);
9017   if (qtdemux->preferred_protection_system_id != NULL) {
9018     const gchar *preferred_system_array[] =
9019         { qtdemux->preferred_protection_system_id, NULL };
9020
9021     selected_system = gst_protection_select_system (preferred_system_array);
9022
9023     if (selected_system) {
9024       GST_TRACE_OBJECT (qtdemux, "selected preferred system %s",
9025           qtdemux->preferred_protection_system_id);
9026     } else {
9027       GST_WARNING_OBJECT (qtdemux, "could not select preferred system %s "
9028           "because there is no available decryptor",
9029           qtdemux->preferred_protection_system_id);
9030     }
9031   }
9032
9033   if (!selected_system) {
9034     g_ptr_array_add (qtdemux->protection_system_ids, NULL);
9035     selected_system = gst_protection_select_system ((const gchar **)
9036         qtdemux->protection_system_ids->pdata);
9037     g_ptr_array_remove_index (qtdemux->protection_system_ids,
9038         qtdemux->protection_system_ids->len - 1);
9039   }
9040
9041   if (!selected_system) {
9042     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
9043         "suitable decryptor element has been found");
9044     return FALSE;
9045   }
9046
9047   GST_DEBUG_OBJECT (qtdemux, "selected protection system is %s",
9048       selected_system);
9049
9050   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9051   if (!gst_structure_has_name (s, "application/x-cenc")) {
9052     gst_structure_set (s,
9053         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
9054         GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
9055         NULL);
9056     gst_structure_set_name (s, "application/x-cenc");
9057   }
9058   return TRUE;
9059 }
9060
9061 static gboolean
9062 gst_qtdemux_guess_framerate (GstQTDemux * qtdemux, QtDemuxStream * stream)
9063 {
9064   /* fps is calculated base on the duration of the average framerate since
9065    * qt does not have a fixed framerate. */
9066   gboolean fps_available = TRUE;
9067   guint32 first_duration = 0;
9068
9069   if (stream->n_samples > 0)
9070     first_duration = stream->samples[0].duration;
9071
9072   if ((stream->n_samples == 1 && first_duration == 0)
9073       || (qtdemux->fragmented && stream->n_samples_moof == 1)) {
9074     /* still frame */
9075     CUR_STREAM (stream)->fps_n = 0;
9076     CUR_STREAM (stream)->fps_d = 1;
9077   } else {
9078     if (stream->duration == 0 || stream->n_samples < 2) {
9079       CUR_STREAM (stream)->fps_n = stream->timescale;
9080       CUR_STREAM (stream)->fps_d = 1;
9081       fps_available = FALSE;
9082     } else {
9083       GstClockTime avg_duration;
9084       guint64 duration;
9085       guint32 n_samples;
9086
9087       /* duration and n_samples can be updated for fragmented format
9088        * so, framerate of fragmented format is calculated using data in a moof */
9089       if (qtdemux->fragmented && stream->n_samples_moof > 0
9090           && stream->duration_moof > 0) {
9091         n_samples = stream->n_samples_moof;
9092         duration = stream->duration_moof;
9093       } else {
9094         n_samples = stream->n_samples;
9095         duration = stream->duration;
9096       }
9097
9098       /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
9099       /* stream->duration is guint64, timescale, n_samples are guint32 */
9100       avg_duration =
9101           gst_util_uint64_scale_round (duration -
9102           first_duration, GST_SECOND,
9103           (guint64) (stream->timescale) * (n_samples - 1));
9104
9105       GST_LOG_OBJECT (qtdemux,
9106           "Calculating avg sample duration based on stream (or moof) duration %"
9107           G_GUINT64_FORMAT
9108           " minus first sample %u, leaving %d samples gives %"
9109           GST_TIME_FORMAT, duration, first_duration,
9110           n_samples - 1, GST_TIME_ARGS (avg_duration));
9111
9112 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
9113       gst_video_guess_framerate (avg_duration,
9114         &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
9115       if (CUR_STREAM (stream)->fps_d == 0)
9116         fps_available = FALSE;
9117 #else
9118       fps_available =
9119           gst_video_guess_framerate (avg_duration,
9120           &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
9121 #endif
9122
9123       GST_DEBUG_OBJECT (qtdemux,
9124           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
9125           stream->timescale, CUR_STREAM (stream)->fps_n,
9126           CUR_STREAM (stream)->fps_d);
9127     }
9128   }
9129
9130   return fps_available;
9131 }
9132
9133 static gboolean
9134 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
9135 {
9136   if (stream->subtype == FOURCC_vide) {
9137     gboolean fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9138
9139     if (CUR_STREAM (stream)->caps) {
9140       CUR_STREAM (stream)->caps =
9141           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9142
9143       if (CUR_STREAM (stream)->width && CUR_STREAM (stream)->height)
9144         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9145             "width", G_TYPE_INT, CUR_STREAM (stream)->width,
9146             "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
9147
9148       /* set framerate if calculated framerate is reliable */
9149       if (fps_available) {
9150         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9151             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9152             CUR_STREAM (stream)->fps_d, NULL);
9153       }
9154
9155       /* calculate pixel-aspect-ratio using display width and height */
9156       GST_DEBUG_OBJECT (qtdemux,
9157           "video size %dx%d, target display size %dx%d",
9158           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
9159           stream->display_width, stream->display_height);
9160       /* qt file might have pasp atom */
9161       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9162         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
9163             CUR_STREAM (stream)->par_h);
9164         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9165             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9166             CUR_STREAM (stream)->par_h, NULL);
9167       } else if (stream->display_width > 0 && stream->display_height > 0
9168           && CUR_STREAM (stream)->width > 0
9169           && CUR_STREAM (stream)->height > 0) {
9170         gint n, d;
9171
9172         /* calculate the pixel aspect ratio using the display and pixel w/h */
9173         n = stream->display_width * CUR_STREAM (stream)->height;
9174         d = stream->display_height * CUR_STREAM (stream)->width;
9175         if (n == d)
9176           n = d = 1;
9177         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
9178         CUR_STREAM (stream)->par_w = n;
9179         CUR_STREAM (stream)->par_h = d;
9180         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
9181             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
9182             CUR_STREAM (stream)->par_h, NULL);
9183       }
9184
9185       if (CUR_STREAM (stream)->interlace_mode > 0) {
9186         if (CUR_STREAM (stream)->interlace_mode == 1) {
9187           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9188               G_TYPE_STRING, "progressive", NULL);
9189         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
9190           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
9191               G_TYPE_STRING, "interleaved", NULL);
9192           if (CUR_STREAM (stream)->field_order == 9) {
9193             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9194                 G_TYPE_STRING, "top-field-first", NULL);
9195           } else if (CUR_STREAM (stream)->field_order == 14) {
9196             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
9197                 G_TYPE_STRING, "bottom-field-first", NULL);
9198           }
9199         }
9200       }
9201
9202       /* Create incomplete colorimetry here if needed */
9203       if (CUR_STREAM (stream)->colorimetry.range ||
9204           CUR_STREAM (stream)->colorimetry.matrix ||
9205           CUR_STREAM (stream)->colorimetry.transfer
9206           || CUR_STREAM (stream)->colorimetry.primaries) {
9207         gchar *colorimetry =
9208             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
9209         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
9210             G_TYPE_STRING, colorimetry, NULL);
9211         g_free (colorimetry);
9212       }
9213
9214       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
9215         guint par_w = 1, par_h = 1;
9216
9217         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
9218           par_w = CUR_STREAM (stream)->par_w;
9219           par_h = CUR_STREAM (stream)->par_h;
9220         }
9221
9222         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
9223                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
9224                 par_h)) {
9225           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
9226         }
9227
9228         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9229             "multiview-mode", G_TYPE_STRING,
9230             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
9231             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
9232             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
9233       }
9234     }
9235   }
9236
9237   else if (stream->subtype == FOURCC_soun) {
9238     if (CUR_STREAM (stream)->caps) {
9239       CUR_STREAM (stream)->caps =
9240           gst_caps_make_writable (CUR_STREAM (stream)->caps);
9241       if (CUR_STREAM (stream)->rate > 0)
9242         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9243             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
9244       if (CUR_STREAM (stream)->n_channels > 0)
9245         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9246             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
9247       if (CUR_STREAM (stream)->n_channels > 2) {
9248         /* FIXME: Need to parse the 'chan' atom to get channel layouts
9249          * correctly; this is just the minimum we can do - assume
9250          * we don't actually have any channel positions. */
9251         gst_caps_set_simple (CUR_STREAM (stream)->caps,
9252             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
9253       }
9254     }
9255   }
9256
9257   else if (stream->subtype == FOURCC_clcp && CUR_STREAM (stream)->caps) {
9258     const GstStructure *s;
9259     QtDemuxStream *fps_stream = NULL;
9260     gboolean fps_available = FALSE;
9261
9262     /* CEA608 closed caption tracks are a bit special in that each sample
9263      * can contain CCs for multiple frames, and CCs can be omitted and have to
9264      * be inferred from the duration of the sample then.
9265      *
9266      * As such we take the framerate from the (first) video track here for
9267      * CEA608 as there must be one CC byte pair for every video frame
9268      * according to the spec.
9269      *
9270      * For CEA708 all is fine and there is one sample per frame.
9271      */
9272
9273     s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
9274     if (gst_structure_has_name (s, "closedcaption/x-cea-608")) {
9275       gint i;
9276
9277       for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
9278         QtDemuxStream *tmp = QTDEMUX_NTH_STREAM (qtdemux, i);
9279
9280         if (tmp->subtype == FOURCC_vide) {
9281           fps_stream = tmp;
9282           break;
9283         }
9284       }
9285
9286       if (fps_stream) {
9287         fps_available = gst_qtdemux_guess_framerate (qtdemux, fps_stream);
9288         CUR_STREAM (stream)->fps_n = CUR_STREAM (fps_stream)->fps_n;
9289         CUR_STREAM (stream)->fps_d = CUR_STREAM (fps_stream)->fps_d;
9290       }
9291     } else {
9292       fps_available = gst_qtdemux_guess_framerate (qtdemux, stream);
9293       fps_stream = stream;
9294     }
9295
9296     CUR_STREAM (stream)->caps =
9297         gst_caps_make_writable (CUR_STREAM (stream)->caps);
9298
9299     /* set framerate if calculated framerate is reliable */
9300     if (fps_available) {
9301       gst_caps_set_simple (CUR_STREAM (stream)->caps,
9302           "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
9303           CUR_STREAM (stream)->fps_d, NULL);
9304     }
9305   }
9306
9307   if (stream->pad) {
9308     GstCaps *prev_caps = NULL;
9309
9310     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
9311     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
9312     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
9313     gst_pad_set_active (stream->pad, TRUE);
9314
9315     gst_pad_use_fixed_caps (stream->pad);
9316
9317     if (stream->protected) {
9318       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
9319         GST_ERROR_OBJECT (qtdemux,
9320             "Failed to configure protected stream caps.");
9321         return FALSE;
9322       }
9323     }
9324
9325     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9326         CUR_STREAM (stream)->caps);
9327     if (stream->new_stream) {
9328       GstEvent *event;
9329       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
9330
9331       event =
9332           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
9333           0);
9334       if (event) {
9335         gst_event_parse_stream_flags (event, &stream_flags);
9336         if (gst_event_parse_group_id (event, &qtdemux->group_id))
9337           qtdemux->have_group_id = TRUE;
9338         else
9339           qtdemux->have_group_id = FALSE;
9340         gst_event_unref (event);
9341       } else if (!qtdemux->have_group_id) {
9342         qtdemux->have_group_id = TRUE;
9343         qtdemux->group_id = gst_util_group_id_next ();
9344       }
9345
9346       stream->new_stream = FALSE;
9347       event = gst_event_new_stream_start (stream->stream_id);
9348       if (qtdemux->have_group_id)
9349         gst_event_set_group_id (event, qtdemux->group_id);
9350       if (stream->disabled)
9351         stream_flags |= GST_STREAM_FLAG_UNSELECT;
9352       if (CUR_STREAM (stream)->sparse) {
9353         stream_flags |= GST_STREAM_FLAG_SPARSE;
9354       } else {
9355         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
9356       }
9357       gst_event_set_stream_flags (event, stream_flags);
9358       gst_pad_push_event (stream->pad, event);
9359     }
9360
9361     prev_caps = gst_pad_get_current_caps (stream->pad);
9362
9363     if (CUR_STREAM (stream)->caps) {
9364       if (!prev_caps
9365           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
9366         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
9367             CUR_STREAM (stream)->caps);
9368         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
9369       } else {
9370         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
9371       }
9372     } else {
9373       GST_WARNING_OBJECT (qtdemux, "stream without caps");
9374     }
9375
9376     if (prev_caps)
9377       gst_caps_unref (prev_caps);
9378     stream->new_caps = FALSE;
9379   }
9380   return TRUE;
9381 }
9382
9383 static void
9384 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
9385     QtDemuxStream * stream)
9386 {
9387   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
9388     return;
9389
9390   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
9391       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
9392   if (G_UNLIKELY (stream->stsd_sample_description_id >=
9393           stream->stsd_entries_length)) {
9394     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
9395         (_("This file is invalid and cannot be played.")),
9396         ("New sample description id is out of bounds (%d >= %d)",
9397             stream->stsd_sample_description_id, stream->stsd_entries_length));
9398   } else {
9399     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
9400     stream->new_caps = TRUE;
9401   }
9402 }
9403
9404 static gboolean
9405 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
9406     QtDemuxStream * stream, GstTagList * list)
9407 {
9408   gboolean ret = TRUE;
9409
9410   if (stream->subtype == FOURCC_vide) {
9411     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9412
9413     stream->pad =
9414         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9415     g_free (name);
9416
9417     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9418       gst_object_unref (stream->pad);
9419       stream->pad = NULL;
9420       ret = FALSE;
9421       goto done;
9422     }
9423
9424     qtdemux->n_video_streams++;
9425   } else if (stream->subtype == FOURCC_soun) {
9426     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
9427
9428     stream->pad =
9429         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
9430     g_free (name);
9431     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9432       gst_object_unref (stream->pad);
9433       stream->pad = NULL;
9434       ret = FALSE;
9435       goto done;
9436     }
9437     qtdemux->n_audio_streams++;
9438   } else if (stream->subtype == FOURCC_strm) {
9439     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
9440   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9441       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
9442       || stream->subtype == FOURCC_clcp) {
9443     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
9444
9445     stream->pad =
9446         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
9447     g_free (name);
9448     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9449       gst_object_unref (stream->pad);
9450       stream->pad = NULL;
9451       ret = FALSE;
9452       goto done;
9453     }
9454     qtdemux->n_sub_streams++;
9455   } else if (CUR_STREAM (stream)->caps) {
9456     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
9457
9458     stream->pad =
9459         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
9460     g_free (name);
9461     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
9462       gst_object_unref (stream->pad);
9463       stream->pad = NULL;
9464       ret = FALSE;
9465       goto done;
9466     }
9467     qtdemux->n_video_streams++;
9468   } else {
9469     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
9470     goto done;
9471   }
9472
9473   if (stream->pad) {
9474     GList *l;
9475
9476     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
9477         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
9478     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
9479     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
9480
9481     if (stream->stream_tags)
9482       gst_tag_list_unref (stream->stream_tags);
9483     stream->stream_tags = list;
9484     list = NULL;
9485     /* global tags go on each pad anyway */
9486     stream->send_global_tags = TRUE;
9487     /* send upstream GST_EVENT_PROTECTION events that were received before
9488        this source pad was created */
9489     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
9490       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
9491   }
9492 done:
9493   if (list)
9494     gst_tag_list_unref (list);
9495   return ret;
9496 }
9497
9498 /* find next atom with @fourcc starting at @offset */
9499 static GstFlowReturn
9500 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
9501     guint64 * length, guint32 fourcc)
9502 {
9503   GstFlowReturn ret;
9504   guint32 lfourcc;
9505   GstBuffer *buf;
9506
9507   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
9508       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
9509
9510   while (TRUE) {
9511     GstMapInfo map;
9512
9513     buf = NULL;
9514     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
9515     if (G_UNLIKELY (ret != GST_FLOW_OK))
9516       goto locate_failed;
9517     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
9518       /* likely EOF */
9519       ret = GST_FLOW_EOS;
9520       gst_buffer_unref (buf);
9521       goto locate_failed;
9522     }
9523     gst_buffer_map (buf, &map, GST_MAP_READ);
9524     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
9525     gst_buffer_unmap (buf, &map);
9526     gst_buffer_unref (buf);
9527
9528     if (G_UNLIKELY (*length == 0)) {
9529       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
9530       ret = GST_FLOW_ERROR;
9531       goto locate_failed;
9532     }
9533
9534     if (lfourcc == fourcc) {
9535       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
9536           *offset);
9537       break;
9538     } else {
9539       GST_LOG_OBJECT (qtdemux,
9540           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
9541           GST_FOURCC_ARGS (fourcc), *offset);
9542       *offset += *length;
9543     }
9544   }
9545
9546   return GST_FLOW_OK;
9547
9548 locate_failed:
9549   {
9550     /* might simply have had last one */
9551     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
9552     return ret;
9553   }
9554 }
9555
9556 /* should only do something in pull mode */
9557 /* call with OBJECT lock */
9558 static GstFlowReturn
9559 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
9560 {
9561   guint64 length, offset;
9562   GstBuffer *buf = NULL;
9563   GstFlowReturn ret = GST_FLOW_OK;
9564   GstFlowReturn res = GST_FLOW_OK;
9565   GstMapInfo map;
9566
9567   offset = qtdemux->moof_offset;
9568   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
9569
9570   if (!offset) {
9571     GST_DEBUG_OBJECT (qtdemux, "no next moof");
9572     return GST_FLOW_EOS;
9573   }
9574
9575   /* best not do pull etc with lock held */
9576   GST_OBJECT_UNLOCK (qtdemux);
9577
9578   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9579   if (ret != GST_FLOW_OK)
9580     goto flow_failed;
9581
9582   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
9583   if (G_UNLIKELY (ret != GST_FLOW_OK))
9584     goto flow_failed;
9585   gst_buffer_map (buf, &map, GST_MAP_READ);
9586   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
9587     gst_buffer_unmap (buf, &map);
9588     gst_buffer_unref (buf);
9589     buf = NULL;
9590     goto parse_failed;
9591   }
9592
9593   gst_buffer_unmap (buf, &map);
9594   gst_buffer_unref (buf);
9595   buf = NULL;
9596
9597   offset += length;
9598   /* look for next moof */
9599   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
9600   if (G_UNLIKELY (ret != GST_FLOW_OK))
9601     goto flow_failed;
9602
9603 exit:
9604   GST_OBJECT_LOCK (qtdemux);
9605
9606   qtdemux->moof_offset = offset;
9607
9608   return res;
9609
9610 parse_failed:
9611   {
9612     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
9613     offset = 0;
9614     res = GST_FLOW_ERROR;
9615     goto exit;
9616   }
9617 flow_failed:
9618   {
9619     /* maybe upstream temporarily flushing */
9620     if (ret != GST_FLOW_FLUSHING) {
9621       GST_DEBUG_OBJECT (qtdemux, "no next moof");
9622       offset = 0;
9623     } else {
9624       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
9625       /* resume at current position next time */
9626     }
9627     res = ret;
9628     goto exit;
9629   }
9630 }
9631
9632 /* initialise bytereaders for stbl sub-atoms */
9633 static gboolean
9634 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
9635 {
9636   stream->stbl_index = -1;      /* no samples have yet been parsed */
9637   stream->sample_index = -1;
9638
9639   /* time-to-sample atom */
9640   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
9641     goto corrupt_file;
9642
9643   /* copy atom data into a new buffer for later use */
9644   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
9645
9646   /* skip version + flags */
9647   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
9648       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
9649     goto corrupt_file;
9650   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
9651
9652   /* make sure there's enough data */
9653   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
9654     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
9655     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
9656         stream->n_sample_times);
9657     if (!stream->n_sample_times)
9658       goto corrupt_file;
9659   }
9660
9661   /* sync sample atom */
9662   stream->stps_present = FALSE;
9663   if ((stream->stss_present =
9664           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
9665               &stream->stss) ? TRUE : FALSE) == TRUE) {
9666     /* copy atom data into a new buffer for later use */
9667     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
9668
9669     /* skip version + flags */
9670     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
9671         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
9672       goto corrupt_file;
9673
9674     if (stream->n_sample_syncs) {
9675       /* make sure there's enough data */
9676       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
9677         goto corrupt_file;
9678     }
9679
9680     /* partial sync sample atom */
9681     if ((stream->stps_present =
9682             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
9683                 &stream->stps) ? TRUE : FALSE) == TRUE) {
9684       /* copy atom data into a new buffer for later use */
9685       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
9686
9687       /* skip version + flags */
9688       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
9689           !gst_byte_reader_get_uint32_be (&stream->stps,
9690               &stream->n_sample_partial_syncs))
9691         goto corrupt_file;
9692
9693       /* if there are no entries, the stss table contains the real
9694        * sync samples */
9695       if (stream->n_sample_partial_syncs) {
9696         /* make sure there's enough data */
9697         if (!qt_atom_parser_has_chunks (&stream->stps,
9698                 stream->n_sample_partial_syncs, 4))
9699           goto corrupt_file;
9700       }
9701     }
9702   }
9703
9704   /* sample size */
9705   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
9706     goto no_samples;
9707
9708   /* copy atom data into a new buffer for later use */
9709   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
9710
9711   /* skip version + flags */
9712   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
9713       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
9714     goto corrupt_file;
9715
9716   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
9717     goto corrupt_file;
9718
9719   if (!stream->n_samples)
9720     goto no_samples;
9721
9722   /* sample-to-chunk atom */
9723   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
9724     goto corrupt_file;
9725
9726   /* copy atom data into a new buffer for later use */
9727   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
9728
9729   /* skip version + flags */
9730   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
9731       !gst_byte_reader_get_uint32_be (&stream->stsc,
9732           &stream->n_samples_per_chunk))
9733     goto corrupt_file;
9734
9735   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
9736       stream->n_samples_per_chunk);
9737
9738   /* make sure there's enough data */
9739   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
9740           12))
9741     goto corrupt_file;
9742
9743
9744   /* chunk offset */
9745   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
9746     stream->co_size = sizeof (guint32);
9747   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
9748           &stream->stco))
9749     stream->co_size = sizeof (guint64);
9750   else
9751     goto corrupt_file;
9752
9753   /* copy atom data into a new buffer for later use */
9754   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
9755
9756   /* skip version + flags */
9757   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
9758     goto corrupt_file;
9759
9760   /* chunks_are_samples == TRUE means treat chunks as samples */
9761   stream->chunks_are_samples = stream->sample_size
9762       && !CUR_STREAM (stream)->sampled;
9763   if (stream->chunks_are_samples) {
9764     /* treat chunks as samples */
9765     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
9766       goto corrupt_file;
9767   } else {
9768     /* skip number of entries */
9769     if (!gst_byte_reader_skip (&stream->stco, 4))
9770       goto corrupt_file;
9771
9772     /* make sure there are enough data in the stsz atom */
9773     if (!stream->sample_size) {
9774       /* different sizes for each sample */
9775       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
9776         goto corrupt_file;
9777     }
9778   }
9779
9780   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
9781       stream->n_samples, (guint) sizeof (QtDemuxSample),
9782       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
9783
9784   if (stream->n_samples >=
9785       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
9786     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
9787         "be larger than %uMB (broken file?)", stream->n_samples,
9788         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
9789     return FALSE;
9790   }
9791
9792   g_assert (stream->samples == NULL);
9793   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
9794   if (!stream->samples) {
9795     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
9796         stream->n_samples);
9797     return FALSE;
9798   }
9799
9800   /* composition time-to-sample */
9801   if ((stream->ctts_present =
9802           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9803               &stream->ctts) ? TRUE : FALSE) == TRUE) {
9804     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9805
9806     /* copy atom data into a new buffer for later use */
9807     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
9808
9809     /* skip version + flags */
9810     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9811         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9812             &stream->n_composition_times))
9813       goto corrupt_file;
9814
9815     /* make sure there's enough data */
9816     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9817             4 + 4))
9818       goto corrupt_file;
9819
9820     /* This is optional, if missing we iterate the ctts */
9821     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9822       if (!gst_byte_reader_skip (&cslg, 1 + 3)
9823           || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9824         g_free ((gpointer) cslg.data);
9825         goto corrupt_file;
9826       }
9827     } else {
9828       gint32 cslg_least = 0;
9829       guint num_entries, pos;
9830       gint i;
9831
9832       pos = gst_byte_reader_get_pos (&stream->ctts);
9833       num_entries = stream->n_composition_times;
9834
9835       stream->cslg_shift = 0;
9836
9837       for (i = 0; i < num_entries; i++) {
9838         gint32 offset;
9839
9840         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9841         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9842         /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
9843          * slightly inaccurate PTS could be more usable than corrupted one */
9844         if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
9845           GST_WARNING_OBJECT (qtdemux,
9846               "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
9847               " larger than duration %" G_GUINT64_FORMAT,
9848               offset, stream->duration);
9849
9850           stream->cslg_shift = 0;
9851           stream->ctts_present = FALSE;
9852           return TRUE;
9853         }
9854
9855         if (offset < cslg_least)
9856           cslg_least = offset;
9857       }
9858
9859       if (cslg_least < 0)
9860         stream->cslg_shift = ABS (cslg_least);
9861       else
9862         stream->cslg_shift = 0;
9863
9864       /* reset the reader so we can generate sample table */
9865       gst_byte_reader_set_pos (&stream->ctts, pos);
9866     }
9867   } else {
9868     /* Ensure the cslg_shift value is consistent so we can use it
9869      * unconditionnally to produce TS and Segment */
9870     stream->cslg_shift = 0;
9871   }
9872
9873   return TRUE;
9874
9875 corrupt_file:
9876   {
9877     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9878         (_("This file is corrupt and cannot be played.")), (NULL));
9879     return FALSE;
9880   }
9881 no_samples:
9882   {
9883     gst_qtdemux_stbl_free (stream);
9884     if (!qtdemux->fragmented) {
9885       /* not quite good */
9886       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9887       return FALSE;
9888     } else {
9889       /* may pick up samples elsewhere */
9890       return TRUE;
9891     }
9892   }
9893 }
9894
9895 /* collect samples from the next sample to be parsed up to sample @n for @stream
9896  * by reading the info from @stbl
9897  *
9898  * This code can be executed from both the streaming thread and the seeking
9899  * thread so it takes the object lock to protect itself
9900  */
9901 static gboolean
9902 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9903 {
9904   gint i, j, k;
9905   QtDemuxSample *samples, *first, *cur, *last;
9906   guint32 n_samples_per_chunk;
9907   guint32 n_samples;
9908
9909   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9910       GST_FOURCC_FORMAT ", pad %s",
9911       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9912       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9913
9914   n_samples = stream->n_samples;
9915
9916   if (n >= n_samples)
9917     goto out_of_samples;
9918
9919   GST_OBJECT_LOCK (qtdemux);
9920   if (n <= stream->stbl_index)
9921     goto already_parsed;
9922
9923   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9924
9925   if (!stream->stsz.data) {
9926     /* so we already parsed and passed all the moov samples;
9927      * onto fragmented ones */
9928     g_assert (qtdemux->fragmented);
9929     goto done;
9930   }
9931
9932   /* pointer to the sample table */
9933   samples = stream->samples;
9934
9935   /* starts from -1, moves to the next sample index to parse */
9936   stream->stbl_index++;
9937
9938   /* keep track of the first and last sample to fill */
9939   first = &samples[stream->stbl_index];
9940   last = &samples[n];
9941
9942   if (!stream->chunks_are_samples) {
9943     /* set the sample sizes */
9944     if (stream->sample_size == 0) {
9945       /* different sizes for each sample */
9946       for (cur = first; cur <= last; cur++) {
9947         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9948         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9949             (guint) (cur - samples), cur->size);
9950       }
9951     } else {
9952       /* samples have the same size */
9953       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9954       for (cur = first; cur <= last; cur++)
9955         cur->size = stream->sample_size;
9956     }
9957   }
9958
9959   n_samples_per_chunk = stream->n_samples_per_chunk;
9960   cur = first;
9961
9962   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9963     guint32 last_chunk;
9964
9965     if (stream->stsc_chunk_index >= stream->last_chunk
9966         || stream->stsc_chunk_index < stream->first_chunk) {
9967       stream->first_chunk =
9968           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9969       stream->samples_per_chunk =
9970           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9971       /* starts from 1 */
9972       stream->stsd_sample_description_id =
9973           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9974
9975       /* chunk numbers are counted from 1 it seems */
9976       if (G_UNLIKELY (stream->first_chunk == 0))
9977         goto corrupt_file;
9978
9979       --stream->first_chunk;
9980
9981       /* the last chunk of each entry is calculated by taking the first chunk
9982        * of the next entry; except if there is no next, where we fake it with
9983        * INT_MAX */
9984       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9985         stream->last_chunk = G_MAXUINT32;
9986       } else {
9987         stream->last_chunk =
9988             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9989         if (G_UNLIKELY (stream->last_chunk == 0))
9990           goto corrupt_file;
9991
9992         --stream->last_chunk;
9993       }
9994
9995       GST_LOG_OBJECT (qtdemux,
9996           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9997           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9998           stream->samples_per_chunk, stream->stsd_sample_description_id);
9999
10000       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
10001         goto corrupt_file;
10002
10003       if (stream->last_chunk != G_MAXUINT32) {
10004         if (!qt_atom_parser_peek_sub (&stream->stco,
10005                 stream->first_chunk * stream->co_size,
10006                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
10007                 &stream->co_chunk))
10008           goto corrupt_file;
10009
10010       } else {
10011         stream->co_chunk = stream->stco;
10012         if (!gst_byte_reader_skip (&stream->co_chunk,
10013                 stream->first_chunk * stream->co_size))
10014           goto corrupt_file;
10015       }
10016
10017       stream->stsc_chunk_index = stream->first_chunk;
10018     }
10019
10020     last_chunk = stream->last_chunk;
10021
10022     if (stream->chunks_are_samples) {
10023       cur = &samples[stream->stsc_chunk_index];
10024
10025       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10026         if (j > n) {
10027           /* save state */
10028           stream->stsc_chunk_index = j;
10029           goto done;
10030         }
10031
10032         cur->offset =
10033             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
10034             stream->co_size);
10035
10036         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
10037             "%" G_GUINT64_FORMAT, j, cur->offset);
10038
10039         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
10040             CUR_STREAM (stream)->bytes_per_frame > 0) {
10041           cur->size =
10042               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
10043               CUR_STREAM (stream)->samples_per_frame *
10044               CUR_STREAM (stream)->bytes_per_frame;
10045         } else {
10046           cur->size = stream->samples_per_chunk;
10047         }
10048
10049         GST_DEBUG_OBJECT (qtdemux,
10050             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
10051             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
10052                     stream->stco_sample_index)), cur->size);
10053
10054         cur->timestamp = stream->stco_sample_index;
10055         cur->duration = stream->samples_per_chunk;
10056         cur->keyframe = TRUE;
10057         cur++;
10058
10059         stream->stco_sample_index += stream->samples_per_chunk;
10060       }
10061       stream->stsc_chunk_index = j;
10062     } else {
10063       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
10064         guint32 samples_per_chunk;
10065         guint64 chunk_offset;
10066
10067         if (!stream->stsc_sample_index
10068             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
10069                 &stream->chunk_offset))
10070           goto corrupt_file;
10071
10072         samples_per_chunk = stream->samples_per_chunk;
10073         chunk_offset = stream->chunk_offset;
10074
10075         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
10076           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
10077               G_GUINT64_FORMAT " and size %d",
10078               (guint) (cur - samples), chunk_offset, cur->size);
10079
10080           cur->offset = chunk_offset;
10081           chunk_offset += cur->size;
10082           cur++;
10083
10084           if (G_UNLIKELY (cur > last)) {
10085             /* save state */
10086             stream->stsc_sample_index = k + 1;
10087             stream->chunk_offset = chunk_offset;
10088             stream->stsc_chunk_index = j;
10089             goto done2;
10090           }
10091         }
10092         stream->stsc_sample_index = 0;
10093       }
10094       stream->stsc_chunk_index = j;
10095     }
10096     stream->stsc_index++;
10097   }
10098
10099   if (stream->chunks_are_samples)
10100     goto ctts;
10101 done2:
10102   {
10103     guint32 n_sample_times;
10104
10105     n_sample_times = stream->n_sample_times;
10106     cur = first;
10107
10108     for (i = stream->stts_index; i < n_sample_times; i++) {
10109       guint32 stts_samples;
10110       gint32 stts_duration;
10111       gint64 stts_time;
10112
10113       if (stream->stts_sample_index >= stream->stts_samples
10114           || !stream->stts_sample_index) {
10115
10116         stream->stts_samples =
10117             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10118         stream->stts_duration =
10119             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
10120
10121         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
10122             i, stream->stts_samples, stream->stts_duration);
10123
10124         stream->stts_sample_index = 0;
10125       }
10126
10127       stts_samples = stream->stts_samples;
10128       stts_duration = stream->stts_duration;
10129       stts_time = stream->stts_time;
10130
10131       for (j = stream->stts_sample_index; j < stts_samples; j++) {
10132         GST_DEBUG_OBJECT (qtdemux,
10133             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
10134             (guint) (cur - samples), j,
10135             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
10136
10137         cur->timestamp = stts_time;
10138         cur->duration = stts_duration;
10139
10140         /* avoid 32-bit wrap-around,
10141          * but still mind possible 'negative' duration */
10142         stts_time += (gint64) stts_duration;
10143         cur++;
10144
10145         if (G_UNLIKELY (cur > last)) {
10146           /* save values */
10147           stream->stts_time = stts_time;
10148           stream->stts_sample_index = j + 1;
10149           if (stream->stts_sample_index >= stream->stts_samples)
10150             stream->stts_index++;
10151           goto done3;
10152         }
10153       }
10154       stream->stts_sample_index = 0;
10155       stream->stts_time = stts_time;
10156       stream->stts_index++;
10157     }
10158     /* fill up empty timestamps with the last timestamp, this can happen when
10159      * the last samples do not decode and so we don't have timestamps for them.
10160      * We however look at the last timestamp to estimate the track length so we
10161      * need something in here. */
10162     for (; cur < last; cur++) {
10163       GST_DEBUG_OBJECT (qtdemux,
10164           "fill sample %d: timestamp %" GST_TIME_FORMAT,
10165           (guint) (cur - samples),
10166           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
10167       cur->timestamp = stream->stts_time;
10168       cur->duration = -1;
10169     }
10170   }
10171 done3:
10172   {
10173     /* sample sync, can be NULL */
10174     if (stream->stss_present == TRUE) {
10175       guint32 n_sample_syncs;
10176
10177       n_sample_syncs = stream->n_sample_syncs;
10178
10179       if (!n_sample_syncs) {
10180         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
10181         stream->all_keyframe = TRUE;
10182       } else {
10183         for (i = stream->stss_index; i < n_sample_syncs; i++) {
10184           /* note that the first sample is index 1, not 0 */
10185           guint32 index;
10186
10187           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
10188
10189           if (G_LIKELY (index > 0 && index <= n_samples)) {
10190             index -= 1;
10191             samples[index].keyframe = TRUE;
10192             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10193             /* and exit if we have enough samples */
10194             if (G_UNLIKELY (index >= n)) {
10195               i++;
10196               break;
10197             }
10198           }
10199         }
10200         /* save state */
10201         stream->stss_index = i;
10202       }
10203
10204       /* stps marks partial sync frames like open GOP I-Frames */
10205       if (stream->stps_present == TRUE) {
10206         guint32 n_sample_partial_syncs;
10207
10208         n_sample_partial_syncs = stream->n_sample_partial_syncs;
10209
10210         /* if there are no entries, the stss table contains the real
10211          * sync samples */
10212         if (n_sample_partial_syncs) {
10213           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
10214             /* note that the first sample is index 1, not 0 */
10215             guint32 index;
10216
10217             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
10218
10219             if (G_LIKELY (index > 0 && index <= n_samples)) {
10220               index -= 1;
10221               samples[index].keyframe = TRUE;
10222               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
10223               /* and exit if we have enough samples */
10224               if (G_UNLIKELY (index >= n)) {
10225                 i++;
10226                 break;
10227               }
10228             }
10229           }
10230           /* save state */
10231           stream->stps_index = i;
10232         }
10233       }
10234     } else {
10235       /* no stss, all samples are keyframes */
10236       stream->all_keyframe = TRUE;
10237       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
10238     }
10239   }
10240
10241 ctts:
10242   /* composition time to sample */
10243   if (stream->ctts_present == TRUE) {
10244     guint32 n_composition_times;
10245     guint32 ctts_count;
10246     gint32 ctts_soffset;
10247
10248     /* Fill in the pts_offsets */
10249     cur = first;
10250     n_composition_times = stream->n_composition_times;
10251
10252     for (i = stream->ctts_index; i < n_composition_times; i++) {
10253       if (stream->ctts_sample_index >= stream->ctts_count
10254           || !stream->ctts_sample_index) {
10255         stream->ctts_count =
10256             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
10257         stream->ctts_soffset =
10258             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
10259         stream->ctts_sample_index = 0;
10260       }
10261
10262       ctts_count = stream->ctts_count;
10263       ctts_soffset = stream->ctts_soffset;
10264
10265       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
10266         cur->pts_offset = ctts_soffset;
10267         cur++;
10268
10269         if (G_UNLIKELY (cur > last)) {
10270           /* save state */
10271           stream->ctts_sample_index = j + 1;
10272           goto done;
10273         }
10274       }
10275       stream->ctts_sample_index = 0;
10276       stream->ctts_index++;
10277     }
10278   }
10279 done:
10280   stream->stbl_index = n;
10281   /* if index has been completely parsed, free data that is no-longer needed */
10282   if (n + 1 == stream->n_samples) {
10283     gst_qtdemux_stbl_free (stream);
10284     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
10285     if (qtdemux->pullbased) {
10286       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
10287       while (n + 1 == stream->n_samples)
10288         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
10289           break;
10290     }
10291   }
10292   GST_OBJECT_UNLOCK (qtdemux);
10293
10294   return TRUE;
10295
10296   /* SUCCESS */
10297 already_parsed:
10298   {
10299     GST_LOG_OBJECT (qtdemux,
10300         "Tried to parse up to sample %u but this sample has already been parsed",
10301         n);
10302     /* if fragmented, there may be more */
10303     if (qtdemux->fragmented && n == stream->stbl_index)
10304       goto done;
10305     GST_OBJECT_UNLOCK (qtdemux);
10306     return TRUE;
10307   }
10308   /* ERRORS */
10309 out_of_samples:
10310   {
10311     GST_LOG_OBJECT (qtdemux,
10312         "Tried to parse up to sample %u but there are only %u samples", n + 1,
10313         stream->n_samples);
10314     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10315         (_("This file is corrupt and cannot be played.")), (NULL));
10316     return FALSE;
10317   }
10318 corrupt_file:
10319   {
10320     GST_OBJECT_UNLOCK (qtdemux);
10321     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10322         (_("This file is corrupt and cannot be played.")), (NULL));
10323     return FALSE;
10324   }
10325 }
10326
10327 /* collect all segment info for @stream.
10328  */
10329 static gboolean
10330 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
10331     GNode * trak)
10332 {
10333   GNode *edts;
10334   /* accept edts if they contain gaps at start and there is only
10335    * one media segment */
10336   gboolean allow_pushbased_edts = TRUE;
10337   gint media_segments_count = 0;
10338
10339   /* parse and prepare segment info from the edit list */
10340   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
10341   stream->n_segments = 0;
10342   stream->segments = NULL;
10343   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
10344     GNode *elst;
10345     gint n_segments;
10346     gint segment_number, entry_size;
10347     guint64 time;
10348     GstClockTime stime;
10349     const guint8 *buffer;
10350     guint8 version;
10351     guint32 size;
10352
10353     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
10354     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
10355       goto done;
10356
10357     buffer = elst->data;
10358
10359     size = QT_UINT32 (buffer);
10360     /* version, flags, n_segments */
10361     if (size < 16) {
10362       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10363       goto done;
10364     }
10365     version = QT_UINT8 (buffer + 8);
10366     entry_size = (version == 1) ? 20 : 12;
10367
10368     n_segments = QT_UINT32 (buffer + 12);
10369
10370     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
10371       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
10372       goto done;
10373     }
10374
10375     /* we might allocate a bit too much, at least allocate 1 segment */
10376     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
10377
10378     /* segments always start from 0 */
10379     time = 0;
10380     stime = 0;
10381     buffer += 16;
10382     for (segment_number = 0; segment_number < n_segments; segment_number++) {
10383       guint64 duration;
10384       guint64 media_time;
10385       gboolean empty_edit = FALSE;
10386       QtDemuxSegment *segment;
10387       guint32 rate_int;
10388       GstClockTime media_start = GST_CLOCK_TIME_NONE;
10389
10390       if (version == 1) {
10391         media_time = QT_UINT64 (buffer + 8);
10392         duration = QT_UINT64 (buffer);
10393         if (media_time == G_MAXUINT64)
10394           empty_edit = TRUE;
10395       } else {
10396         media_time = QT_UINT32 (buffer + 4);
10397         duration = QT_UINT32 (buffer);
10398         if (media_time == G_MAXUINT32)
10399           empty_edit = TRUE;
10400       }
10401
10402       if (!empty_edit)
10403         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
10404
10405       segment = &stream->segments[segment_number];
10406
10407       /* time and duration expressed in global timescale */
10408       segment->time = stime;
10409       if (duration != 0 || empty_edit) {
10410         /* edge case: empty edits with duration=zero are treated here.
10411          * (files should not have these anyway). */
10412
10413         /* add non scaled values so we don't cause roundoff errors */
10414         time += duration;
10415         stime = QTTIME_TO_GSTTIME (qtdemux, time);
10416         segment->duration = stime - segment->time;
10417       } else {
10418         /* zero duration does not imply media_start == media_stop
10419          * but, only specify media_start. The edit ends with the track. */
10420         stime = segment->duration = GST_CLOCK_TIME_NONE;
10421         /* Don't allow more edits after this one. */
10422         n_segments = segment_number + 1;
10423       }
10424       segment->stop_time = stime;
10425
10426       segment->trak_media_start = media_time;
10427       /* media_time expressed in stream timescale */
10428       if (!empty_edit) {
10429         segment->media_start = media_start;
10430         segment->media_stop = GST_CLOCK_TIME_IS_VALID (segment->duration)
10431             ? segment->media_start + segment->duration : GST_CLOCK_TIME_NONE;
10432         media_segments_count++;
10433       } else {
10434         segment->media_start = GST_CLOCK_TIME_NONE;
10435         segment->media_stop = GST_CLOCK_TIME_NONE;
10436       }
10437       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
10438
10439       if (rate_int <= 1) {
10440         /* 0 is not allowed, some programs write 1 instead of the floating point
10441          * value */
10442         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
10443             rate_int);
10444         segment->rate = 1;
10445       } else {
10446         segment->rate = rate_int / 65536.0;
10447       }
10448
10449       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
10450           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
10451           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
10452           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
10453           segment_number, GST_TIME_ARGS (segment->time),
10454           GST_TIME_ARGS (segment->duration),
10455           GST_TIME_ARGS (segment->media_start), media_time,
10456           GST_TIME_ARGS (segment->media_stop),
10457           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
10458           stream->timescale);
10459       if (segment->stop_time > qtdemux->segment.stop &&
10460           !qtdemux->upstream_format_is_time) {
10461         GST_WARNING_OBJECT (qtdemux, "Segment %d "
10462             " extends to %" GST_TIME_FORMAT
10463             " past the end of the declared movie duration %" GST_TIME_FORMAT
10464             " movie segment will be extended", segment_number,
10465             GST_TIME_ARGS (segment->stop_time),
10466             GST_TIME_ARGS (qtdemux->segment.stop));
10467         qtdemux->segment.stop = qtdemux->segment.duration = segment->stop_time;
10468       }
10469
10470       buffer += entry_size;
10471     }
10472     GST_DEBUG_OBJECT (qtdemux, "found %d segments", n_segments);
10473     stream->n_segments = n_segments;
10474     if (media_segments_count != 1)
10475       allow_pushbased_edts = FALSE;
10476   }
10477 done:
10478
10479   /* push based does not handle segments, so act accordingly here,
10480    * and warn if applicable */
10481   if (!qtdemux->pullbased && !allow_pushbased_edts) {
10482     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
10483     /* remove and use default one below, we stream like it anyway */
10484     g_free (stream->segments);
10485     stream->segments = NULL;
10486     stream->n_segments = 0;
10487   }
10488
10489   /* no segments, create one to play the complete trak */
10490   if (stream->n_segments == 0) {
10491     GstClockTime stream_duration =
10492         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
10493
10494     if (stream->segments == NULL)
10495       stream->segments = g_new (QtDemuxSegment, 1);
10496
10497     /* represent unknown our way */
10498     if (stream_duration == 0)
10499       stream_duration = GST_CLOCK_TIME_NONE;
10500
10501     stream->segments[0].time = 0;
10502     stream->segments[0].stop_time = stream_duration;
10503     stream->segments[0].duration = stream_duration;
10504     stream->segments[0].media_start = 0;
10505     stream->segments[0].media_stop = stream_duration;
10506     stream->segments[0].rate = 1.0;
10507     stream->segments[0].trak_media_start = 0;
10508
10509     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
10510         GST_TIME_ARGS (stream_duration));
10511     stream->n_segments = 1;
10512     stream->dummy_segment = TRUE;
10513   }
10514   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
10515
10516   return TRUE;
10517 }
10518
10519 /*
10520  * Parses the stsd atom of a svq3 trak looking for
10521  * the SMI and gama atoms.
10522  */
10523 static void
10524 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
10525     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
10526 {
10527   const guint8 *_gamma = NULL;
10528   GstBuffer *_seqh = NULL;
10529   const guint8 *stsd_data = stsd_entry_data;
10530   guint32 length = QT_UINT32 (stsd_data);
10531   guint16 version;
10532
10533   if (length < 32) {
10534     GST_WARNING_OBJECT (qtdemux, "stsd too short");
10535     goto end;
10536   }
10537
10538   stsd_data += 16;
10539   length -= 16;
10540   version = QT_UINT16 (stsd_data);
10541   if (version == 3) {
10542     if (length >= 70) {
10543       length -= 70;
10544       stsd_data += 70;
10545       while (length > 8) {
10546         guint32 fourcc, size;
10547         const guint8 *data;
10548         size = QT_UINT32 (stsd_data);
10549         fourcc = QT_FOURCC (stsd_data + 4);
10550         data = stsd_data + 8;
10551
10552         if (size == 0) {
10553           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
10554               "svq3 atom parsing");
10555           goto end;
10556         }
10557
10558         switch (fourcc) {
10559           case FOURCC_gama:{
10560             if (size == 12) {
10561               _gamma = data;
10562             } else {
10563               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
10564                   " for gama atom, expected 12", size);
10565             }
10566             break;
10567           }
10568           case FOURCC_SMI_:{
10569             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
10570               guint32 seqh_size;
10571               if (_seqh != NULL) {
10572                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
10573                     " found, ignoring");
10574               } else {
10575                 seqh_size = QT_UINT32 (data + 4);
10576                 if (seqh_size > 0) {
10577                   _seqh = gst_buffer_new_and_alloc (seqh_size);
10578                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
10579                 }
10580               }
10581             }
10582             break;
10583           }
10584           default:{
10585             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
10586                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
10587           }
10588         }
10589
10590         if (size <= length) {
10591           length -= size;
10592           stsd_data += size;
10593         }
10594       }
10595     } else {
10596       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
10597     }
10598   } else {
10599     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
10600         G_GUINT16_FORMAT, version);
10601     goto end;
10602   }
10603
10604 end:
10605   if (gamma) {
10606     *gamma = _gamma;
10607   }
10608   if (seqh) {
10609     *seqh = _seqh;
10610   } else if (_seqh) {
10611     gst_buffer_unref (_seqh);
10612   }
10613 }
10614
10615 static gchar *
10616 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
10617 {
10618   GNode *dinf;
10619   GstByteReader dref;
10620   gchar *uri = NULL;
10621
10622   /*
10623    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
10624    * atom that might contain a 'data' atom with the rtsp uri.
10625    * This case was reported in bug #597497, some info about
10626    * the hndl atom can be found in TN1195
10627    */
10628   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
10629   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
10630
10631   if (dinf) {
10632     guint32 dref_num_entries = 0;
10633     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
10634         gst_byte_reader_skip (&dref, 4) &&
10635         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
10636       gint i;
10637
10638       /* search dref entries for hndl atom */
10639       for (i = 0; i < dref_num_entries; i++) {
10640         guint32 size = 0, type;
10641         guint8 string_len = 0;
10642         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
10643             qt_atom_parser_get_fourcc (&dref, &type)) {
10644           if (type == FOURCC_hndl) {
10645             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
10646
10647             /* skip data reference handle bytes and the
10648              * following pascal string and some extra 4
10649              * bytes I have no idea what are */
10650             if (!gst_byte_reader_skip (&dref, 4) ||
10651                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
10652                 !gst_byte_reader_skip (&dref, string_len + 4)) {
10653               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
10654               break;
10655             }
10656
10657             /* iterate over the atoms to find the data atom */
10658             while (gst_byte_reader_get_remaining (&dref) >= 8) {
10659               guint32 atom_size;
10660               guint32 atom_type;
10661
10662               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
10663                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
10664                 if (atom_type == FOURCC_data) {
10665                   const guint8 *uri_aux = NULL;
10666
10667                   /* found the data atom that might contain the rtsp uri */
10668                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
10669                       "hndl atom, interpreting it as an URI");
10670                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
10671                           &uri_aux)) {
10672                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
10673                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
10674                     else
10675                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
10676                           "didn't contain a rtsp address");
10677                   } else {
10678                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
10679                         "atom contents");
10680                   }
10681                   break;
10682                 }
10683                 /* skipping to the next entry */
10684                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
10685                   break;
10686               } else {
10687                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
10688                     "atom header");
10689                 break;
10690               }
10691             }
10692             break;
10693           }
10694           /* skip to the next entry */
10695           if (!gst_byte_reader_skip (&dref, size - 8))
10696             break;
10697         } else {
10698           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
10699         }
10700       }
10701       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
10702     }
10703   }
10704   return uri;
10705 }
10706
10707 #define AMR_NB_ALL_MODES        0x81ff
10708 #define AMR_WB_ALL_MODES        0x83ff
10709 static guint
10710 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
10711 {
10712   /* The 'damr' atom is of the form:
10713    *
10714    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
10715    *    32 b       8 b          16 b           8 b                 8 b
10716    *
10717    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
10718    * represents the highest mode used in the stream (and thus the maximum
10719    * bitrate), with a couple of special cases as seen below.
10720    */
10721
10722   /* Map of frame type ID -> bitrate */
10723   static const guint nb_bitrates[] = {
10724     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
10725   };
10726   static const guint wb_bitrates[] = {
10727     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
10728   };
10729   GstMapInfo map;
10730   gsize max_mode;
10731   guint16 mode_set;
10732
10733   gst_buffer_map (buf, &map, GST_MAP_READ);
10734
10735   if (map.size != 0x11) {
10736     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
10737     goto bad_data;
10738   }
10739
10740   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
10741     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
10742         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
10743     goto bad_data;
10744   }
10745
10746   mode_set = QT_UINT16 (map.data + 13);
10747
10748   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
10749     max_mode = 7 + (wb ? 1 : 0);
10750   else
10751     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
10752     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
10753
10754   if (max_mode == -1) {
10755     GST_DEBUG ("No mode indication was found (mode set) = %x",
10756         (guint) mode_set);
10757     goto bad_data;
10758   }
10759
10760   gst_buffer_unmap (buf, &map);
10761   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
10762
10763 bad_data:
10764   gst_buffer_unmap (buf, &map);
10765   return 0;
10766 }
10767
10768 static gboolean
10769 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
10770     GstByteReader * reader, guint32 * matrix, const gchar * atom)
10771 {
10772   /*
10773    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
10774    * [0 1 2]
10775    * [3 4 5]
10776    * [6 7 8]
10777    */
10778
10779   if (gst_byte_reader_get_remaining (reader) < 36)
10780     return FALSE;
10781
10782   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
10783   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
10784   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
10785   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
10786   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
10787   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
10788   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
10789   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
10790   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
10791
10792   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
10793   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
10794       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
10795       matrix[2] & 0xFF);
10796   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
10797       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
10798       matrix[5] & 0xFF);
10799   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
10800       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
10801       matrix[8] & 0xFF);
10802
10803   return TRUE;
10804 }
10805
10806 static void
10807 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
10808     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
10809 {
10810
10811 /* [a b c]
10812  * [d e f]
10813  * [g h i]
10814  *
10815  * This macro will only compare value abdegh, it expects cfi to have already
10816  * been checked
10817  */
10818 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10819                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
10820
10821   /* only handle the cases where the last column has standard values */
10822   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10823     const gchar *rotation_tag = NULL;
10824
10825     /* no rotation needed */
10826     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10827       /* NOP */
10828     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10829       rotation_tag = "rotate-90";
10830     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10831       rotation_tag = "rotate-180";
10832     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10833       rotation_tag = "rotate-270";
10834     } else {
10835       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10836     }
10837
10838     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10839         rotation_tag);
10840     if (rotation_tag != NULL) {
10841       if (*taglist == NULL)
10842         *taglist = gst_tag_list_new_empty ();
10843       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10844           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10845     }
10846   } else {
10847     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10848   }
10849 }
10850
10851 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10852  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10853  * Common Encryption (cenc), the function will also parse the tenc box (defined
10854  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10855  * (typically an enc[v|a|t|s] sample entry); the function will set
10856  * @original_fmt to the fourcc of the original unencrypted stream format.
10857  * Returns TRUE if successful; FALSE otherwise. */
10858 static gboolean
10859 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10860     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10861 {
10862   GNode *sinf;
10863   GNode *frma;
10864   GNode *schm;
10865   GNode *schi;
10866   QtDemuxCencSampleSetInfo *info;
10867   GNode *tenc;
10868   const guint8 *tenc_data;
10869
10870   g_return_val_if_fail (qtdemux != NULL, FALSE);
10871   g_return_val_if_fail (stream != NULL, FALSE);
10872   g_return_val_if_fail (container != NULL, FALSE);
10873   g_return_val_if_fail (original_fmt != NULL, FALSE);
10874
10875   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10876   if (G_UNLIKELY (!sinf)) {
10877     if (stream->protection_scheme_type == FOURCC_cenc) {
10878       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10879           "mandatory for Common Encryption");
10880       return FALSE;
10881     }
10882     return TRUE;
10883   }
10884
10885   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10886   if (G_UNLIKELY (!frma)) {
10887     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10888     return FALSE;
10889   }
10890
10891   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10892   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10893       GST_FOURCC_ARGS (*original_fmt));
10894
10895   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10896   if (!schm) {
10897     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10898     return FALSE;
10899   }
10900   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10901   stream->protection_scheme_version =
10902       QT_UINT32 ((const guint8 *) schm->data + 16);
10903
10904   GST_DEBUG_OBJECT (qtdemux,
10905       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10906       "protection_scheme_version: %#010x",
10907       GST_FOURCC_ARGS (stream->protection_scheme_type),
10908       stream->protection_scheme_version);
10909
10910   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10911   if (!schi) {
10912     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10913     return FALSE;
10914   }
10915   if (stream->protection_scheme_type != FOURCC_cenc &&
10916       stream->protection_scheme_type != FOURCC_piff) {
10917     GST_ERROR_OBJECT (qtdemux,
10918         "Invalid protection_scheme_type: %" GST_FOURCC_FORMAT,
10919         GST_FOURCC_ARGS (stream->protection_scheme_type));
10920     return FALSE;
10921   }
10922
10923   if (G_UNLIKELY (!stream->protection_scheme_info))
10924     stream->protection_scheme_info =
10925         g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10926
10927   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10928
10929   if (stream->protection_scheme_type == FOURCC_cenc) {
10930     guint32 is_encrypted;
10931     guint8 iv_size;
10932     const guint8 *default_kid;
10933
10934     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10935     if (!tenc) {
10936       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10937           "which is mandatory for Common Encryption");
10938       return FALSE;
10939     }
10940     tenc_data = (const guint8 *) tenc->data + 12;
10941     is_encrypted = QT_UINT24 (tenc_data);
10942     iv_size = QT_UINT8 (tenc_data + 3);
10943     default_kid = (tenc_data + 4);
10944     qtdemux_update_default_sample_encryption_settings (qtdemux, info,
10945         is_encrypted, iv_size, default_kid);
10946   } else if (stream->protection_scheme_type == FOURCC_piff) {
10947     GstByteReader br;
10948     static const guint8 piff_track_encryption_uuid[] = {
10949       0x89, 0x74, 0xdb, 0xce, 0x7b, 0xe7, 0x4c, 0x51,
10950       0x84, 0xf9, 0x71, 0x48, 0xf9, 0x88, 0x25, 0x54
10951     };
10952
10953     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_uuid);
10954     if (!tenc) {
10955       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10956           "which is mandatory for Common Encryption");
10957       return FALSE;
10958     }
10959
10960     tenc_data = (const guint8 *) tenc->data + 8;
10961     if (memcmp (tenc_data, piff_track_encryption_uuid, 16) != 0) {
10962       gchar *box_uuid = qtdemux_uuid_bytes_to_string (tenc_data);
10963       GST_ERROR_OBJECT (qtdemux,
10964           "Unsupported track encryption box with uuid: %s", box_uuid);
10965       g_free (box_uuid);
10966       return FALSE;
10967     }
10968     tenc_data = (const guint8 *) tenc->data + 16 + 12;
10969     gst_byte_reader_init (&br, tenc_data, 20);
10970     if (!qtdemux_update_default_piff_encryption_settings (qtdemux, info, &br)) {
10971       GST_ERROR_OBJECT (qtdemux, "PIFF track box parsing error");
10972       return FALSE;
10973     }
10974     stream->protection_scheme_type = FOURCC_cenc;
10975   }
10976
10977   return TRUE;
10978 }
10979
10980 static gint
10981 qtdemux_track_id_compare_func (QtDemuxStream ** stream1,
10982     QtDemuxStream ** stream2)
10983 {
10984   return (gint) (*stream1)->track_id - (gint) (*stream2)->track_id;
10985 }
10986
10987 /* parse the traks.
10988  * With each track we associate a new QtDemuxStream that contains all the info
10989  * about the trak.
10990  * traks that do not decode to something (like strm traks) will not have a pad.
10991  */
10992 static gboolean
10993 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10994 {
10995   GstByteReader tkhd;
10996   int offset;
10997   GNode *mdia;
10998   GNode *mdhd;
10999   GNode *hdlr;
11000   GNode *minf;
11001   GNode *stbl;
11002   GNode *stsd;
11003   GNode *mp4a;
11004   GNode *mp4v;
11005   GNode *esds;
11006   GNode *tref;
11007   GNode *udta;
11008   GNode *svmi;
11009
11010   QtDemuxStream *stream = NULL;
11011   const guint8 *stsd_data;
11012   const guint8 *stsd_entry_data;
11013   guint remaining_stsd_len;
11014   guint stsd_entry_count;
11015   guint stsd_index;
11016   guint16 lang_code;            /* quicktime lang code or packed iso code */
11017   guint32 version;
11018   guint32 tkhd_flags = 0;
11019   guint8 tkhd_version = 0;
11020   guint32 w = 0, h = 0;
11021   guint value_size, stsd_len, len;
11022   guint32 track_id;
11023   guint32 dummy;
11024
11025   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
11026
11027   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
11028       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
11029       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
11030     goto corrupt_file;
11031
11032   /* pick between 64 or 32 bits */
11033   value_size = tkhd_version == 1 ? 8 : 4;
11034   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
11035       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
11036     goto corrupt_file;
11037
11038   /* Check if current moov has duplicated track_id */
11039   if (qtdemux_find_stream (qtdemux, track_id))
11040     goto existing_stream;
11041
11042   stream = _create_stream (qtdemux, track_id);
11043   stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
11044
11045 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
11046   if (!gst_byte_reader_skip (&tkhd, 4))
11047     goto corrupt_file;
11048
11049   if (tkhd_version == 1) {
11050     if (!gst_byte_reader_get_uint64_be (&tkhd, &stream->tkhd_duration))
11051       goto corrupt_file;
11052   } else {
11053     guint32 dur = 0;
11054     if (!gst_byte_reader_get_uint32_be (&tkhd, &dur))
11055       goto corrupt_file;
11056     stream->tkhd_duration = dur;
11057   }
11058   GST_INFO_OBJECT (qtdemux, "tkhd duration: %" G_GUINT64_FORMAT,
11059       stream->tkhd_duration);
11060 #endif
11061   /* need defaults for fragments */
11062   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
11063
11064   if ((tkhd_flags & 1) == 0)
11065     stream->disabled = TRUE;
11066
11067   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
11068       tkhd_version, tkhd_flags, stream->track_id);
11069
11070   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
11071     goto corrupt_file;
11072
11073   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
11074     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
11075     if (qtdemux->major_brand != FOURCC_mjp2 ||
11076         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
11077       goto corrupt_file;
11078   }
11079
11080   len = QT_UINT32 ((guint8 *) mdhd->data);
11081   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
11082   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
11083   if (version == 0x01000000) {
11084     if (len < 42)
11085       goto corrupt_file;
11086     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
11087     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
11088     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 40);
11089   } else {
11090     if (len < 30)
11091       goto corrupt_file;
11092     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
11093     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
11094     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
11095   }
11096
11097   if (lang_code < 0x400) {
11098     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
11099   } else if (lang_code == 0x7fff) {
11100     stream->lang_id[0] = 0;     /* unspecified */
11101   } else {
11102     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
11103     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
11104     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
11105     stream->lang_id[3] = 0;
11106   }
11107
11108   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
11109       stream->timescale);
11110   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
11111       stream->duration);
11112   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
11113       lang_code, stream->lang_id);
11114
11115   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
11116     goto corrupt_file;
11117
11118   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
11119     /* chapters track reference */
11120     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
11121     if (chap) {
11122       gsize length = GST_READ_UINT32_BE (chap->data);
11123       if (qtdemux->chapters_track_id)
11124         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
11125
11126       if (length >= 12) {
11127         qtdemux->chapters_track_id =
11128             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
11129       }
11130     }
11131   }
11132
11133   /* fragmented files may have bogus duration in moov */
11134   if (!qtdemux->fragmented &&
11135       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
11136     guint64 tdur1, tdur2;
11137
11138     /* don't overflow */
11139     tdur1 = stream->timescale * (guint64) qtdemux->duration;
11140     tdur2 = qtdemux->timescale * (guint64) stream->duration;
11141
11142     /* HACK:
11143      * some of those trailers, nowadays, have prologue images that are
11144      * themselves video tracks as well. I haven't really found a way to
11145      * identify those yet, except for just looking at their duration. */
11146     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
11147       GST_WARNING_OBJECT (qtdemux,
11148           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
11149           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
11150           "found, assuming preview image or something; skipping track",
11151           stream->duration, stream->timescale, qtdemux->duration,
11152           qtdemux->timescale);
11153       gst_qtdemux_stream_unref (stream);
11154       return TRUE;
11155     }
11156   }
11157
11158   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
11159     goto corrupt_file;
11160
11161   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
11162       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
11163
11164   len = QT_UINT32 ((guint8 *) hdlr->data);
11165   if (len >= 20)
11166     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
11167   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
11168       GST_FOURCC_ARGS (stream->subtype));
11169
11170   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
11171     goto corrupt_file;
11172
11173   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
11174     goto corrupt_file;
11175
11176   /*parse svmi header if existing */
11177   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
11178   if (svmi) {
11179     len = QT_UINT32 ((guint8 *) svmi->data);
11180     version = QT_UINT32 ((guint8 *) svmi->data + 8);
11181     if (!version) {
11182       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
11183       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
11184       guint8 frame_type, frame_layout;
11185
11186       /* MPEG-A stereo video */
11187       if (qtdemux->major_brand == FOURCC_ss02)
11188         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
11189
11190       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
11191       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
11192       switch (frame_type) {
11193         case 0:
11194           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
11195           break;
11196         case 1:
11197           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
11198           break;
11199         case 2:
11200           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
11201           break;
11202         case 3:
11203           /* mode 3 is primary/secondary view sequence, ie
11204            * left/right views in separate tracks. See section 7.2
11205            * of ISO/IEC 23000-11:2009 */
11206           GST_FIXME_OBJECT (qtdemux,
11207               "Implement stereo video in separate streams");
11208       }
11209
11210       if ((frame_layout & 0x1) == 0)
11211         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
11212
11213       GST_LOG_OBJECT (qtdemux,
11214           "StereoVideo: composition type: %u, is_left_first: %u",
11215           frame_type, frame_layout);
11216       stream->multiview_mode = mode;
11217       stream->multiview_flags = flags;
11218     }
11219   }
11220
11221   /* parse rest of tkhd */
11222   if (stream->subtype == FOURCC_vide) {
11223     guint32 matrix[9];
11224
11225     /* version 1 uses some 64-bit ints */
11226 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
11227     if (!gst_byte_reader_skip (&tkhd, 16))
11228 #else
11229     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
11230 #endif
11231       goto corrupt_file;
11232
11233     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
11234       goto corrupt_file;
11235
11236     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
11237         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
11238       goto corrupt_file;
11239
11240     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
11241         &stream->stream_tags);
11242   }
11243
11244   /* parse stsd */
11245   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
11246     goto corrupt_file;
11247   stsd_data = (const guint8 *) stsd->data;
11248
11249   /* stsd should at least have one entry */
11250   stsd_len = QT_UINT32 (stsd_data);
11251   if (stsd_len < 24) {
11252     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
11253     if (stream->subtype == FOURCC_vivo) {
11254       gst_qtdemux_stream_unref (stream);
11255       return TRUE;
11256     } else {
11257       goto corrupt_file;
11258     }
11259   }
11260
11261   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
11262   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
11263   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
11264   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
11265
11266   stsd_entry_data = stsd_data + 16;
11267   remaining_stsd_len = stsd_len - 16;
11268   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
11269     guint32 fourcc;
11270     gchar *codec = NULL;
11271     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
11272
11273     /* and that entry should fit within stsd */
11274     len = QT_UINT32 (stsd_entry_data);
11275     if (len > remaining_stsd_len)
11276       goto corrupt_file;
11277
11278     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
11279     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
11280         GST_FOURCC_ARGS (entry->fourcc));
11281     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
11282
11283     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
11284       goto error_encrypted;
11285
11286     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
11287       /* FIXME this looks wrong, there might be multiple children
11288        * with the same type */
11289       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
11290       stream->protected = TRUE;
11291       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
11292         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
11293     }
11294
11295     if (stream->subtype == FOURCC_vide) {
11296       GNode *colr;
11297       GNode *fiel;
11298       GNode *pasp;
11299       gboolean gray;
11300       gint depth, palette_size, palette_count;
11301       guint32 *palette_data = NULL;
11302
11303       entry->sampled = TRUE;
11304
11305       stream->display_width = w >> 16;
11306       stream->display_height = h >> 16;
11307
11308       offset = 16;
11309       if (len < 86)             /* TODO verify */
11310         goto corrupt_file;
11311
11312       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
11313       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
11314       entry->fps_n = 0;         /* this is filled in later */
11315       entry->fps_d = 0;         /* this is filled in later */
11316       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
11317       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
11318
11319       /* if color_table_id is 0, ctab atom must follow; however some files
11320        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
11321        * if color table is not present we'll correct the value */
11322       if (entry->color_table_id == 0 &&
11323           (len < 90
11324               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
11325         entry->color_table_id = -1;
11326       }
11327
11328       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
11329           entry->width, entry->height, entry->bits_per_sample,
11330           entry->color_table_id);
11331
11332       depth = entry->bits_per_sample;
11333
11334       /* more than 32 bits means grayscale */
11335       gray = (depth > 32);
11336       /* low 32 bits specify the depth  */
11337       depth &= 0x1F;
11338
11339       /* different number of palette entries is determined by depth. */
11340       palette_count = 0;
11341       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
11342         palette_count = (1 << depth);
11343       palette_size = palette_count * 4;
11344
11345       if (entry->color_table_id) {
11346         switch (palette_count) {
11347           case 0:
11348             break;
11349           case 2:
11350             palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
11351             break;
11352           case 4:
11353             palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
11354             break;
11355           case 16:
11356             if (gray)
11357               palette_data =
11358                   g_memdup (ff_qt_grayscale_palette_16, palette_size);
11359             else
11360               palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
11361             break;
11362           case 256:
11363             if (gray)
11364               palette_data =
11365                   g_memdup (ff_qt_grayscale_palette_256, palette_size);
11366             else
11367               palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
11368             break;
11369           default:
11370             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
11371                 (_("The video in this file might not play correctly.")),
11372                 ("unsupported palette depth %d", depth));
11373             break;
11374         }
11375       } else {
11376         gint i, j, start, end;
11377
11378         if (len < 94)
11379           goto corrupt_file;
11380
11381         /* read table */
11382         start = QT_UINT32 (stsd_entry_data + offset + 70);
11383         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
11384         end = QT_UINT16 (stsd_entry_data + offset + 76);
11385
11386         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
11387             start, end, palette_count);
11388
11389         if (end > 255)
11390           end = 255;
11391         if (start > end)
11392           start = end;
11393
11394         if (len < 94 + (end - start) * 8)
11395           goto corrupt_file;
11396
11397         /* palette is always the same size */
11398         palette_data = g_malloc0 (256 * 4);
11399         palette_size = 256 * 4;
11400
11401         for (j = 0, i = start; i <= end; j++, i++) {
11402           guint32 a, r, g, b;
11403
11404           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
11405           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
11406           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
11407           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
11408
11409           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
11410               (g & 0xff00) | (b >> 8);
11411         }
11412       }
11413
11414       if (entry->caps)
11415         gst_caps_unref (entry->caps);
11416
11417       entry->caps =
11418           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
11419           &codec);
11420       if (G_UNLIKELY (!entry->caps)) {
11421         g_free (palette_data);
11422         goto unknown_stream;
11423       }
11424
11425       if (codec) {
11426         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11427             GST_TAG_VIDEO_CODEC, codec, NULL);
11428         g_free (codec);
11429         codec = NULL;
11430       }
11431
11432       if (palette_data) {
11433         GstStructure *s;
11434
11435         if (entry->rgb8_palette)
11436           gst_memory_unref (entry->rgb8_palette);
11437         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
11438             palette_data, palette_size, 0, palette_size, palette_data, g_free);
11439
11440         s = gst_caps_get_structure (entry->caps, 0);
11441
11442         /* non-raw video has a palette_data property. raw video has the palette as
11443          * an extra plane that we append to the output buffers before we push
11444          * them*/
11445         if (!gst_structure_has_name (s, "video/x-raw")) {
11446           GstBuffer *palette;
11447
11448           palette = gst_buffer_new ();
11449           gst_buffer_append_memory (palette, entry->rgb8_palette);
11450           entry->rgb8_palette = NULL;
11451
11452           gst_caps_set_simple (entry->caps, "palette_data",
11453               GST_TYPE_BUFFER, palette, NULL);
11454           gst_buffer_unref (palette);
11455         }
11456       } else if (palette_count != 0) {
11457         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
11458             (NULL), ("Unsupported palette depth %d", depth));
11459       }
11460
11461       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
11462           QT_UINT16 (stsd_entry_data + offset + 32));
11463
11464       esds = NULL;
11465       pasp = NULL;
11466       colr = NULL;
11467       fiel = NULL;
11468       /* pick 'the' stsd child */
11469       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11470       // We should skip parsing the stsd for non-protected streams if
11471       // the entry doesn't match the fourcc, since they don't change
11472       // format. However, for protected streams we can have partial
11473       // encryption, where parts of the stream are encrypted and parts
11474       // not. For both parts of such streams, we should ensure the
11475       // esds overrides are parsed for both from the stsd.
11476       if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
11477         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv)
11478           mp4v = NULL;
11479         else if (!stream->protected)
11480           mp4v = NULL;
11481       }
11482
11483       if (mp4v) {
11484         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
11485         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
11486         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
11487         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
11488       }
11489
11490       if (pasp) {
11491         const guint8 *pasp_data = (const guint8 *) pasp->data;
11492         gint len = QT_UINT32 (pasp_data);
11493
11494         if (len == 16) {
11495           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
11496           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
11497         } else {
11498           CUR_STREAM (stream)->par_w = 0;
11499           CUR_STREAM (stream)->par_h = 0;
11500         }
11501       } else {
11502         CUR_STREAM (stream)->par_w = 0;
11503         CUR_STREAM (stream)->par_h = 0;
11504       }
11505
11506       if (fiel) {
11507         const guint8 *fiel_data = (const guint8 *) fiel->data;
11508         gint len = QT_UINT32 (fiel_data);
11509
11510         if (len == 10) {
11511           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
11512           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
11513         }
11514       }
11515
11516       if (colr) {
11517         const guint8 *colr_data = (const guint8 *) colr->data;
11518         gint len = QT_UINT32 (colr_data);
11519
11520         if (len == 19 || len == 18) {
11521           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
11522
11523           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
11524             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
11525             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
11526             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
11527             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
11528
11529             switch (primaries) {
11530               case 1:
11531                 CUR_STREAM (stream)->colorimetry.primaries =
11532                     GST_VIDEO_COLOR_PRIMARIES_BT709;
11533                 break;
11534               case 5:
11535                 CUR_STREAM (stream)->colorimetry.primaries =
11536                     GST_VIDEO_COLOR_PRIMARIES_BT470BG;
11537                 break;
11538               case 6:
11539                 CUR_STREAM (stream)->colorimetry.primaries =
11540                     GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
11541                 break;
11542               case 9:
11543                 CUR_STREAM (stream)->colorimetry.primaries =
11544                     GST_VIDEO_COLOR_PRIMARIES_BT2020;
11545                 break;
11546               default:
11547                 break;
11548             }
11549
11550             switch (transfer_function) {
11551               case 1:
11552                 CUR_STREAM (stream)->colorimetry.transfer =
11553                     GST_VIDEO_TRANSFER_BT709;
11554                 break;
11555               case 7:
11556                 CUR_STREAM (stream)->colorimetry.transfer =
11557                     GST_VIDEO_TRANSFER_SMPTE240M;
11558                 break;
11559               default:
11560                 break;
11561             }
11562
11563             switch (matrix) {
11564               case 1:
11565                 CUR_STREAM (stream)->colorimetry.matrix =
11566                     GST_VIDEO_COLOR_MATRIX_BT709;
11567                 break;
11568               case 6:
11569                 CUR_STREAM (stream)->colorimetry.matrix =
11570                     GST_VIDEO_COLOR_MATRIX_BT601;
11571                 break;
11572               case 7:
11573                 CUR_STREAM (stream)->colorimetry.matrix =
11574                     GST_VIDEO_COLOR_MATRIX_SMPTE240M;
11575                 break;
11576               case 9:
11577                 CUR_STREAM (stream)->colorimetry.matrix =
11578                     GST_VIDEO_COLOR_MATRIX_BT2020;
11579                 break;
11580               default:
11581                 break;
11582             }
11583
11584             CUR_STREAM (stream)->colorimetry.range =
11585                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
11586                 GST_VIDEO_COLOR_RANGE_16_235;
11587           } else {
11588             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
11589           }
11590         } else {
11591           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
11592         }
11593       }
11594
11595       if (esds) {
11596         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11597             stream->stream_tags);
11598       } else {
11599         switch (fourcc) {
11600           case FOURCC_H264:
11601           case FOURCC_avc1:
11602           case FOURCC_avc3:
11603           {
11604             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11605             const guint8 *avc_data = stsd_entry_data + 0x56;
11606
11607             /* find avcC */
11608             while (len >= 0x8) {
11609               gint size;
11610
11611               if (QT_UINT32 (avc_data) <= len)
11612                 size = QT_UINT32 (avc_data) - 0x8;
11613               else
11614                 size = len - 0x8;
11615
11616               if (size < 1)
11617                 /* No real data, so break out */
11618                 break;
11619
11620               switch (QT_FOURCC (avc_data + 0x4)) {
11621                 case FOURCC_avcC:
11622                 {
11623                   /* parse, if found */
11624                   GstBuffer *buf;
11625
11626                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
11627
11628                   /* First 4 bytes are the length of the atom, the next 4 bytes
11629                    * are the fourcc, the next 1 byte is the version, and the
11630                    * subsequent bytes are profile_tier_level structure like data. */
11631                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
11632                       avc_data + 8 + 1, size - 1);
11633                   buf = gst_buffer_new_and_alloc (size);
11634                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
11635                   gst_caps_set_simple (entry->caps,
11636                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11637                   gst_buffer_unref (buf);
11638
11639                   break;
11640                 }
11641                 case FOURCC_strf:
11642                 {
11643                   GstBuffer *buf;
11644
11645                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
11646
11647                   /* First 4 bytes are the length of the atom, the next 4 bytes
11648                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
11649                    * next 1 byte is the version, and the
11650                    * subsequent bytes are sequence parameter set like data. */
11651
11652                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
11653                   if (size > 1) {
11654                     gst_codec_utils_h264_caps_set_level_and_profile
11655                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
11656
11657                     buf = gst_buffer_new_and_alloc (size);
11658                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
11659                     gst_caps_set_simple (entry->caps,
11660                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
11661                     gst_buffer_unref (buf);
11662                   }
11663                   break;
11664                 }
11665                 case FOURCC_btrt:
11666                 {
11667                   guint avg_bitrate, max_bitrate;
11668
11669                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
11670                   if (size < 12)
11671                     break;
11672
11673                   max_bitrate = QT_UINT32 (avc_data + 0xc);
11674                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
11675
11676                   if (!max_bitrate && !avg_bitrate)
11677                     break;
11678
11679                   /* Some muxers seem to swap the average and maximum bitrates
11680                    * (I'm looking at you, YouTube), so we swap for sanity. */
11681                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
11682                     guint temp = avg_bitrate;
11683
11684                     avg_bitrate = max_bitrate;
11685                     max_bitrate = temp;
11686                   }
11687
11688                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
11689                     gst_tag_list_add (stream->stream_tags,
11690                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
11691                         max_bitrate, NULL);
11692                   }
11693                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
11694                     gst_tag_list_add (stream->stream_tags,
11695                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
11696                         NULL);
11697                   }
11698
11699                   break;
11700                 }
11701
11702                 default:
11703                   break;
11704               }
11705
11706               len -= size + 8;
11707               avc_data += size + 8;
11708             }
11709
11710             break;
11711           }
11712           case FOURCC_H265:
11713           case FOURCC_hvc1:
11714           case FOURCC_hev1:
11715           {
11716             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11717             const guint8 *hevc_data = stsd_entry_data + 0x56;
11718
11719             /* find hevc */
11720             while (len >= 0x8) {
11721               gint size;
11722
11723               if (QT_UINT32 (hevc_data) <= len)
11724                 size = QT_UINT32 (hevc_data) - 0x8;
11725               else
11726                 size = len - 0x8;
11727
11728               if (size < 1)
11729                 /* No real data, so break out */
11730                 break;
11731
11732               switch (QT_FOURCC (hevc_data + 0x4)) {
11733                 case FOURCC_hvcC:
11734                 {
11735                   /* parse, if found */
11736                   GstBuffer *buf;
11737
11738                   GST_DEBUG_OBJECT (qtdemux, "found hvcC codec_data in stsd");
11739
11740                   /* First 4 bytes are the length of the atom, the next 4 bytes
11741                    * are the fourcc, the next 1 byte is the version, and the
11742                    * subsequent bytes are sequence parameter set like data. */
11743                   gst_codec_utils_h265_caps_set_level_tier_and_profile
11744                       (entry->caps, hevc_data + 8 + 1, size - 1);
11745
11746                   buf = gst_buffer_new_and_alloc (size);
11747                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
11748                   gst_caps_set_simple (entry->caps,
11749                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11750                   gst_buffer_unref (buf);
11751                   break;
11752                 }
11753                 default:
11754                   break;
11755               }
11756               len -= size + 8;
11757               hevc_data += size + 8;
11758             }
11759             break;
11760           }
11761           case FOURCC_mp4v:
11762           case FOURCC_MP4V:
11763           case FOURCC_fmp4:
11764           case FOURCC_FMP4:
11765           case FOURCC_xvid:
11766           case FOURCC_XVID:
11767           {
11768             GNode *glbl;
11769
11770             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
11771                 GST_FOURCC_ARGS (fourcc));
11772
11773             /* codec data might be in glbl extension atom */
11774             glbl = mp4v ?
11775                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
11776             if (glbl) {
11777               guint8 *data;
11778               GstBuffer *buf;
11779               gint len;
11780
11781               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
11782               data = glbl->data;
11783               len = QT_UINT32 (data);
11784               if (len > 0x8) {
11785                 len -= 0x8;
11786                 buf = gst_buffer_new_and_alloc (len);
11787                 gst_buffer_fill (buf, 0, data + 8, len);
11788                 gst_caps_set_simple (entry->caps,
11789                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11790                 gst_buffer_unref (buf);
11791               }
11792             }
11793             break;
11794           }
11795           case FOURCC_mjp2:
11796           {
11797             /* see annex I of the jpeg2000 spec */
11798             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
11799             const guint8 *data;
11800             const gchar *colorspace = NULL;
11801             gint ncomp = 0;
11802             guint32 ncomp_map = 0;
11803             gint32 *comp_map = NULL;
11804             guint32 nchan_def = 0;
11805             gint32 *chan_def = NULL;
11806
11807             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
11808             /* some required atoms */
11809             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11810             if (!mjp2)
11811               break;
11812             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
11813             if (!jp2h)
11814               break;
11815
11816             /* number of components; redundant with info in codestream, but useful
11817                to a muxer */
11818             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
11819             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
11820               break;
11821             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
11822
11823             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
11824             if (!colr)
11825               break;
11826             GST_DEBUG_OBJECT (qtdemux, "found colr");
11827             /* extract colour space info */
11828             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
11829               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
11830                 case 16:
11831                   colorspace = "sRGB";
11832                   break;
11833                 case 17:
11834                   colorspace = "GRAY";
11835                   break;
11836                 case 18:
11837                   colorspace = "sYUV";
11838                   break;
11839                 default:
11840                   colorspace = NULL;
11841                   break;
11842               }
11843             }
11844             if (!colorspace)
11845               /* colr is required, and only values 16, 17, and 18 are specified,
11846                  so error if we have no colorspace */
11847               break;
11848
11849             /* extract component mapping */
11850             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
11851             if (cmap) {
11852               guint32 cmap_len = 0;
11853               int i;
11854               cmap_len = QT_UINT32 (cmap->data);
11855               if (cmap_len >= 8) {
11856                 /* normal box, subtract off header */
11857                 cmap_len -= 8;
11858                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11859                 if (cmap_len % 4 == 0) {
11860                   ncomp_map = (cmap_len / 4);
11861                   comp_map = g_new0 (gint32, ncomp_map);
11862                   for (i = 0; i < ncomp_map; i++) {
11863                     guint16 cmp;
11864                     guint8 mtyp, pcol;
11865                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11866                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11867                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11868                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11869                   }
11870                 }
11871               }
11872             }
11873             /* extract channel definitions */
11874             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11875             if (cdef) {
11876               guint32 cdef_len = 0;
11877               int i;
11878               cdef_len = QT_UINT32 (cdef->data);
11879               if (cdef_len >= 10) {
11880                 /* normal box, subtract off header and len */
11881                 cdef_len -= 10;
11882                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11883                 if (cdef_len % 6 == 0) {
11884                   nchan_def = (cdef_len / 6);
11885                   chan_def = g_new0 (gint32, nchan_def);
11886                   for (i = 0; i < nchan_def; i++)
11887                     chan_def[i] = -1;
11888                   for (i = 0; i < nchan_def; i++) {
11889                     guint16 cn, typ, asoc;
11890                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11891                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11892                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11893                     if (cn < nchan_def) {
11894                       switch (typ) {
11895                         case 0:
11896                           chan_def[cn] = asoc;
11897                           break;
11898                         case 1:
11899                           chan_def[cn] = 0;     /* alpha */
11900                           break;
11901                         default:
11902                           chan_def[cn] = -typ;
11903                       }
11904                     }
11905                   }
11906                 }
11907               }
11908             }
11909
11910             gst_caps_set_simple (entry->caps,
11911                 "num-components", G_TYPE_INT, ncomp, NULL);
11912             gst_caps_set_simple (entry->caps,
11913                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11914
11915             if (comp_map) {
11916               GValue arr = { 0, };
11917               GValue elt = { 0, };
11918               int i;
11919               g_value_init (&arr, GST_TYPE_ARRAY);
11920               g_value_init (&elt, G_TYPE_INT);
11921               for (i = 0; i < ncomp_map; i++) {
11922                 g_value_set_int (&elt, comp_map[i]);
11923                 gst_value_array_append_value (&arr, &elt);
11924               }
11925               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11926                   "component-map", &arr);
11927               g_value_unset (&elt);
11928               g_value_unset (&arr);
11929               g_free (comp_map);
11930             }
11931
11932             if (chan_def) {
11933               GValue arr = { 0, };
11934               GValue elt = { 0, };
11935               int i;
11936               g_value_init (&arr, GST_TYPE_ARRAY);
11937               g_value_init (&elt, G_TYPE_INT);
11938               for (i = 0; i < nchan_def; i++) {
11939                 g_value_set_int (&elt, chan_def[i]);
11940                 gst_value_array_append_value (&arr, &elt);
11941               }
11942               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11943                   "channel-definitions", &arr);
11944               g_value_unset (&elt);
11945               g_value_unset (&arr);
11946               g_free (chan_def);
11947             }
11948
11949             /* some optional atoms */
11950             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11951             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11952
11953             /* indicate possible fields in caps */
11954             if (field) {
11955               data = (guint8 *) field->data + 8;
11956               if (*data != 1)
11957                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11958                     (gint) * data, NULL);
11959             }
11960             /* add codec_data if provided */
11961             if (prefix) {
11962               GstBuffer *buf;
11963               gint len;
11964
11965               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11966               data = prefix->data;
11967               len = QT_UINT32 (data);
11968               if (len > 0x8) {
11969                 len -= 0x8;
11970                 buf = gst_buffer_new_and_alloc (len);
11971                 gst_buffer_fill (buf, 0, data + 8, len);
11972                 gst_caps_set_simple (entry->caps,
11973                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11974                 gst_buffer_unref (buf);
11975               }
11976             }
11977             break;
11978           }
11979           case FOURCC_SVQ3:
11980           case FOURCC_VP31:
11981           {
11982             GstBuffer *buf;
11983             GstBuffer *seqh = NULL;
11984             const guint8 *gamma_data = NULL;
11985             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11986
11987             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11988                 &seqh);
11989             if (gamma_data) {
11990               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11991                   QT_FP32 (gamma_data), NULL);
11992             }
11993             if (seqh) {
11994               /* sorry for the bad name, but we don't know what this is, other
11995                * than its own fourcc */
11996               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11997                   NULL);
11998               gst_buffer_unref (seqh);
11999             }
12000
12001             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
12002             buf = gst_buffer_new_and_alloc (len);
12003             gst_buffer_fill (buf, 0, stsd_data, len);
12004             gst_caps_set_simple (entry->caps,
12005                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12006             gst_buffer_unref (buf);
12007             break;
12008           }
12009           case FOURCC_jpeg:
12010           {
12011             /* https://developer.apple.com/standards/qtff-2001.pdf,
12012              * page 92, "Video Sample Description", under table 3.1 */
12013             GstByteReader br;
12014
12015             const gint compressor_offset =
12016                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
12017             const gint min_size = compressor_offset + 32 + 2 + 2;
12018             GNode *jpeg;
12019             guint32 len;
12020             guint16 color_table_id = 0;
12021             gboolean ok;
12022
12023             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
12024
12025             /* recover information on interlaced/progressive */
12026             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
12027             if (!jpeg)
12028               break;
12029
12030             len = QT_UINT32 (jpeg->data);
12031             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
12032                 min_size);
12033             if (len >= min_size) {
12034               gst_byte_reader_init (&br, jpeg->data, len);
12035
12036               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
12037               gst_byte_reader_get_uint16_le (&br, &color_table_id);
12038               if (color_table_id != 0) {
12039                 /* the spec says there can be concatenated chunks in the data, and we want
12040                  * to find one called field. Walk through them. */
12041                 gint offset = min_size;
12042                 while (offset + 8 < len) {
12043                   guint32 size = 0, tag;
12044                   ok = gst_byte_reader_get_uint32_le (&br, &size);
12045                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
12046                   if (!ok || size < 8) {
12047                     GST_WARNING_OBJECT (qtdemux,
12048                         "Failed to walk optional chunk list");
12049                     break;
12050                   }
12051                   GST_DEBUG_OBJECT (qtdemux,
12052                       "Found optional %4.4s chunk, size %u",
12053                       (const char *) &tag, size);
12054                   if (tag == FOURCC_fiel) {
12055                     guint8 n_fields = 0, ordering = 0;
12056                     gst_byte_reader_get_uint8 (&br, &n_fields);
12057                     gst_byte_reader_get_uint8 (&br, &ordering);
12058                     if (n_fields == 1 || n_fields == 2) {
12059                       GST_DEBUG_OBJECT (qtdemux,
12060                           "Found fiel tag with %u fields, ordering %u",
12061                           n_fields, ordering);
12062                       if (n_fields == 2)
12063                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
12064                             "interlace-mode", G_TYPE_STRING, "interleaved",
12065                             NULL);
12066                     } else {
12067                       GST_WARNING_OBJECT (qtdemux,
12068                           "Found fiel tag with invalid fields (%u)", n_fields);
12069                     }
12070                   }
12071                   offset += size;
12072                 }
12073               } else {
12074                 GST_DEBUG_OBJECT (qtdemux,
12075                     "Color table ID is 0, not trying to get interlacedness");
12076               }
12077             } else {
12078               GST_WARNING_OBJECT (qtdemux,
12079                   "Length of jpeg chunk is too small, not trying to get interlacedness");
12080             }
12081
12082             break;
12083           }
12084           case FOURCC_rle_:
12085           case FOURCC_WRLE:
12086           {
12087             gst_caps_set_simple (entry->caps,
12088                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
12089                 NULL);
12090             break;
12091           }
12092           case FOURCC_XiTh:
12093           {
12094             GNode *xith, *xdxt;
12095
12096             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
12097             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12098             if (!xith)
12099               break;
12100
12101             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
12102             if (!xdxt)
12103               break;
12104
12105             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
12106             /* collect the headers and store them in a stream list so that we can
12107              * send them out first */
12108             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
12109             break;
12110           }
12111           case FOURCC_ovc1:
12112           {
12113             GNode *ovc1;
12114             guint8 *ovc1_data;
12115             guint ovc1_len;
12116             GstBuffer *buf;
12117
12118             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
12119             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12120             if (!ovc1)
12121               break;
12122             ovc1_data = ovc1->data;
12123             ovc1_len = QT_UINT32 (ovc1_data);
12124             if (ovc1_len <= 198) {
12125               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
12126               break;
12127             }
12128             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
12129             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
12130             gst_caps_set_simple (entry->caps,
12131                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
12132             gst_buffer_unref (buf);
12133             break;
12134           }
12135           case FOURCC_vc_1:
12136           {
12137             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12138             const guint8 *vc1_data = stsd_entry_data + 0x56;
12139
12140             /* find dvc1 */
12141             while (len >= 8) {
12142               gint size;
12143
12144               if (QT_UINT32 (vc1_data) <= len)
12145                 size = QT_UINT32 (vc1_data) - 8;
12146               else
12147                 size = len - 8;
12148
12149               if (size < 1)
12150                 /* No real data, so break out */
12151                 break;
12152
12153               switch (QT_FOURCC (vc1_data + 0x4)) {
12154                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
12155                 {
12156                   GstBuffer *buf;
12157
12158                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
12159                   buf = gst_buffer_new_and_alloc (size);
12160                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
12161                   gst_caps_set_simple (entry->caps,
12162                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12163                   gst_buffer_unref (buf);
12164                   break;
12165                 }
12166                 default:
12167                   break;
12168               }
12169               len -= size + 8;
12170               vc1_data += size + 8;
12171             }
12172             break;
12173           }
12174           case FOURCC_av01:
12175           {
12176             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
12177             const guint8 *av1_data = stsd_entry_data + 0x56;
12178
12179             /* find av1C */
12180             while (len >= 0x8) {
12181               gint size;
12182
12183               if (QT_UINT32 (av1_data) <= len)
12184                 size = QT_UINT32 (av1_data) - 0x8;
12185               else
12186                 size = len - 0x8;
12187
12188               if (size < 1)
12189                 /* No real data, so break out */
12190                 break;
12191
12192               switch (QT_FOURCC (av1_data + 0x4)) {
12193                 case FOURCC_av1C:
12194                 {
12195                   /* parse, if found */
12196                   GstBuffer *buf;
12197                   guint8 pres_delay_field;
12198
12199                   GST_DEBUG_OBJECT (qtdemux,
12200                       "found av1C codec_data in stsd of size %d", size);
12201
12202                   /* not enough data, just ignore and hope for the best */
12203                   if (size < 5)
12204                     break;
12205
12206                   /* Content is:
12207                    * 4 bytes: atom length
12208                    * 4 bytes: fourcc
12209                    * 1 byte: version
12210                    * 3 bytes: flags
12211                    * 3 bits: reserved
12212                    * 1 bits:  initial_presentation_delay_present
12213                    * 4 bits: initial_presentation_delay (if present else reserved
12214                    * rest: OBUs.
12215                    */
12216
12217                   if (av1_data[9] != 0) {
12218                     GST_WARNING ("Unknown version %d of av1C box", av1_data[9]);
12219                     break;
12220                   }
12221
12222                   /* We skip initial_presentation_delay* for now */
12223                   pres_delay_field = *(av1_data + 12);
12224                   if (pres_delay_field & (1 << 5)) {
12225                     gst_caps_set_simple (entry->caps,
12226                         "presentation-delay", G_TYPE_INT,
12227                         (gint) (pres_delay_field & 0x0F) + 1, NULL);
12228                   }
12229                   if (size > 5) {
12230                     buf = gst_buffer_new_and_alloc (size - 5);
12231                     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
12232                     gst_buffer_fill (buf, 0, av1_data + 13, size - 5);
12233                     gst_caps_set_simple (entry->caps,
12234                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
12235                     gst_buffer_unref (buf);
12236                   }
12237                   break;
12238                 }
12239                 default:
12240                   break;
12241               }
12242
12243               len -= size + 8;
12244               av1_data += size + 8;
12245             }
12246
12247             break;
12248           }
12249           default:
12250             break;
12251         }
12252       }
12253
12254       GST_INFO_OBJECT (qtdemux,
12255           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12256           GST_FOURCC_ARGS (fourcc), entry->caps);
12257
12258     } else if (stream->subtype == FOURCC_soun) {
12259       GNode *wave;
12260       int version, samplesize;
12261       guint16 compression_id;
12262       gboolean amrwb = FALSE;
12263
12264       offset = 16;
12265       /* sample description entry (16) + sound sample description v0 (20) */
12266       if (len < 36)
12267         goto corrupt_file;
12268
12269       version = QT_UINT32 (stsd_entry_data + offset);
12270       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
12271       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
12272       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
12273       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
12274
12275       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
12276       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
12277           QT_UINT32 (stsd_entry_data + offset + 4));
12278       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
12279       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
12280       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
12281       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
12282           QT_UINT16 (stsd_entry_data + offset + 14));
12283       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
12284
12285       if (compression_id == 0xfffe)
12286         entry->sampled = TRUE;
12287
12288       /* first assume uncompressed audio */
12289       entry->bytes_per_sample = samplesize / 8;
12290       entry->samples_per_frame = entry->n_channels;
12291       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
12292       entry->samples_per_packet = entry->samples_per_frame;
12293       entry->bytes_per_packet = entry->bytes_per_sample;
12294
12295       offset = 36;
12296       switch (fourcc) {
12297           /* Yes, these have to be hard-coded */
12298         case FOURCC_MAC6:
12299         {
12300           entry->samples_per_packet = 6;
12301           entry->bytes_per_packet = 1;
12302           entry->bytes_per_frame = 1 * entry->n_channels;
12303           entry->bytes_per_sample = 1;
12304           entry->samples_per_frame = 6 * entry->n_channels;
12305           break;
12306         }
12307         case FOURCC_MAC3:
12308         {
12309           entry->samples_per_packet = 3;
12310           entry->bytes_per_packet = 1;
12311           entry->bytes_per_frame = 1 * entry->n_channels;
12312           entry->bytes_per_sample = 1;
12313           entry->samples_per_frame = 3 * entry->n_channels;
12314           break;
12315         }
12316         case FOURCC_ima4:
12317         {
12318           entry->samples_per_packet = 64;
12319           entry->bytes_per_packet = 34;
12320           entry->bytes_per_frame = 34 * entry->n_channels;
12321           entry->bytes_per_sample = 2;
12322           entry->samples_per_frame = 64 * entry->n_channels;
12323           break;
12324         }
12325         case FOURCC_ulaw:
12326         case FOURCC_alaw:
12327         {
12328           entry->samples_per_packet = 1;
12329           entry->bytes_per_packet = 1;
12330           entry->bytes_per_frame = 1 * entry->n_channels;
12331           entry->bytes_per_sample = 1;
12332           entry->samples_per_frame = 1 * entry->n_channels;
12333           break;
12334         }
12335         case FOURCC_agsm:
12336         {
12337           entry->samples_per_packet = 160;
12338           entry->bytes_per_packet = 33;
12339           entry->bytes_per_frame = 33 * entry->n_channels;
12340           entry->bytes_per_sample = 2;
12341           entry->samples_per_frame = 160 * entry->n_channels;
12342           break;
12343         }
12344         default:
12345           break;
12346       }
12347
12348       if (version == 0x00010000) {
12349         /* sample description entry (16) + sound sample description v1 (20+16) */
12350         if (len < 52)
12351           goto corrupt_file;
12352
12353         switch (fourcc) {
12354           case FOURCC_twos:
12355           case FOURCC_sowt:
12356           case FOURCC_raw_:
12357           case FOURCC_lpcm:
12358             break;
12359           default:
12360           {
12361             /* only parse extra decoding config for non-pcm audio */
12362             entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
12363             entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
12364             entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
12365             entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
12366
12367             GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
12368                 entry->samples_per_packet);
12369             GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
12370                 entry->bytes_per_packet);
12371             GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
12372                 entry->bytes_per_frame);
12373             GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
12374                 entry->bytes_per_sample);
12375
12376             if (!entry->sampled && entry->bytes_per_packet) {
12377               entry->samples_per_frame = (entry->bytes_per_frame /
12378                   entry->bytes_per_packet) * entry->samples_per_packet;
12379               GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
12380                   entry->samples_per_frame);
12381             }
12382             break;
12383           }
12384         }
12385       } else if (version == 0x00020000) {
12386         union
12387         {
12388           gdouble fp;
12389           guint64 val;
12390         } qtfp;
12391
12392         /* sample description entry (16) + sound sample description v2 (56) */
12393         if (len < 72)
12394           goto corrupt_file;
12395
12396         qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
12397         entry->rate = qtfp.fp;
12398         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
12399
12400         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
12401         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
12402         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
12403         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
12404             QT_UINT32 (stsd_entry_data + offset + 20));
12405         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
12406             QT_UINT32 (stsd_entry_data + offset + 24));
12407         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
12408             QT_UINT32 (stsd_entry_data + offset + 28));
12409         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
12410             QT_UINT32 (stsd_entry_data + offset + 32));
12411       } else if (version != 0x00000) {
12412         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
12413             version);
12414       }
12415
12416       if (entry->caps)
12417         gst_caps_unref (entry->caps);
12418
12419       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
12420           stsd_entry_data + 32, len - 16, &codec);
12421
12422       switch (fourcc) {
12423         case FOURCC_in24:
12424         {
12425           GNode *enda;
12426           GNode *in24;
12427
12428           in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
12429
12430           enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
12431           if (!enda) {
12432             wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
12433             if (wave)
12434               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
12435           }
12436           if (enda) {
12437             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
12438             gst_caps_set_simple (entry->caps,
12439                 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
12440                 NULL);
12441           }
12442           break;
12443         }
12444         case FOURCC_owma:
12445         {
12446           const guint8 *owma_data;
12447           const gchar *codec_name = NULL;
12448           guint owma_len;
12449           GstBuffer *buf;
12450           gint version = 1;
12451           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12452           /* FIXME this should also be gst_riff_strf_auds,
12453            * but the latter one is actually missing bits-per-sample :( */
12454           typedef struct
12455           {
12456             gint16 wFormatTag;
12457             gint16 nChannels;
12458             gint32 nSamplesPerSec;
12459             gint32 nAvgBytesPerSec;
12460             gint16 nBlockAlign;
12461             gint16 wBitsPerSample;
12462             gint16 cbSize;
12463           } WAVEFORMATEX;
12464           WAVEFORMATEX *wfex;
12465
12466           GST_DEBUG_OBJECT (qtdemux, "parse owma");
12467           owma_data = stsd_entry_data;
12468           owma_len = QT_UINT32 (owma_data);
12469           if (owma_len <= 54) {
12470             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
12471             break;
12472           }
12473           wfex = (WAVEFORMATEX *) (owma_data + 36);
12474           buf = gst_buffer_new_and_alloc (owma_len - 54);
12475           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
12476           if (wfex->wFormatTag == 0x0161) {
12477             codec_name = "Windows Media Audio";
12478             version = 2;
12479           } else if (wfex->wFormatTag == 0x0162) {
12480             codec_name = "Windows Media Audio 9 Pro";
12481             version = 3;
12482           } else if (wfex->wFormatTag == 0x0163) {
12483             codec_name = "Windows Media Audio 9 Lossless";
12484             /* is that correct? gstffmpegcodecmap.c is missing it, but
12485              * fluendo codec seems to support it */
12486             version = 4;
12487           }
12488
12489           gst_caps_set_simple (entry->caps,
12490               "codec_data", GST_TYPE_BUFFER, buf,
12491               "wmaversion", G_TYPE_INT, version,
12492               "block_align", G_TYPE_INT,
12493               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
12494               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
12495               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
12496               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
12497           gst_buffer_unref (buf);
12498
12499           if (codec_name) {
12500             g_free (codec);
12501             codec = g_strdup (codec_name);
12502           }
12503           break;
12504         }
12505         case FOURCC_wma_:
12506         {
12507           gint len = QT_UINT32 (stsd_entry_data) - offset;
12508           const guint8 *wfex_data = stsd_entry_data + offset;
12509           const gchar *codec_name = NULL;
12510           gint version = 1;
12511           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
12512           /* FIXME this should also be gst_riff_strf_auds,
12513            * but the latter one is actually missing bits-per-sample :( */
12514           typedef struct
12515           {
12516             gint16 wFormatTag;
12517             gint16 nChannels;
12518             gint32 nSamplesPerSec;
12519             gint32 nAvgBytesPerSec;
12520             gint16 nBlockAlign;
12521             gint16 wBitsPerSample;
12522             gint16 cbSize;
12523           } WAVEFORMATEX;
12524           WAVEFORMATEX wfex;
12525
12526           /* FIXME: unify with similar wavformatex parsing code above */
12527           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
12528
12529           /* find wfex */
12530           while (len >= 8) {
12531             gint size;
12532
12533             if (QT_UINT32 (wfex_data) <= len)
12534               size = QT_UINT32 (wfex_data) - 8;
12535             else
12536               size = len - 8;
12537
12538             if (size < 1)
12539               /* No real data, so break out */
12540               break;
12541
12542             switch (QT_FOURCC (wfex_data + 4)) {
12543               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
12544               {
12545                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
12546
12547                 if (size < 8 + 18)
12548                   break;
12549
12550                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
12551                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
12552                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
12553                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
12554                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
12555                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
12556                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
12557
12558                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
12559                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
12560                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
12561                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
12562                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
12563                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
12564
12565                 if (wfex.wFormatTag == 0x0161) {
12566                   codec_name = "Windows Media Audio";
12567                   version = 2;
12568                 } else if (wfex.wFormatTag == 0x0162) {
12569                   codec_name = "Windows Media Audio 9 Pro";
12570                   version = 3;
12571                 } else if (wfex.wFormatTag == 0x0163) {
12572                   codec_name = "Windows Media Audio 9 Lossless";
12573                   /* is that correct? gstffmpegcodecmap.c is missing it, but
12574                    * fluendo codec seems to support it */
12575                   version = 4;
12576                 }
12577
12578                 gst_caps_set_simple (entry->caps,
12579                     "wmaversion", G_TYPE_INT, version,
12580                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
12581                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
12582                     "width", G_TYPE_INT, wfex.wBitsPerSample,
12583                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
12584
12585                 if (size > wfex.cbSize) {
12586                   GstBuffer *buf;
12587
12588                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
12589                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
12590                       size - wfex.cbSize);
12591                   gst_caps_set_simple (entry->caps,
12592                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
12593                   gst_buffer_unref (buf);
12594                 } else {
12595                   GST_WARNING_OBJECT (qtdemux, "no codec data");
12596                 }
12597
12598                 if (codec_name) {
12599                   g_free (codec);
12600                   codec = g_strdup (codec_name);
12601                 }
12602                 break;
12603               }
12604               default:
12605                 break;
12606             }
12607             len -= size + 8;
12608             wfex_data += size + 8;
12609           }
12610           break;
12611         }
12612         case FOURCC_opus:
12613         {
12614           const guint8 *opus_data;
12615           guint8 *channel_mapping = NULL;
12616           guint32 rate;
12617           guint8 channels;
12618           guint8 channel_mapping_family;
12619           guint8 stream_count;
12620           guint8 coupled_count;
12621           guint8 i;
12622
12623           opus_data = stsd_entry_data;
12624
12625           channels = GST_READ_UINT8 (opus_data + 45);
12626           rate = GST_READ_UINT32_LE (opus_data + 48);
12627           channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
12628           stream_count = GST_READ_UINT8 (opus_data + 55);
12629           coupled_count = GST_READ_UINT8 (opus_data + 56);
12630
12631           if (channels > 0) {
12632             channel_mapping = g_malloc (channels * sizeof (guint8));
12633             for (i = 0; i < channels; i++)
12634               channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
12635           }
12636
12637           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
12638               channel_mapping_family, stream_count, coupled_count,
12639               channel_mapping);
12640           break;
12641         }
12642         default:
12643           break;
12644       }
12645
12646       if (codec) {
12647         GstStructure *s;
12648         gint bitrate = 0;
12649
12650         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12651             GST_TAG_AUDIO_CODEC, codec, NULL);
12652         g_free (codec);
12653         codec = NULL;
12654
12655         /* some bitrate info may have ended up in caps */
12656         s = gst_caps_get_structure (entry->caps, 0);
12657         gst_structure_get_int (s, "bitrate", &bitrate);
12658         if (bitrate > 0)
12659           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12660               GST_TAG_BITRATE, bitrate, NULL);
12661       }
12662
12663       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
12664       if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != fourcc) {
12665         if (stream->protected && QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca)
12666           mp4a = NULL;
12667         else if (!stream->protected)
12668           mp4a = NULL;
12669       }
12670
12671       wave = NULL;
12672       esds = NULL;
12673       if (mp4a) {
12674         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
12675         if (wave)
12676           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
12677         if (!esds)
12678           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
12679       }
12680
12681
12682       /* If the fourcc's bottom 16 bits gives 'sm', then the top
12683          16 bits is a byte-swapped wave-style codec identifier,
12684          and we can find a WAVE header internally to a 'wave' atom here.
12685          This can more clearly be thought of as 'ms' as the top 16 bits, and a
12686          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
12687          is big-endian).
12688        */
12689       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
12690         if (len < offset + 20) {
12691           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
12692         } else {
12693           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
12694           const guint8 *data = stsd_entry_data + offset + 16;
12695           GNode *wavenode;
12696           GNode *waveheadernode;
12697
12698           wavenode = g_node_new ((guint8 *) data);
12699           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
12700             const guint8 *waveheader;
12701             guint32 headerlen;
12702
12703             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
12704             if (waveheadernode) {
12705               waveheader = (const guint8 *) waveheadernode->data;
12706               headerlen = QT_UINT32 (waveheader);
12707
12708               if (headerlen > 8) {
12709                 gst_riff_strf_auds *header = NULL;
12710                 GstBuffer *headerbuf;
12711                 GstBuffer *extra;
12712
12713                 waveheader += 8;
12714                 headerlen -= 8;
12715
12716                 headerbuf = gst_buffer_new_and_alloc (headerlen);
12717                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
12718
12719                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
12720                         headerbuf, &header, &extra)) {
12721                   gst_caps_unref (entry->caps);
12722                   /* FIXME: Need to do something with the channel reorder map */
12723                   entry->caps =
12724                       gst_riff_create_audio_caps (header->format, NULL, header,
12725                       extra, NULL, NULL, NULL);
12726
12727                   if (extra)
12728                     gst_buffer_unref (extra);
12729                   g_free (header);
12730                 }
12731               }
12732             } else
12733               GST_DEBUG ("Didn't find waveheadernode for this codec");
12734           }
12735           g_node_destroy (wavenode);
12736         }
12737       } else if (esds) {
12738         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12739             stream->stream_tags);
12740       } else {
12741         switch (fourcc) {
12742 #if 0
12743             /* FIXME: what is in the chunk? */
12744           case FOURCC_QDMC:
12745           {
12746             gint len = QT_UINT32 (stsd_data);
12747
12748             /* seems to be always = 116 = 0x74 */
12749             break;
12750           }
12751 #endif
12752           case FOURCC_QDM2:
12753           {
12754             gint len = QT_UINT32 (stsd_entry_data);
12755
12756             if (len > 0x3C) {
12757               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
12758
12759               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
12760               gst_caps_set_simple (entry->caps,
12761                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12762               gst_buffer_unref (buf);
12763             }
12764             gst_caps_set_simple (entry->caps,
12765                 "samplesize", G_TYPE_INT, samplesize, NULL);
12766             break;
12767           }
12768           case FOURCC_alac:
12769           {
12770             GNode *alac, *wave = NULL;
12771
12772             /* apparently, m4a has this atom appended directly in the stsd entry,
12773              * while mov has it in a wave atom */
12774             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
12775             if (alac) {
12776               /* alac now refers to stsd entry atom */
12777               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
12778               if (wave)
12779                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
12780               else
12781                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
12782             }
12783             if (alac) {
12784               const guint8 *alac_data = alac->data;
12785               gint len = QT_UINT32 (alac->data);
12786               GstBuffer *buf;
12787
12788               if (len < 36) {
12789                 GST_DEBUG_OBJECT (qtdemux,
12790                     "discarding alac atom with unexpected len %d", len);
12791               } else {
12792                 /* codec-data contains alac atom size and prefix,
12793                  * ffmpeg likes it that way, not quite gst-ish though ...*/
12794                 buf = gst_buffer_new_and_alloc (len);
12795                 gst_buffer_fill (buf, 0, alac->data, len);
12796                 gst_caps_set_simple (entry->caps,
12797                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12798                 gst_buffer_unref (buf);
12799
12800                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
12801                 entry->n_channels = QT_UINT8 (alac_data + 21);
12802                 entry->rate = QT_UINT32 (alac_data + 32);
12803               }
12804             }
12805             gst_caps_set_simple (entry->caps,
12806                 "samplesize", G_TYPE_INT, samplesize, NULL);
12807             break;
12808           }
12809           case FOURCC_fLaC:
12810           {
12811             /* The codingname of the sample entry is 'fLaC' */
12812             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
12813
12814             if (flac) {
12815               /* The 'dfLa' box is added to the sample entry to convey
12816                  initializing information for the decoder. */
12817               const GNode *dfla =
12818                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
12819
12820               if (dfla) {
12821                 const guint32 len = QT_UINT32 (dfla->data);
12822
12823                 /* Must contain at least dfLa box header (12),
12824                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
12825                 if (len < 50) {
12826                   GST_DEBUG_OBJECT (qtdemux,
12827                       "discarding dfla atom with unexpected len %d", len);
12828                 } else {
12829                   /* skip dfLa header to get the METADATA_BLOCKs */
12830                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
12831                   const guint32 metadata_blocks_len = len - 12;
12832
12833                   gchar *stream_marker = g_strdup ("fLaC");
12834                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
12835                       strlen (stream_marker));
12836
12837                   guint32 index = 0;
12838                   guint32 remainder = 0;
12839                   guint32 block_size = 0;
12840                   gboolean is_last = FALSE;
12841
12842                   GValue array = G_VALUE_INIT;
12843                   GValue value = G_VALUE_INIT;
12844
12845                   g_value_init (&array, GST_TYPE_ARRAY);
12846                   g_value_init (&value, GST_TYPE_BUFFER);
12847
12848                   gst_value_set_buffer (&value, block);
12849                   gst_value_array_append_value (&array, &value);
12850                   g_value_reset (&value);
12851
12852                   gst_buffer_unref (block);
12853
12854                   /* check there's at least one METADATA_BLOCK_HEADER's worth
12855                    * of data, and we haven't already finished parsing */
12856                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
12857                     remainder = metadata_blocks_len - index;
12858
12859                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
12860                     block_size = 4 +
12861                         (metadata_blocks[index + 1] << 16) +
12862                         (metadata_blocks[index + 2] << 8) +
12863                         metadata_blocks[index + 3];
12864
12865                     /* be careful not to read off end of box */
12866                     if (block_size > remainder) {
12867                       break;
12868                     }
12869
12870                     is_last = metadata_blocks[index] >> 7;
12871
12872                     block = gst_buffer_new_and_alloc (block_size);
12873
12874                     gst_buffer_fill (block, 0, &metadata_blocks[index],
12875                         block_size);
12876
12877                     gst_value_set_buffer (&value, block);
12878                     gst_value_array_append_value (&array, &value);
12879                     g_value_reset (&value);
12880
12881                     gst_buffer_unref (block);
12882
12883                     index += block_size;
12884                   }
12885
12886                   /* only append the metadata if we successfully read all of it */
12887                   if (is_last) {
12888                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
12889                             (stream)->caps, 0), "streamheader", &array);
12890                   } else {
12891                     GST_WARNING_OBJECT (qtdemux,
12892                         "discarding all METADATA_BLOCKs due to invalid "
12893                         "block_size %d at idx %d, rem %d", block_size, index,
12894                         remainder);
12895                   }
12896
12897                   g_value_unset (&value);
12898                   g_value_unset (&array);
12899
12900                   /* The sample rate obtained from the stsd may not be accurate
12901                    * since it cannot represent rates greater than 65535Hz, so
12902                    * override that value with the sample rate from the
12903                    * METADATA_BLOCK_STREAMINFO block */
12904                   CUR_STREAM (stream)->rate =
12905                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
12906                 }
12907               }
12908             }
12909             break;
12910           }
12911           case FOURCC_sawb:
12912             /* Fallthrough! */
12913             amrwb = TRUE;
12914           case FOURCC_samr:
12915           {
12916             gint len = QT_UINT32 (stsd_entry_data);
12917
12918             if (len > 0x24) {
12919               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
12920               guint bitrate;
12921
12922               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
12923
12924               /* If we have enough data, let's try to get the 'damr' atom. See
12925                * the 3GPP container spec (26.244) for more details. */
12926               if ((len - 0x34) > 8 &&
12927                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12928                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12929                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12930               }
12931
12932               gst_caps_set_simple (entry->caps,
12933                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12934               gst_buffer_unref (buf);
12935             }
12936             break;
12937           }
12938           case FOURCC_mp4a:
12939           {
12940             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12941             gint len = QT_UINT32 (stsd_entry_data);
12942
12943             if (len >= 34) {
12944               guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12945
12946               if (sound_version == 1) {
12947                 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12948                 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12949                 guint8 codec_data[2];
12950                 GstBuffer *buf;
12951                 gint profile = 2;       /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12952
12953                 gint sample_rate_index =
12954                     gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12955
12956                 /* build AAC codec data */
12957                 codec_data[0] = profile << 3;
12958                 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12959                 codec_data[1] = (sample_rate_index & 0x01) << 7;
12960                 codec_data[1] |= (channels & 0xF) << 3;
12961
12962                 buf = gst_buffer_new_and_alloc (2);
12963                 gst_buffer_fill (buf, 0, codec_data, 2);
12964                 gst_caps_set_simple (entry->caps,
12965                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12966                 gst_buffer_unref (buf);
12967               }
12968             }
12969             break;
12970           }
12971           case FOURCC_lpcm:
12972             /* Fully handled elsewhere */
12973             break;
12974           default:
12975             GST_INFO_OBJECT (qtdemux,
12976                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12977             break;
12978         }
12979       }
12980       GST_INFO_OBJECT (qtdemux,
12981           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12982           GST_FOURCC_ARGS (fourcc), entry->caps);
12983
12984     } else if (stream->subtype == FOURCC_strm) {
12985       if (fourcc == FOURCC_rtsp) {
12986         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12987       } else {
12988         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12989             GST_FOURCC_ARGS (fourcc));
12990         goto unknown_stream;
12991       }
12992       entry->sampled = TRUE;
12993     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12994         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt
12995         || stream->subtype == FOURCC_clcp) {
12996
12997       entry->sampled = TRUE;
12998       entry->sparse = TRUE;
12999
13000       entry->caps =
13001           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13002           &codec);
13003       if (codec) {
13004         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13005             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13006         g_free (codec);
13007         codec = NULL;
13008       }
13009
13010       /* hunt for sort-of codec data */
13011       switch (fourcc) {
13012         case FOURCC_mp4s:
13013         {
13014           GNode *mp4s = NULL;
13015           GNode *esds = NULL;
13016
13017           /* look for palette in a stsd->mp4s->esds sub-atom */
13018           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
13019           if (mp4s)
13020             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
13021           if (esds == NULL) {
13022             /* Invalid STSD */
13023             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
13024             break;
13025           }
13026
13027           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
13028               stream->stream_tags);
13029           break;
13030         }
13031         default:
13032           GST_INFO_OBJECT (qtdemux,
13033               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13034           break;
13035       }
13036       GST_INFO_OBJECT (qtdemux,
13037           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
13038           GST_FOURCC_ARGS (fourcc), entry->caps);
13039     } else {
13040       /* everything in 1 sample */
13041       entry->sampled = TRUE;
13042
13043       entry->caps =
13044           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
13045           &codec);
13046
13047       if (entry->caps == NULL)
13048         goto unknown_stream;
13049
13050       if (codec) {
13051         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13052             GST_TAG_SUBTITLE_CODEC, codec, NULL);
13053         g_free (codec);
13054         codec = NULL;
13055       }
13056     }
13057
13058     /* promote to sampled format */
13059     if (entry->fourcc == FOURCC_samr) {
13060       /* force mono 8000 Hz for AMR */
13061       entry->sampled = TRUE;
13062       entry->n_channels = 1;
13063       entry->rate = 8000;
13064     } else if (entry->fourcc == FOURCC_sawb) {
13065       /* force mono 16000 Hz for AMR-WB */
13066       entry->sampled = TRUE;
13067       entry->n_channels = 1;
13068       entry->rate = 16000;
13069     } else if (entry->fourcc == FOURCC_mp4a) {
13070       entry->sampled = TRUE;
13071     }
13072
13073
13074     stsd_entry_data += len;
13075     remaining_stsd_len -= len;
13076
13077   }
13078
13079   /* collect sample information */
13080   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
13081     goto samples_failed;
13082
13083   if (qtdemux->fragmented) {
13084     guint64 offset;
13085
13086     /* need all moov samples as basis; probably not many if any at all */
13087     /* prevent moof parsing taking of at this time */
13088     offset = qtdemux->moof_offset;
13089     qtdemux->moof_offset = 0;
13090     if (stream->n_samples &&
13091         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
13092       qtdemux->moof_offset = offset;
13093       goto samples_failed;
13094     }
13095     qtdemux->moof_offset = 0;
13096     /* movie duration more reliable in this case (e.g. mehd) */
13097     if (qtdemux->segment.duration &&
13098         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
13099       stream->duration =
13100           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
13101   }
13102
13103   /* configure segments */
13104   if (!qtdemux_parse_segments (qtdemux, stream, trak))
13105     goto segments_failed;
13106
13107   /* add some language tag, if useful */
13108   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
13109       strcmp (stream->lang_id, "und")) {
13110     const gchar *lang_code;
13111
13112     /* convert ISO 639-2 code to ISO 639-1 */
13113     lang_code = gst_tag_get_language_code (stream->lang_id);
13114     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13115         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
13116   }
13117
13118   /* Check for UDTA tags */
13119   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
13120     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
13121   }
13122
13123   /* Insert and sort new stream in track-id order.
13124    * This will help in comparing old/new streams during stream update check */
13125   g_ptr_array_add (qtdemux->active_streams, stream);
13126   g_ptr_array_sort (qtdemux->active_streams,
13127       (GCompareFunc) qtdemux_track_id_compare_func);
13128   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d",
13129       QTDEMUX_N_STREAMS (qtdemux));
13130
13131   return TRUE;
13132
13133 /* ERRORS */
13134 corrupt_file:
13135   {
13136     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
13137         (_("This file is corrupt and cannot be played.")), (NULL));
13138     if (stream)
13139       gst_qtdemux_stream_unref (stream);
13140     return FALSE;
13141   }
13142 error_encrypted:
13143   {
13144     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
13145     gst_qtdemux_stream_unref (stream);
13146     return FALSE;
13147   }
13148 samples_failed:
13149 segments_failed:
13150   {
13151     /* we posted an error already */
13152     /* free stbl sub-atoms */
13153     gst_qtdemux_stbl_free (stream);
13154     gst_qtdemux_stream_unref (stream);
13155     return FALSE;
13156   }
13157 existing_stream:
13158   {
13159     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
13160         track_id);
13161     return TRUE;
13162   }
13163 unknown_stream:
13164   {
13165     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
13166         GST_FOURCC_ARGS (stream->subtype));
13167     gst_qtdemux_stream_unref (stream);
13168     return TRUE;
13169   }
13170 }
13171
13172 /* If we can estimate the overall bitrate, and don't have information about the
13173  * stream bitrate for exactly one stream, this guesses the stream bitrate as
13174  * the overall bitrate minus the sum of the bitrates of all other streams. This
13175  * should be useful for the common case where we have one audio and one video
13176  * stream and can estimate the bitrate of one, but not the other. */
13177 static void
13178 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
13179 {
13180   QtDemuxStream *stream = NULL;
13181   gint64 size, sys_bitrate, sum_bitrate = 0;
13182   GstClockTime duration;
13183   guint bitrate;
13184   gint i;
13185
13186   if (qtdemux->fragmented)
13187     return;
13188
13189   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
13190
13191   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
13192       || size <= 0) {
13193     GST_DEBUG_OBJECT (qtdemux,
13194         "Size in bytes of the stream not known - bailing");
13195     return;
13196   }
13197
13198   /* Subtract the header size */
13199   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
13200       size, qtdemux->header_size);
13201
13202   if (size < qtdemux->header_size)
13203     return;
13204
13205   size = size - qtdemux->header_size;
13206
13207   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
13208     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
13209     return;
13210   }
13211
13212   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13213     QtDemuxStream *str = QTDEMUX_NTH_STREAM (qtdemux, i);
13214     switch (str->subtype) {
13215       case FOURCC_soun:
13216       case FOURCC_vide:
13217         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
13218             CUR_STREAM (str)->caps);
13219         /* retrieve bitrate, prefer avg then max */
13220         bitrate = 0;
13221         if (str->stream_tags) {
13222           if (gst_tag_list_get_uint (str->stream_tags,
13223                   GST_TAG_MAXIMUM_BITRATE, &bitrate))
13224             GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
13225           if (gst_tag_list_get_uint (str->stream_tags,
13226                   GST_TAG_NOMINAL_BITRATE, &bitrate))
13227             GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
13228           if (gst_tag_list_get_uint (str->stream_tags,
13229                   GST_TAG_BITRATE, &bitrate))
13230             GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
13231         }
13232         if (bitrate)
13233           sum_bitrate += bitrate;
13234         else {
13235           if (stream) {
13236             GST_DEBUG_OBJECT (qtdemux,
13237                 ">1 stream with unknown bitrate - bailing");
13238             return;
13239           } else
13240             stream = str;
13241         }
13242
13243       default:
13244         /* For other subtypes, we assume no significant impact on bitrate */
13245         break;
13246     }
13247   }
13248
13249   if (!stream) {
13250     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
13251     return;
13252   }
13253
13254   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
13255
13256   if (sys_bitrate < sum_bitrate) {
13257     /* This can happen, since sum_bitrate might be derived from maximum
13258      * bitrates and not average bitrates */
13259     GST_DEBUG_OBJECT (qtdemux,
13260         "System bitrate less than sum bitrate - bailing");
13261     return;
13262   }
13263
13264   bitrate = sys_bitrate - sum_bitrate;
13265   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
13266       ", Stream bitrate = %u", sys_bitrate, bitrate);
13267
13268   if (!stream->stream_tags)
13269     stream->stream_tags = gst_tag_list_new_empty ();
13270   else
13271     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
13272
13273   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
13274       GST_TAG_BITRATE, bitrate, NULL);
13275 }
13276
13277 static GstFlowReturn
13278 qtdemux_prepare_streams (GstQTDemux * qtdemux)
13279 {
13280   GstFlowReturn ret = GST_FLOW_OK;
13281 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
13282   guint64 tkhd_max_duration = 0;
13283 #endif
13284   gint i;
13285
13286   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
13287
13288   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13289     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13290     guint32 sample_num = 0;
13291
13292     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13293         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13294
13295     if (qtdemux->fragmented) {
13296       /* need all moov samples first */
13297       GST_OBJECT_LOCK (qtdemux);
13298       while (stream->n_samples == 0)
13299         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
13300           break;
13301       GST_OBJECT_UNLOCK (qtdemux);
13302     } else {
13303       /* discard any stray moof */
13304       qtdemux->moof_offset = 0;
13305 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
13306       if (tkhd_max_duration < stream->tkhd_duration)
13307         tkhd_max_duration = stream->tkhd_duration;
13308 #endif
13309     }
13310
13311     /* prepare braking */
13312     if (ret != GST_FLOW_ERROR)
13313       ret = GST_FLOW_OK;
13314
13315     /* in pull mode, we should have parsed some sample info by now;
13316      * and quite some code will not handle no samples.
13317      * in push mode, we'll just have to deal with it */
13318     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
13319       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
13320       g_ptr_array_remove_index (qtdemux->active_streams, i);
13321       i--;
13322       continue;
13323     } else if (stream->track_id == qtdemux->chapters_track_id &&
13324         (stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl)) {
13325       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
13326          so that it doesn't look like a subtitle track */
13327       g_ptr_array_remove_index (qtdemux->active_streams, i);
13328       i--;
13329       continue;
13330     }
13331
13332     /* parse the initial sample for use in setting the frame rate cap */
13333     while (sample_num == 0 && sample_num < stream->n_samples) {
13334       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
13335         break;
13336       ++sample_num;
13337     }
13338   }
13339
13340 #ifdef TIZEN_FEATURE_QTDEMUX_DURATION
13341   if (!qtdemux->fragmented && (qtdemux->duration > tkhd_max_duration)) {
13342     GST_INFO_OBJECT (qtdemux,
13343         "Update duration: %" G_GUINT64_FORMAT " -> %" G_GUINT64_FORMAT,
13344         qtdemux->duration, tkhd_max_duration);
13345     qtdemux->duration = tkhd_max_duration;
13346   }
13347 #endif
13348
13349   return ret;
13350 }
13351
13352 static gboolean
13353 _stream_equal_func (const QtDemuxStream * stream, const gchar * stream_id)
13354 {
13355   return g_strcmp0 (stream->stream_id, stream_id) == 0;
13356 }
13357
13358 static gboolean
13359 qtdemux_is_streams_update (GstQTDemux * qtdemux)
13360 {
13361   gint i;
13362
13363   /* Different length, updated */
13364   if (QTDEMUX_N_STREAMS (qtdemux) != qtdemux->old_streams->len)
13365     return TRUE;
13366
13367   /* streams in list are sorted in track-id order */
13368   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13369     /* Different stream-id, updated */
13370     if (g_strcmp0 (QTDEMUX_NTH_STREAM (qtdemux, i)->stream_id,
13371             QTDEMUX_NTH_OLD_STREAM (qtdemux, i)->stream_id))
13372       return TRUE;
13373   }
13374
13375   return FALSE;
13376 }
13377
13378 static gboolean
13379 qtdemux_reuse_and_configure_stream (GstQTDemux * qtdemux,
13380     QtDemuxStream * oldstream, QtDemuxStream * newstream)
13381 {
13382   /* Connect old stream's srcpad to new stream */
13383   newstream->pad = oldstream->pad;
13384   oldstream->pad = NULL;
13385
13386   /* unset new_stream to prevent stream-start event */
13387   newstream->new_stream = FALSE;
13388
13389   return gst_qtdemux_configure_stream (qtdemux, newstream);
13390 }
13391
13392 /* g_ptr_array_find_with_equal_func is available since 2.54,
13393  * replacement until we can depend unconditionally on the real one in GLib */
13394 #if !GLIB_CHECK_VERSION(2,54,0)
13395 #define g_ptr_array_find_with_equal_func qtdemux_ptr_array_find_with_equal_func
13396 static gboolean
13397 qtdemux_ptr_array_find_with_equal_func (GPtrArray * haystack,
13398     gconstpointer needle, GEqualFunc equal_func, guint * index_)
13399 {
13400   guint i;
13401
13402   g_return_val_if_fail (haystack != NULL, FALSE);
13403
13404   if (equal_func == NULL)
13405     equal_func = g_direct_equal;
13406
13407   for (i = 0; i < haystack->len; i++) {
13408     if (equal_func (g_ptr_array_index (haystack, i), needle)) {
13409       if (index_ != NULL)
13410         *index_ = i;
13411       return TRUE;
13412     }
13413   }
13414
13415   return FALSE;
13416 }
13417 #endif
13418
13419 static gboolean
13420 qtdemux_update_streams (GstQTDemux * qtdemux)
13421 {
13422   gint i;
13423   g_assert (qtdemux->streams_aware);
13424
13425   /* At below, figure out which stream in active_streams has identical stream-id
13426    * with that of in old_streams. If there is matching stream-id,
13427    * corresponding newstream will not be exposed again,
13428    * but demux will reuse srcpad of matched old stream
13429    *
13430    * active_streams : newly created streams from the latest moov
13431    * old_streams : existing streams (belong to previous moov)
13432    */
13433
13434   for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13435     QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13436     QtDemuxStream *oldstream = NULL;
13437     guint target;
13438
13439     GST_DEBUG_OBJECT (qtdemux, "track-id %u, fourcc %" GST_FOURCC_FORMAT,
13440         stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
13441
13442     if (g_ptr_array_find_with_equal_func (qtdemux->old_streams,
13443             stream->stream_id, (GEqualFunc) _stream_equal_func, &target)) {
13444       oldstream = QTDEMUX_NTH_OLD_STREAM (qtdemux, target);
13445
13446       /* null pad stream cannot be reused */
13447       if (oldstream->pad == NULL)
13448         oldstream = NULL;
13449     }
13450
13451     if (oldstream) {
13452       GST_DEBUG_OBJECT (qtdemux, "Reuse track-id %d", oldstream->track_id);
13453
13454       if (!qtdemux_reuse_and_configure_stream (qtdemux, oldstream, stream))
13455         return FALSE;
13456
13457       /* we don't need to preserve order of old streams */
13458       g_ptr_array_remove_fast (qtdemux->old_streams, oldstream);
13459     } else {
13460       GstTagList *list;
13461
13462       /* now we have all info and can expose */
13463       list = stream->stream_tags;
13464       stream->stream_tags = NULL;
13465       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13466         return FALSE;
13467     }
13468   }
13469
13470   return TRUE;
13471 }
13472
13473 /* Must be called with expose lock */
13474 static GstFlowReturn
13475 qtdemux_expose_streams (GstQTDemux * qtdemux)
13476 {
13477   gint i;
13478
13479   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
13480
13481   if (!qtdemux_is_streams_update (qtdemux)) {
13482     GST_DEBUG_OBJECT (qtdemux, "Reuse all streams");
13483     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13484       QtDemuxStream *new_stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13485       QtDemuxStream *old_stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13486       if (!qtdemux_reuse_and_configure_stream (qtdemux, old_stream, new_stream))
13487         return GST_FLOW_ERROR;
13488     }
13489
13490     g_ptr_array_set_size (qtdemux->old_streams, 0);
13491     qtdemux->need_segment = TRUE;
13492
13493     return GST_FLOW_OK;
13494   }
13495
13496   if (qtdemux->streams_aware) {
13497     if (!qtdemux_update_streams (qtdemux))
13498       return GST_FLOW_ERROR;
13499   } else {
13500     for (i = 0; i < QTDEMUX_N_STREAMS (qtdemux); i++) {
13501       QtDemuxStream *stream = QTDEMUX_NTH_STREAM (qtdemux, i);
13502       GstTagList *list;
13503
13504       /* now we have all info and can expose */
13505       list = stream->stream_tags;
13506       stream->stream_tags = NULL;
13507       if (!gst_qtdemux_add_stream (qtdemux, stream, list))
13508         return GST_FLOW_ERROR;
13509
13510     }
13511   }
13512
13513   gst_qtdemux_guess_bitrate (qtdemux);
13514
13515   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
13516
13517   /* If we have still old_streams, it's no more used stream */
13518   for (i = 0; i < qtdemux->old_streams->len; i++) {
13519     QtDemuxStream *stream = QTDEMUX_NTH_OLD_STREAM (qtdemux, i);
13520
13521     if (stream->pad) {
13522       GstEvent *event;
13523
13524       event = gst_event_new_eos ();
13525       if (qtdemux->segment_seqnum)
13526         gst_event_set_seqnum (event, qtdemux->segment_seqnum);
13527
13528       gst_pad_push_event (stream->pad, event);
13529     }
13530   }
13531
13532   g_ptr_array_set_size (qtdemux->old_streams, 0);
13533
13534   /* check if we should post a redirect in case there is a single trak
13535    * and it is a redirecting trak */
13536   if (QTDEMUX_N_STREAMS (qtdemux) == 1 &&
13537       QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri != NULL) {
13538     GstMessage *m;
13539
13540     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
13541         "an external content");
13542     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
13543         gst_structure_new ("redirect",
13544             "new-location", G_TYPE_STRING,
13545             QTDEMUX_NTH_STREAM (qtdemux, 0)->redirect_uri, NULL));
13546     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
13547     qtdemux->posted_redirect = TRUE;
13548   }
13549
13550   g_ptr_array_foreach (qtdemux->active_streams,
13551       (GFunc) qtdemux_do_allocation, qtdemux);
13552
13553   qtdemux->need_segment = TRUE;
13554
13555   qtdemux->exposed = TRUE;
13556   return GST_FLOW_OK;
13557 }
13558
13559 /* check if major or compatible brand is 3GP */
13560 static inline gboolean
13561 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
13562 {
13563   if (major) {
13564     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
13565         FOURCC_3g__);
13566   } else if (qtdemux->comp_brands != NULL) {
13567     GstMapInfo map;
13568     guint8 *data;
13569     gsize size;
13570     gboolean res = FALSE;
13571
13572     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
13573     data = map.data;
13574     size = map.size;
13575     while (size >= 4) {
13576       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
13577           FOURCC_3g__);
13578       data += 4;
13579       size -= 4;
13580     }
13581     gst_buffer_unmap (qtdemux->comp_brands, &map);
13582     return res;
13583   } else {
13584     return FALSE;
13585   }
13586 }
13587
13588 /* check if tag is a spec'ed 3GP tag keyword storing a string */
13589 static inline gboolean
13590 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
13591 {
13592   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
13593       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
13594       || fourcc == FOURCC_albm;
13595 }
13596
13597 static void
13598 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
13599     const char *tag, const char *dummy, GNode * node)
13600 {
13601   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13602   int offset;
13603   char *name;
13604   gchar *data;
13605   gdouble longitude, latitude, altitude;
13606   gint len;
13607
13608   len = QT_UINT32 (node->data);
13609   if (len <= 14)
13610     goto short_read;
13611
13612   data = node->data;
13613   offset = 14;
13614
13615   /* TODO: language code skipped */
13616
13617   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
13618
13619   if (!name) {
13620     /* do not alarm in trivial case, but bail out otherwise */
13621     if (*(data + offset) != 0) {
13622       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
13623           "giving up", tag);
13624     }
13625   } else {
13626     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
13627         GST_TAG_GEO_LOCATION_NAME, name, NULL);
13628     offset += strlen (name);
13629     g_free (name);
13630   }
13631
13632   if (len < offset + 2 + 4 + 4 + 4)
13633     goto short_read;
13634
13635   /* +1 +1 = skip null-terminator and location role byte */
13636   offset += 1 + 1;
13637   /* table in spec says unsigned, semantics say negative has meaning ... */
13638   longitude = QT_SFP32 (data + offset);
13639
13640   offset += 4;
13641   latitude = QT_SFP32 (data + offset);
13642
13643   offset += 4;
13644   altitude = QT_SFP32 (data + offset);
13645
13646   /* one invalid means all are invalid */
13647   if (longitude >= -180.0 && longitude <= 180.0 &&
13648       latitude >= -90.0 && latitude <= 90.0) {
13649     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
13650         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
13651         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
13652         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
13653   }
13654
13655   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
13656
13657   return;
13658
13659   /* ERRORS */
13660 short_read:
13661   {
13662     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
13663     return;
13664   }
13665 }
13666
13667
13668 static void
13669 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
13670     const char *tag, const char *dummy, GNode * node)
13671 {
13672   guint16 y;
13673   GDate *date;
13674   gint len;
13675
13676   len = QT_UINT32 (node->data);
13677   if (len < 14)
13678     return;
13679
13680   y = QT_UINT16 ((guint8 *) node->data + 12);
13681   if (y == 0) {
13682     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
13683     return;
13684   }
13685   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
13686
13687   date = g_date_new_dmy (1, 1, y);
13688   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13689   g_date_free (date);
13690 }
13691
13692 static void
13693 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
13694     const char *tag, const char *dummy, GNode * node)
13695 {
13696   int offset;
13697   char *tag_str = NULL;
13698   guint8 *entity;
13699   guint16 table;
13700   gint len;
13701
13702   len = QT_UINT32 (node->data);
13703   if (len <= 20)
13704     goto short_read;
13705
13706   offset = 12;
13707   entity = (guint8 *) node->data + offset;
13708   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
13709     GST_DEBUG_OBJECT (qtdemux,
13710         "classification info: %c%c%c%c invalid classification entity",
13711         entity[0], entity[1], entity[2], entity[3]);
13712     return;
13713   }
13714
13715   offset += 4;
13716   table = QT_UINT16 ((guint8 *) node->data + offset);
13717
13718   /* Language code skipped */
13719
13720   offset += 4;
13721
13722   /* Tag format: "XXXX://Y[YYYY]/classification info string"
13723    * XXXX: classification entity, fixed length 4 chars.
13724    * Y[YYYY]: classification table, max 5 chars.
13725    */
13726   tag_str = g_strdup_printf ("----://%u/%s",
13727       table, (char *) node->data + offset);
13728
13729   /* memcpy To be sure we're preserving byte order */
13730   memcpy (tag_str, entity, 4);
13731   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
13732
13733   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
13734
13735   g_free (tag_str);
13736
13737   return;
13738
13739   /* ERRORS */
13740 short_read:
13741   {
13742     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
13743     return;
13744   }
13745 }
13746
13747 static gboolean
13748 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
13749     const char *tag, const char *dummy, GNode * node)
13750 {
13751   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13752   GNode *data;
13753   char *s;
13754   int len;
13755   guint32 type;
13756   int offset;
13757   gboolean ret = TRUE;
13758   const gchar *charset = NULL;
13759
13760   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13761   if (data) {
13762     len = QT_UINT32 (data->data);
13763     type = QT_UINT32 ((guint8 *) data->data + 8);
13764     if (type == 0x00000001 && len > 16) {
13765       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
13766           env_vars);
13767       if (s) {
13768         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13769         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13770         g_free (s);
13771       } else {
13772         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13773       }
13774     }
13775   } else {
13776     len = QT_UINT32 (node->data);
13777     type = QT_UINT32 ((guint8 *) node->data + 4);
13778     if ((type >> 24) == 0xa9 && len > 8 + 4) {
13779       gint str_len;
13780       gint lang_code;
13781
13782       /* Type starts with the (C) symbol, so the next data is a list
13783        * of (string size(16), language code(16), string) */
13784
13785       str_len = QT_UINT16 ((guint8 *) node->data + 8);
13786       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
13787
13788       /* the string + fourcc + size + 2 16bit fields,
13789        * means that there are more tags in this atom */
13790       if (len > str_len + 8 + 4) {
13791         /* TODO how to represent the same tag in different languages? */
13792         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
13793             "text alternatives, reading only first one");
13794       }
13795
13796       offset = 12;
13797       len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
13798       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
13799
13800       if (lang_code < 0x800) {  /* MAC encoded string */
13801         charset = "mac";
13802       }
13803     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
13804             QT_FOURCC ((guint8 *) node->data + 4))) {
13805       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
13806
13807       /* we go for 3GP style encoding if major brands claims so,
13808        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
13809       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13810           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
13811               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
13812         offset = 14;
13813         /* 16-bit Language code is ignored here as well */
13814         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
13815       } else {
13816         goto normal;
13817       }
13818     } else {
13819     normal:
13820       offset = 8;
13821       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
13822       ret = FALSE;              /* may have to fallback */
13823     }
13824     if (charset) {
13825       GError *err = NULL;
13826
13827       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
13828           charset, NULL, NULL, &err);
13829       if (err) {
13830         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
13831             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
13832             err->message);
13833         g_error_free (err);
13834       }
13835     } else {
13836       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13837           len - offset, env_vars);
13838     }
13839     if (s) {
13840       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
13841       gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
13842       g_free (s);
13843       ret = TRUE;
13844     } else {
13845       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
13846     }
13847   }
13848   return ret;
13849 }
13850
13851 static void
13852 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
13853     const char *tag, const char *dummy, GNode * node)
13854 {
13855   qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
13856 }
13857
13858 static void
13859 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
13860     const char *tag, const char *dummy, GNode * node)
13861 {
13862   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
13863   guint8 *data;
13864   char *s, *t, *k = NULL;
13865   int len;
13866   int offset;
13867   int count;
13868
13869   /* first try normal string tag if major brand not 3GP */
13870   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
13871     if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
13872       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
13873        * let's try it 3gpp way after minor safety check */
13874       data = node->data;
13875       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
13876         return;
13877     } else
13878       return;
13879   }
13880
13881   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
13882
13883   data = node->data;
13884
13885   len = QT_UINT32 (data);
13886   if (len < 15)
13887     goto short_read;
13888
13889   count = QT_UINT8 (data + 14);
13890   offset = 15;
13891   for (; count; count--) {
13892     gint slen;
13893
13894     if (offset + 1 > len)
13895       goto short_read;
13896     slen = QT_UINT8 (data + offset);
13897     offset += 1;
13898     if (offset + slen > len)
13899       goto short_read;
13900     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
13901         slen, env_vars);
13902     if (s) {
13903       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
13904       if (k) {
13905         t = g_strjoin (",", k, s, NULL);
13906         g_free (s);
13907         g_free (k);
13908         k = t;
13909       } else {
13910         k = s;
13911       }
13912     } else {
13913       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
13914     }
13915     offset += slen;
13916   }
13917
13918 done:
13919   if (k) {
13920     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
13921     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
13922   }
13923   g_free (k);
13924
13925   return;
13926
13927   /* ERRORS */
13928 short_read:
13929   {
13930     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
13931     goto done;
13932   }
13933 }
13934
13935 static void
13936 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
13937     const char *tag1, const char *tag2, GNode * node)
13938 {
13939   GNode *data;
13940   int len;
13941   int type;
13942   int n1, n2;
13943
13944   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13945   if (data) {
13946     len = QT_UINT32 (data->data);
13947     type = QT_UINT32 ((guint8 *) data->data + 8);
13948     if (type == 0x00000000 && len >= 22) {
13949       n1 = QT_UINT16 ((guint8 *) data->data + 18);
13950       n2 = QT_UINT16 ((guint8 *) data->data + 20);
13951       if (n1 > 0) {
13952         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
13953         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
13954       }
13955       if (n2 > 0) {
13956         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
13957         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
13958       }
13959     }
13960   }
13961 }
13962
13963 static void
13964 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
13965     const char *tag1, const char *dummy, GNode * node)
13966 {
13967   GNode *data;
13968   int len;
13969   int type;
13970   int n1;
13971
13972   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13973   if (data) {
13974     len = QT_UINT32 (data->data);
13975     type = QT_UINT32 ((guint8 *) data->data + 8);
13976     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
13977     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
13978     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
13979       n1 = QT_UINT16 ((guint8 *) data->data + 16);
13980       if (n1) {
13981         /* do not add bpm=0 */
13982         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
13983         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
13984             NULL);
13985       }
13986     }
13987   }
13988 }
13989
13990 static void
13991 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
13992     const char *tag1, const char *dummy, GNode * node)
13993 {
13994   GNode *data;
13995   int len;
13996   int type;
13997   guint32 num;
13998
13999   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14000   if (data) {
14001     len = QT_UINT32 (data->data);
14002     type = QT_UINT32 ((guint8 *) data->data + 8);
14003     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
14004     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
14005     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
14006       num = QT_UINT32 ((guint8 *) data->data + 16);
14007       if (num) {
14008         /* do not add num=0 */
14009         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
14010         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
14011       }
14012     }
14013   }
14014 }
14015
14016 static void
14017 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
14018     const char *tag1, const char *dummy, GNode * node)
14019 {
14020   GNode *data;
14021   int len;
14022   int type;
14023   GstSample *sample;
14024
14025   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14026   if (data) {
14027     len = QT_UINT32 (data->data);
14028     type = QT_UINT32 ((guint8 *) data->data + 8);
14029     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
14030     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
14031       GstTagImageType image_type;
14032
14033       if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
14034         image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
14035       else
14036         image_type = GST_TAG_IMAGE_TYPE_NONE;
14037
14038       if ((sample =
14039               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
14040                   len - 16, image_type))) {
14041         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
14042         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
14043         gst_sample_unref (sample);
14044       }
14045     }
14046   }
14047 }
14048
14049 static void
14050 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
14051     const char *tag, const char *dummy, GNode * node)
14052 {
14053   GNode *data;
14054   GstDateTime *datetime = NULL;
14055   char *s;
14056   int len;
14057   int type;
14058
14059   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14060   if (data) {
14061     len = QT_UINT32 (data->data);
14062     type = QT_UINT32 ((guint8 *) data->data + 8);
14063     if (type == 0x00000001 && len > 16) {
14064       guint y, m = 1, d = 1;
14065       gint ret;
14066
14067       s = g_strndup ((char *) data->data + 16, len - 16);
14068       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
14069       datetime = gst_date_time_new_from_iso8601_string (s);
14070       if (datetime != NULL) {
14071         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, GST_TAG_DATE_TIME,
14072             datetime, NULL);
14073         gst_date_time_unref (datetime);
14074       }
14075
14076       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
14077       if (ret >= 1 && y > 1500 && y < 3000) {
14078         GDate *date;
14079
14080         date = g_date_new_dmy (d, m, y);
14081         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
14082         g_date_free (date);
14083       } else {
14084         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
14085       }
14086       g_free (s);
14087     }
14088   }
14089 }
14090
14091 static void
14092 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
14093     const char *tag, const char *dummy, GNode * node)
14094 {
14095   GNode *data;
14096
14097   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14098
14099   /* re-route to normal string tag if major brand says so
14100    * or no data atom and compatible brand suggests so */
14101   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
14102       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
14103     qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
14104     return;
14105   }
14106
14107   if (data) {
14108     guint len, type, n;
14109
14110     len = QT_UINT32 (data->data);
14111     type = QT_UINT32 ((guint8 *) data->data + 8);
14112     if (type == 0x00000000 && len >= 18) {
14113       n = QT_UINT16 ((guint8 *) data->data + 16);
14114       if (n > 0) {
14115         const gchar *genre;
14116
14117         genre = gst_tag_id3_genre_get (n - 1);
14118         if (genre != NULL) {
14119           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
14120           gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
14121         }
14122       }
14123     }
14124   }
14125 }
14126
14127 static void
14128 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
14129     const gchar * tag, guint8 * data, guint32 datasize)
14130 {
14131   gdouble value;
14132   gchar *datacopy;
14133
14134   /* make a copy to have \0 at the end */
14135   datacopy = g_strndup ((gchar *) data, datasize);
14136
14137   /* convert the str to double */
14138   if (sscanf (datacopy, "%lf", &value) == 1) {
14139     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
14140     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
14141   } else {
14142     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
14143         datacopy);
14144   }
14145   g_free (datacopy);
14146 }
14147
14148
14149 static void
14150 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
14151     const char *tag, const char *tag_bis, GNode * node)
14152 {
14153   GNode *mean;
14154   GNode *name;
14155   GNode *data;
14156   guint32 meansize;
14157   guint32 namesize;
14158   guint32 datatype;
14159   guint32 datasize;
14160   const gchar *meanstr;
14161   const gchar *namestr;
14162
14163   /* checking the whole ---- atom size for consistency */
14164   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
14165     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
14166     return;
14167   }
14168
14169   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
14170   if (!mean) {
14171     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
14172     return;
14173   }
14174
14175   meansize = QT_UINT32 (mean->data);
14176   if (meansize <= 12) {
14177     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
14178     return;
14179   }
14180   meanstr = ((gchar *) mean->data) + 12;
14181   meansize -= 12;
14182
14183   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
14184   if (!name) {
14185     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
14186     return;
14187   }
14188
14189   namesize = QT_UINT32 (name->data);
14190   if (namesize <= 12) {
14191     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
14192     return;
14193   }
14194   namestr = ((gchar *) name->data) + 12;
14195   namesize -= 12;
14196
14197   /*
14198    * Data atom is:
14199    * uint32 - size
14200    * uint32 - name
14201    * uint8  - version
14202    * uint24 - data type
14203    * uint32 - all 0
14204    * rest   - the data
14205    */
14206   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
14207   if (!data) {
14208     GST_WARNING_OBJECT (demux, "No data atom in this tag");
14209     return;
14210   }
14211   datasize = QT_UINT32 (data->data);
14212   if (datasize <= 16) {
14213     GST_WARNING_OBJECT (demux, "Data atom too small");
14214     return;
14215   }
14216   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
14217
14218   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
14219       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
14220     static const struct
14221     {
14222       const gchar name[28];
14223       const gchar tag[28];
14224     } tags[] = {
14225       {
14226       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
14227       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
14228       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
14229       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
14230       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
14231       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
14232       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
14233       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
14234     };
14235     int i;
14236
14237     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
14238       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
14239         switch (gst_tag_get_type (tags[i].tag)) {
14240           case G_TYPE_DOUBLE:
14241             qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
14242                 ((guint8 *) data->data) + 16, datasize - 16);
14243             break;
14244           case G_TYPE_STRING:
14245             qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
14246             break;
14247           default:
14248             /* not reached */
14249             break;
14250         }
14251         break;
14252       }
14253     }
14254     if (i == G_N_ELEMENTS (tags))
14255       goto unknown_tag;
14256   } else {
14257     goto unknown_tag;
14258   }
14259
14260   return;
14261
14262 /* errors */
14263 unknown_tag:
14264 #ifndef GST_DISABLE_GST_DEBUG
14265   {
14266     gchar *namestr_dbg;
14267     gchar *meanstr_dbg;
14268
14269     meanstr_dbg = g_strndup (meanstr, meansize);
14270     namestr_dbg = g_strndup (namestr, namesize);
14271
14272     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
14273         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
14274
14275     g_free (namestr_dbg);
14276     g_free (meanstr_dbg);
14277   }
14278 #endif
14279   return;
14280 }
14281
14282 static void
14283 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
14284     const char *tag_bis, GNode * node)
14285 {
14286   guint8 *data;
14287   GstBuffer *buf;
14288   guint len;
14289   GstTagList *id32_taglist = NULL;
14290
14291   GST_LOG_OBJECT (demux, "parsing ID32");
14292
14293   data = node->data;
14294   len = GST_READ_UINT32_BE (data);
14295
14296   /* need at least full box and language tag */
14297   if (len < 12 + 2)
14298     return;
14299
14300   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
14301   gst_buffer_fill (buf, 0, data + 14, len - 14);
14302
14303   id32_taglist = gst_tag_list_from_id3v2_tag (buf);
14304   if (id32_taglist) {
14305     GST_LOG_OBJECT (demux, "parsing ok");
14306     gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
14307     gst_tag_list_unref (id32_taglist);
14308   } else {
14309     GST_LOG_OBJECT (demux, "parsing failed");
14310   }
14311
14312   gst_buffer_unref (buf);
14313 }
14314
14315 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
14316     const char *tag, const char *tag_bis, GNode * node);
14317
14318 /* unmapped tags
14319 FOURCC_pcst -> if media is a podcast -> bool
14320 FOURCC_cpil -> if media is part of a compilation -> bool
14321 FOURCC_pgap -> if media is part of a gapless context -> bool
14322 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
14323 */
14324
14325 static const struct
14326 {
14327   guint32 fourcc;
14328   const gchar *gst_tag;
14329   const gchar *gst_tag_bis;
14330   const GstQTDemuxAddTagFunc func;
14331 } add_funcs[] = {
14332   {
14333   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
14334   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
14335   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
14336   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
14337   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
14338   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
14339   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
14340   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
14341   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
14342   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
14343   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
14344   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
14345   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
14346   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14347   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14348   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
14349   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
14350   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
14351   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
14352   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
14353   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
14354   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
14355   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
14356         qtdemux_tag_add_num}, {
14357   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
14358         qtdemux_tag_add_num}, {
14359   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
14360   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
14361   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
14362   FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
14363   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
14364   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
14365   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
14366   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
14367   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
14368   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
14369   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
14370   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
14371   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
14372   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
14373   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
14374   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
14375   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
14376   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
14377         qtdemux_tag_add_classification}, {
14378   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
14379   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
14380   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
14381
14382     /* This is a special case, some tags are stored in this
14383      * 'reverse dns naming', according to:
14384      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
14385      * bug #614471
14386      */
14387   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
14388     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
14389   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
14390 };
14391
14392 struct _GstQtDemuxTagList
14393 {
14394   GstQTDemux *demux;
14395   GstTagList *taglist;
14396 };
14397 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
14398
14399 static void
14400 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
14401 {
14402   gint len;
14403   guint8 *data;
14404   GstBuffer *buf;
14405   gchar *media_type;
14406   const gchar *style;
14407   GstSample *sample;
14408   GstStructure *s;
14409   guint i;
14410   guint8 ndata[4];
14411   GstQTDemux *demux = qtdemuxtaglist->demux;
14412   GstTagList *taglist = qtdemuxtaglist->taglist;
14413
14414   data = node->data;
14415   len = QT_UINT32 (data);
14416   buf = gst_buffer_new_and_alloc (len);
14417   gst_buffer_fill (buf, 0, data, len);
14418
14419   /* heuristic to determine style of tag */
14420   if (QT_FOURCC (data + 4) == FOURCC_____ ||
14421       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
14422     style = "itunes";
14423   else if (demux->major_brand == FOURCC_qt__)
14424     style = "quicktime";
14425   /* fall back to assuming iso/3gp tag style */
14426   else
14427     style = "iso";
14428
14429   /* santize the name for the caps. */
14430   for (i = 0; i < 4; i++) {
14431     guint8 d = data[4 + i];
14432     if (g_ascii_isalnum (d))
14433       ndata[i] = g_ascii_tolower (d);
14434     else
14435       ndata[i] = '_';
14436   }
14437
14438   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
14439       ndata[0], ndata[1], ndata[2], ndata[3]);
14440   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
14441
14442   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
14443   sample = gst_sample_new (buf, NULL, NULL, s);
14444   gst_buffer_unref (buf);
14445   g_free (media_type);
14446
14447   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
14448       len, s);
14449
14450   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
14451       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
14452
14453   gst_sample_unref (sample);
14454 }
14455
14456 static void
14457 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
14458 {
14459   GNode *meta;
14460   GNode *ilst;
14461   GNode *xmp_;
14462   GNode *node;
14463   gint i;
14464   GstQtDemuxTagList demuxtaglist;
14465
14466   demuxtaglist.demux = qtdemux;
14467   demuxtaglist.taglist = taglist;
14468
14469   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
14470   if (meta != NULL) {
14471     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
14472     if (ilst == NULL) {
14473       GST_LOG_OBJECT (qtdemux, "no ilst");
14474       return;
14475     }
14476   } else {
14477     ilst = udta;
14478     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
14479   }
14480
14481   i = 0;
14482   while (i < G_N_ELEMENTS (add_funcs)) {
14483     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
14484     if (node) {
14485       gint len;
14486
14487       len = QT_UINT32 (node->data);
14488       if (len < 12) {
14489         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
14490             GST_FOURCC_ARGS (add_funcs[i].fourcc));
14491       } else {
14492         add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
14493             add_funcs[i].gst_tag_bis, node);
14494       }
14495       g_node_destroy (node);
14496     } else {
14497       i++;
14498     }
14499   }
14500
14501   /* parsed nodes have been removed, pass along remainder as blob */
14502   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
14503       (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
14504
14505   /* parse up XMP_ node if existing */
14506   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
14507   if (xmp_ != NULL) {
14508     GstBuffer *buf;
14509     GstTagList *xmptaglist;
14510
14511     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
14512         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
14513     xmptaglist = gst_tag_list_from_xmp_buffer (buf);
14514     gst_buffer_unref (buf);
14515
14516     qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
14517   } else {
14518     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
14519   }
14520 }
14521
14522 typedef struct
14523 {
14524   GstStructure *structure;      /* helper for sort function */
14525   gchar *location;
14526   guint min_req_bitrate;
14527   guint min_req_qt_version;
14528 } GstQtReference;
14529
14530 static gint
14531 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
14532 {
14533   GstQtReference *ref_a = (GstQtReference *) a;
14534   GstQtReference *ref_b = (GstQtReference *) b;
14535
14536   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
14537     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
14538
14539   /* known bitrates go before unknown; higher bitrates go first */
14540   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
14541 }
14542
14543 /* sort the redirects and post a message for the application.
14544  */
14545 static void
14546 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
14547 {
14548   GstQtReference *best;
14549   GstStructure *s;
14550   GstMessage *msg;
14551   GValue list_val = { 0, };
14552   GList *l;
14553
14554   g_assert (references != NULL);
14555
14556   references = g_list_sort (references, qtdemux_redirects_sort_func);
14557
14558   best = (GstQtReference *) references->data;
14559
14560   g_value_init (&list_val, GST_TYPE_LIST);
14561
14562   for (l = references; l != NULL; l = l->next) {
14563     GstQtReference *ref = (GstQtReference *) l->data;
14564     GValue struct_val = { 0, };
14565
14566     ref->structure = gst_structure_new ("redirect",
14567         "new-location", G_TYPE_STRING, ref->location, NULL);
14568
14569     if (ref->min_req_bitrate > 0) {
14570       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
14571           ref->min_req_bitrate, NULL);
14572     }
14573
14574     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
14575     g_value_set_boxed (&struct_val, ref->structure);
14576     gst_value_list_append_value (&list_val, &struct_val);
14577     g_value_unset (&struct_val);
14578     /* don't free anything here yet, since we need best->structure below */
14579   }
14580
14581   g_assert (best != NULL);
14582   s = gst_structure_copy (best->structure);
14583
14584   if (g_list_length (references) > 1) {
14585     gst_structure_set_value (s, "locations", &list_val);
14586   }
14587
14588   g_value_unset (&list_val);
14589
14590   for (l = references; l != NULL; l = l->next) {
14591     GstQtReference *ref = (GstQtReference *) l->data;
14592
14593     gst_structure_free (ref->structure);
14594     g_free (ref->location);
14595     g_free (ref);
14596   }
14597   g_list_free (references);
14598
14599   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
14600   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
14601   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
14602   qtdemux->posted_redirect = TRUE;
14603 }
14604
14605 /* look for redirect nodes, collect all redirect information and
14606  * process it.
14607  */
14608 static gboolean
14609 qtdemux_parse_redirects (GstQTDemux * qtdemux)
14610 {
14611   GNode *rmra, *rmda, *rdrf;
14612
14613   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
14614   if (rmra) {
14615     GList *redirects = NULL;
14616
14617     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
14618     while (rmda) {
14619       GstQtReference ref = { NULL, NULL, 0, 0 };
14620       GNode *rmdr, *rmvc;
14621
14622       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
14623         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
14624         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
14625             ref.min_req_bitrate);
14626       }
14627
14628       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
14629         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
14630         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
14631
14632 #ifndef GST_DISABLE_GST_DEBUG
14633         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
14634 #endif
14635         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
14636
14637         GST_LOG_OBJECT (qtdemux,
14638             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
14639             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
14640             bitmask, check_type);
14641         if (package == FOURCC_qtim && check_type == 0) {
14642           ref.min_req_qt_version = version;
14643         }
14644       }
14645
14646       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
14647       if (rdrf) {
14648         guint32 ref_type;
14649         guint8 *ref_data;
14650         guint ref_len;
14651
14652         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
14653         if (ref_len > 20) {
14654           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
14655           ref_data = (guint8 *) rdrf->data + 20;
14656           if (ref_type == FOURCC_alis) {
14657             guint record_len, record_version, fn_len;
14658
14659             if (ref_len > 70) {
14660               /* MacOSX alias record, google for alias-layout.txt */
14661               record_len = QT_UINT16 (ref_data + 4);
14662               record_version = QT_UINT16 (ref_data + 4 + 2);
14663               fn_len = QT_UINT8 (ref_data + 50);
14664               if (record_len > 50 && record_version == 2 && fn_len > 0) {
14665                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
14666               }
14667             } else {
14668               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
14669                   ref_len);
14670             }
14671           } else if (ref_type == FOURCC_url_) {
14672             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
14673           } else {
14674             GST_DEBUG_OBJECT (qtdemux,
14675                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
14676                 GST_FOURCC_ARGS (ref_type));
14677           }
14678           if (ref.location != NULL) {
14679             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
14680             redirects =
14681                 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
14682           } else {
14683             GST_WARNING_OBJECT (qtdemux,
14684                 "Failed to extract redirect location from rdrf atom");
14685           }
14686         } else {
14687           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
14688         }
14689       }
14690
14691       /* look for others */
14692       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
14693     }
14694
14695     if (redirects != NULL) {
14696       qtdemux_process_redirects (qtdemux, redirects);
14697     }
14698   }
14699   return TRUE;
14700 }
14701
14702 static GstTagList *
14703 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
14704 {
14705   const gchar *fmt;
14706
14707   if (tags == NULL) {
14708     tags = gst_tag_list_new_empty ();
14709     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
14710   }
14711
14712   if (qtdemux->major_brand == FOURCC_mjp2)
14713     fmt = "Motion JPEG 2000";
14714   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
14715     fmt = "3GP";
14716   else if (qtdemux->major_brand == FOURCC_qt__)
14717     fmt = "Quicktime";
14718   else if (qtdemux->fragmented)
14719     fmt = "ISO fMP4";
14720   else
14721     fmt = "ISO MP4/M4A";
14722
14723   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
14724       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
14725
14726   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
14727       fmt, NULL);
14728
14729   return tags;
14730 }
14731
14732 /* we have read the complete moov node now.
14733  * This function parses all of the relevant info, creates the traks and
14734  * prepares all data structures for playback
14735  */
14736 static gboolean
14737 qtdemux_parse_tree (GstQTDemux * qtdemux)
14738 {
14739   GNode *mvhd;
14740   GNode *trak;
14741   GNode *udta;
14742   GNode *mvex;
14743   GNode *pssh;
14744   guint64 creation_time;
14745   GstDateTime *datetime = NULL;
14746   gint version;
14747
14748   /* make sure we have a usable taglist */
14749   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14750
14751   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
14752   if (mvhd == NULL) {
14753     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
14754     return qtdemux_parse_redirects (qtdemux);
14755   }
14756
14757   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
14758   if (version == 1) {
14759     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
14760     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
14761     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
14762   } else if (version == 0) {
14763     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
14764     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
14765     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
14766   } else {
14767     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
14768     return FALSE;
14769   }
14770
14771   /* Moving qt creation time (secs since 1904) to unix time */
14772   if (creation_time != 0) {
14773     /* Try to use epoch first as it should be faster and more commonly found */
14774     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
14775       GTimeVal now;
14776
14777       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
14778       /* some data cleansing sanity */
14779       g_get_current_time (&now);
14780       if (now.tv_sec + 24 * 3600 < creation_time) {
14781         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
14782       } else {
14783         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
14784       }
14785     } else {
14786       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
14787       GDateTime *dt, *dt_local;
14788
14789       dt = g_date_time_add_seconds (base_dt, creation_time);
14790       dt_local = g_date_time_to_local (dt);
14791       datetime = gst_date_time_new_from_g_date_time (dt_local);
14792
14793       g_date_time_unref (base_dt);
14794       g_date_time_unref (dt);
14795     }
14796   }
14797   if (datetime) {
14798     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
14799     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
14800         datetime, NULL);
14801     gst_date_time_unref (datetime);
14802   }
14803
14804   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
14805   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
14806
14807   /* check for fragmented file and get some (default) data */
14808   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
14809   if (mvex) {
14810     GNode *mehd;
14811     GstByteReader mehd_data;
14812
14813     /* let track parsing or anyone know weird stuff might happen ... */
14814     qtdemux->fragmented = TRUE;
14815
14816     /* compensate for total duration */
14817     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
14818     if (mehd)
14819       qtdemux_parse_mehd (qtdemux, &mehd_data);
14820   }
14821
14822   /* Update the movie segment duration, unless it was directly given to us
14823    * by upstream. Otherwise let it as is, as we don't want to mangle the
14824    * duration provided by upstream that may come e.g. from a MPD file. */
14825   if (!qtdemux->upstream_format_is_time) {
14826     GstClockTime duration;
14827     /* set duration in the segment info */
14828     gst_qtdemux_get_duration (qtdemux, &duration);
14829     qtdemux->segment.duration = duration;
14830     /* also do not exceed duration; stop is set that way post seek anyway,
14831      * and segment activation falls back to duration,
14832      * whereas loop only checks stop, so let's align this here as well */
14833     qtdemux->segment.stop = duration;
14834   }
14835
14836   /* parse all traks */
14837   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
14838   while (trak) {
14839     qtdemux_parse_trak (qtdemux, trak);
14840     /* iterate all siblings */
14841     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
14842   }
14843
14844   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
14845
14846   /* find tags */
14847   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
14848   if (udta) {
14849     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14850   } else {
14851     GST_LOG_OBJECT (qtdemux, "No udta node found.");
14852   }
14853
14854   /* maybe also some tags in meta box */
14855   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
14856   if (udta) {
14857     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
14858     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
14859   } else {
14860     GST_LOG_OBJECT (qtdemux, "No meta node found.");
14861   }
14862
14863   /* parse any protection system info */
14864   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
14865   while (pssh) {
14866     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
14867     qtdemux_parse_pssh (qtdemux, pssh);
14868     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
14869   }
14870
14871   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
14872
14873   return TRUE;
14874 }
14875
14876 /* taken from ffmpeg */
14877 static int
14878 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
14879 {
14880   int count = 4;
14881   int len = 0;
14882
14883   while (count--) {
14884     int c;
14885
14886     if (ptr >= end)
14887       return -1;
14888
14889     c = *ptr++;
14890     len = (len << 7) | (c & 0x7f);
14891     if (!(c & 0x80))
14892       break;
14893   }
14894   *end_out = ptr;
14895   return len;
14896 }
14897
14898 static GList *
14899 parse_xiph_stream_headers (GstQTDemux * qtdemux, gpointer codec_data,
14900     gsize codec_data_size)
14901 {
14902   GList *list = NULL;
14903   guint8 *p = codec_data;
14904   gint i, offset, num_packets;
14905   guint *length, last;
14906
14907   GST_MEMDUMP_OBJECT (qtdemux, "xiph codec data", codec_data, codec_data_size);
14908
14909   if (codec_data == NULL || codec_data_size == 0)
14910     goto error;
14911
14912   /* start of the stream and vorbis audio or theora video, need to
14913    * send the codec_priv data as first three packets */
14914   num_packets = p[0] + 1;
14915   GST_DEBUG_OBJECT (qtdemux,
14916       "%u stream headers, total length=%" G_GSIZE_FORMAT " bytes",
14917       (guint) num_packets, codec_data_size);
14918
14919   /* Let's put some limits, Don't think there even is a xiph codec
14920    * with more than 3-4 headers */
14921   if (G_UNLIKELY (num_packets > 16)) {
14922     GST_WARNING_OBJECT (qtdemux,
14923         "Unlikely number of xiph headers, most likely not valid");
14924     goto error;
14925   }
14926
14927   length = g_alloca (num_packets * sizeof (guint));
14928   last = 0;
14929   offset = 1;
14930
14931   /* first packets, read length values */
14932   for (i = 0; i < num_packets - 1; i++) {
14933     length[i] = 0;
14934     while (offset < codec_data_size) {
14935       length[i] += p[offset];
14936       if (p[offset++] != 0xff)
14937         break;
14938     }
14939     last += length[i];
14940   }
14941   if (offset + last > codec_data_size)
14942     goto error;
14943
14944   /* last packet is the remaining size */
14945   length[i] = codec_data_size - offset - last;
14946
14947   for (i = 0; i < num_packets; i++) {
14948     GstBuffer *hdr;
14949
14950     GST_DEBUG_OBJECT (qtdemux, "buffer %d: %u bytes", i, (guint) length[i]);
14951
14952     if (offset + length[i] > codec_data_size)
14953       goto error;
14954
14955     hdr = gst_buffer_new_wrapped (g_memdup (p + offset, length[i]), length[i]);
14956     list = g_list_append (list, hdr);
14957
14958     offset += length[i];
14959   }
14960
14961   return list;
14962
14963   /* ERRORS */
14964 error:
14965   {
14966     if (list != NULL)
14967       g_list_free_full (list, (GDestroyNotify) gst_buffer_unref);
14968     return NULL;
14969   }
14970
14971 }
14972
14973 /* this can change the codec originally present in @list */
14974 static void
14975 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
14976     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
14977 {
14978   int len = QT_UINT32 (esds->data);
14979   guint8 *ptr = esds->data;
14980   guint8 *end = ptr + len;
14981   int tag;
14982   guint8 *data_ptr = NULL;
14983   int data_len = 0;
14984   guint8 object_type_id = 0;
14985   guint8 stream_type = 0;
14986   const char *codec_name = NULL;
14987   GstCaps *caps = NULL;
14988
14989   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
14990   ptr += 8;
14991   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
14992   ptr += 4;
14993   while (ptr + 1 < end) {
14994     tag = QT_UINT8 (ptr);
14995     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
14996     ptr++;
14997     len = read_descr_size (ptr, end, &ptr);
14998     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
14999
15000     /* Check the stated amount of data is available for reading */
15001     if (len < 0 || ptr + len > end)
15002       break;
15003
15004     switch (tag) {
15005       case ES_DESCRIPTOR_TAG:
15006         GST_DEBUG_OBJECT (qtdemux, "ID 0x%04x", QT_UINT16 (ptr));
15007         GST_DEBUG_OBJECT (qtdemux, "priority 0x%04x", QT_UINT8 (ptr + 2));
15008         ptr += 3;
15009         break;
15010       case DECODER_CONFIG_DESC_TAG:{
15011         guint max_bitrate, avg_bitrate;
15012
15013         object_type_id = QT_UINT8 (ptr);
15014         stream_type = QT_UINT8 (ptr + 1) >> 2;
15015         max_bitrate = QT_UINT32 (ptr + 5);
15016         avg_bitrate = QT_UINT32 (ptr + 9);
15017         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
15018         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", stream_type);
15019         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
15020         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
15021         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
15022         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
15023           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
15024               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
15025         }
15026         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
15027           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
15028               avg_bitrate, NULL);
15029         }
15030         ptr += 13;
15031         break;
15032       }
15033       case DECODER_SPECIFIC_INFO_TAG:
15034         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
15035         if (object_type_id == 0xe0 && len == 0x40) {
15036           guint8 *data;
15037           GstStructure *s;
15038           guint32 clut[16];
15039           gint i;
15040
15041           GST_DEBUG_OBJECT (qtdemux,
15042               "Have VOBSUB palette. Creating palette event");
15043           /* move to decConfigDescr data and read palette */
15044           data = ptr;
15045           for (i = 0; i < 16; i++) {
15046             clut[i] = QT_UINT32 (data);
15047             data += 4;
15048           }
15049
15050           s = gst_structure_new ("application/x-gst-dvd", "event",
15051               G_TYPE_STRING, "dvd-spu-clut-change",
15052               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
15053               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
15054               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
15055               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
15056               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
15057               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
15058               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
15059               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
15060               NULL);
15061
15062           /* store event and trigger custom processing */
15063           stream->pending_event =
15064               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
15065         } else {
15066           /* Generic codec_data handler puts it on the caps */
15067           data_ptr = ptr;
15068           data_len = len;
15069         }
15070
15071         ptr += len;
15072         break;
15073       case SL_CONFIG_DESC_TAG:
15074         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
15075         ptr += 1;
15076         break;
15077       default:
15078         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
15079             tag);
15080         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
15081         ptr += len;
15082         break;
15083     }
15084   }
15085
15086   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
15087    * in use, and should also be used to override some other parameters for some
15088    * codecs. */
15089   switch (object_type_id) {
15090     case 0x20:                 /* MPEG-4 */
15091       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
15092        * profile_and_level_indication */
15093       if (data_ptr != NULL && data_len >= 5 &&
15094           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
15095         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
15096             data_ptr + 4, data_len - 4);
15097       }
15098       break;                    /* Nothing special needed here */
15099     case 0x21:                 /* H.264 */
15100       codec_name = "H.264 / AVC";
15101       caps = gst_caps_new_simple ("video/x-h264",
15102           "stream-format", G_TYPE_STRING, "avc",
15103           "alignment", G_TYPE_STRING, "au", NULL);
15104       break;
15105     case 0x40:                 /* AAC (any) */
15106     case 0x66:                 /* AAC Main */
15107     case 0x67:                 /* AAC LC */
15108     case 0x68:                 /* AAC SSR */
15109       /* Override channels and rate based on the codec_data, as it's often
15110        * wrong. */
15111       /* Only do so for basic setup without HE-AAC extension */
15112       if (data_ptr && data_len == 2) {
15113         guint channels, rate;
15114
15115         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
15116         if (channels > 0)
15117           entry->n_channels = channels;
15118
15119         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
15120         if (rate > 0)
15121           entry->rate = rate;
15122       }
15123
15124       /* Set level and profile if possible */
15125       if (data_ptr != NULL && data_len >= 2) {
15126         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
15127             data_ptr, data_len);
15128       } else {
15129         const gchar *profile_str = NULL;
15130         GstBuffer *buffer;
15131         GstMapInfo map;
15132         guint8 *codec_data;
15133         gint rate_idx, profile;
15134
15135         /* No codec_data, let's invent something.
15136          * FIXME: This is wrong for SBR! */
15137
15138         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
15139
15140         buffer = gst_buffer_new_and_alloc (2);
15141         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
15142         codec_data = map.data;
15143
15144         rate_idx =
15145             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
15146             (stream)->rate);
15147
15148         switch (object_type_id) {
15149           case 0x66:
15150             profile_str = "main";
15151             profile = 0;
15152             break;
15153           case 0x67:
15154             profile_str = "lc";
15155             profile = 1;
15156             break;
15157           case 0x68:
15158             profile_str = "ssr";
15159             profile = 2;
15160             break;
15161           default:
15162             profile = 3;
15163             break;
15164         }
15165
15166         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
15167         codec_data[1] =
15168             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
15169
15170         gst_buffer_unmap (buffer, &map);
15171         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
15172             GST_TYPE_BUFFER, buffer, NULL);
15173         gst_buffer_unref (buffer);
15174
15175         if (profile_str) {
15176           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
15177               G_TYPE_STRING, profile_str, NULL);
15178         }
15179       }
15180       break;
15181     case 0x60:                 /* MPEG-2, various profiles */
15182     case 0x61:
15183     case 0x62:
15184     case 0x63:
15185     case 0x64:
15186     case 0x65:
15187       codec_name = "MPEG-2 video";
15188       caps = gst_caps_new_simple ("video/mpeg",
15189           "mpegversion", G_TYPE_INT, 2,
15190           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15191       break;
15192     case 0x69:                 /* MPEG-2 BC audio */
15193     case 0x6B:                 /* MPEG-1 audio */
15194       caps = gst_caps_new_simple ("audio/mpeg",
15195           "mpegversion", G_TYPE_INT, 1, NULL);
15196       codec_name = "MPEG-1 audio";
15197       break;
15198     case 0x6A:                 /* MPEG-1 */
15199       codec_name = "MPEG-1 video";
15200       caps = gst_caps_new_simple ("video/mpeg",
15201           "mpegversion", G_TYPE_INT, 1,
15202           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15203       break;
15204     case 0x6C:                 /* MJPEG */
15205       caps =
15206           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15207           NULL);
15208       codec_name = "Motion-JPEG";
15209       break;
15210     case 0x6D:                 /* PNG */
15211       caps =
15212           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
15213           NULL);
15214       codec_name = "PNG still images";
15215       break;
15216     case 0x6E:                 /* JPEG2000 */
15217       codec_name = "JPEG-2000";
15218       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15219       break;
15220     case 0xA4:                 /* Dirac */
15221       codec_name = "Dirac";
15222       caps = gst_caps_new_empty_simple ("video/x-dirac");
15223       break;
15224     case 0xA5:                 /* AC3 */
15225       codec_name = "AC-3 audio";
15226       caps = gst_caps_new_simple ("audio/x-ac3",
15227           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15228       break;
15229     case 0xA9:                 /* AC3 */
15230       codec_name = "DTS audio";
15231       caps = gst_caps_new_simple ("audio/x-dts",
15232           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15233       break;
15234     case 0xDD:
15235       if (stream_type == 0x05 && data_ptr) {
15236         GList *headers =
15237             parse_xiph_stream_headers (qtdemux, data_ptr, data_len);
15238         if (headers) {
15239           GList *tmp;
15240           GValue arr_val = G_VALUE_INIT;
15241           GValue buf_val = G_VALUE_INIT;
15242           GstStructure *s;
15243
15244           /* Let's assume it's vorbis if it's an audio stream of type 0xdd and we have codec data that extracts properly */
15245           codec_name = "Vorbis";
15246           caps = gst_caps_new_empty_simple ("audio/x-vorbis");
15247           g_value_init (&arr_val, GST_TYPE_ARRAY);
15248           g_value_init (&buf_val, GST_TYPE_BUFFER);
15249           for (tmp = headers; tmp; tmp = tmp->next) {
15250             g_value_set_boxed (&buf_val, (GstBuffer *) tmp->data);
15251             gst_value_array_append_value (&arr_val, &buf_val);
15252           }
15253           s = gst_caps_get_structure (caps, 0);
15254           gst_structure_take_value (s, "streamheader", &arr_val);
15255           g_value_unset (&buf_val);
15256           g_list_free (headers);
15257
15258           data_ptr = NULL;
15259           data_len = 0;
15260         }
15261       }
15262       break;
15263     case 0xE1:                 /* QCELP */
15264       /* QCELP, the codec_data is a riff tag (little endian) with
15265        * 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). */
15266       caps = gst_caps_new_empty_simple ("audio/qcelp");
15267       codec_name = "QCELP";
15268       break;
15269     default:
15270       break;
15271   }
15272
15273   /* If we have a replacement caps, then change our caps for this stream */
15274   if (caps) {
15275     gst_caps_unref (entry->caps);
15276     entry->caps = caps;
15277   }
15278
15279   if (codec_name && list)
15280     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
15281         GST_TAG_AUDIO_CODEC, codec_name, NULL);
15282
15283   /* Add the codec_data attribute to caps, if we have it */
15284   if (data_ptr) {
15285     GstBuffer *buffer;
15286
15287     buffer = gst_buffer_new_and_alloc (data_len);
15288     gst_buffer_fill (buffer, 0, data_ptr, data_len);
15289
15290     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
15291     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
15292
15293     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
15294         buffer, NULL);
15295     gst_buffer_unref (buffer);
15296   }
15297
15298 }
15299
15300 static inline GstCaps *
15301 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
15302 {
15303   GstCaps *caps;
15304   guint i;
15305   char *s, fourstr[5];
15306
15307   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
15308   for (i = 0; i < 4; i++) {
15309     if (!g_ascii_isalnum (fourstr[i]))
15310       fourstr[i] = '_';
15311   }
15312   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
15313   caps = gst_caps_new_empty_simple (s);
15314   g_free (s);
15315   return caps;
15316 }
15317
15318 #define _codec(name) \
15319   do { \
15320     if (codec_name) { \
15321       *codec_name = g_strdup (name); \
15322     } \
15323   } while (0)
15324
15325 static GstCaps *
15326 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15327     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
15328     const guint8 * stsd_entry_data, gchar ** codec_name)
15329 {
15330   GstCaps *caps = NULL;
15331   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
15332
15333   switch (fourcc) {
15334     case FOURCC_png:
15335       _codec ("PNG still images");
15336       caps = gst_caps_new_empty_simple ("image/png");
15337       break;
15338     case FOURCC_jpeg:
15339       _codec ("JPEG still images");
15340       caps =
15341           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15342           NULL);
15343       break;
15344     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
15345     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
15346     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
15347     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
15348       _codec ("Motion-JPEG");
15349       caps =
15350           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
15351           NULL);
15352       break;
15353     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
15354       _codec ("Motion-JPEG format B");
15355       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
15356       break;
15357     case FOURCC_mjp2:
15358       _codec ("JPEG-2000");
15359       /* override to what it should be according to spec, avoid palette_data */
15360       entry->bits_per_sample = 24;
15361       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
15362       break;
15363     case FOURCC_SVQ3:
15364       _codec ("Sorensen video v.3");
15365       caps = gst_caps_new_simple ("video/x-svq",
15366           "svqversion", G_TYPE_INT, 3, NULL);
15367       break;
15368     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
15369     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
15370       _codec ("Sorensen video v.1");
15371       caps = gst_caps_new_simple ("video/x-svq",
15372           "svqversion", G_TYPE_INT, 1, NULL);
15373       break;
15374     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
15375       caps = gst_caps_new_empty_simple ("video/x-raw");
15376       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
15377       _codec ("Windows Raw RGB");
15378       stream->alignment = 32;
15379       break;
15380     case FOURCC_raw_:
15381     {
15382       guint16 bps;
15383
15384       bps = QT_UINT16 (stsd_entry_data + 82);
15385       switch (bps) {
15386         case 15:
15387           format = GST_VIDEO_FORMAT_RGB15;
15388           break;
15389         case 16:
15390           format = GST_VIDEO_FORMAT_RGB16;
15391           break;
15392         case 24:
15393           format = GST_VIDEO_FORMAT_RGB;
15394           break;
15395         case 32:
15396           format = GST_VIDEO_FORMAT_ARGB;
15397           break;
15398         default:
15399           /* unknown */
15400           break;
15401       }
15402       break;
15403     }
15404     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
15405       format = GST_VIDEO_FORMAT_I420;
15406       break;
15407     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
15408     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
15409       format = GST_VIDEO_FORMAT_I420;
15410       break;
15411     case FOURCC_2vuy:
15412     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
15413       format = GST_VIDEO_FORMAT_UYVY;
15414       break;
15415     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
15416       format = GST_VIDEO_FORMAT_v308;
15417       break;
15418     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
15419       format = GST_VIDEO_FORMAT_v216;
15420       break;
15421     case FOURCC_v210:
15422       format = GST_VIDEO_FORMAT_v210;
15423       break;
15424     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
15425       format = GST_VIDEO_FORMAT_r210;
15426       break;
15427       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
15428          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
15429          format = GST_VIDEO_FORMAT_v410;
15430          break;
15431        */
15432       /* Packed YUV 4:4:4:4 8 bit in 32 bits
15433        * but different order than AYUV
15434        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
15435        format = GST_VIDEO_FORMAT_v408;
15436        break;
15437        */
15438     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
15439     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
15440       _codec ("MPEG-1 video");
15441       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
15442           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15443       break;
15444     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
15445     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
15446     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
15447     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
15448     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
15449     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
15450     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
15451     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
15452     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
15453     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
15454     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
15455     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
15456     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
15457     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
15458     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
15459     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
15460     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
15461     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
15462     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
15463     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
15464     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
15465     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
15466     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
15467     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
15468     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
15469     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
15470     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
15471     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
15472     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
15473     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
15474     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
15475     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
15476     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
15477     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
15478     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
15479     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
15480     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15481     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
15482     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
15483     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
15484     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
15485     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
15486     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
15487     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
15488     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
15489     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
15490     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
15491       _codec ("MPEG-2 video");
15492       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
15493           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15494       break;
15495     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
15496       _codec ("GIF still images");
15497       caps = gst_caps_new_empty_simple ("image/gif");
15498       break;
15499     case FOURCC_h263:
15500     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
15501     case FOURCC_s263:
15502     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
15503       _codec ("H.263");
15504       /* ffmpeg uses the height/width props, don't know why */
15505       caps = gst_caps_new_simple ("video/x-h263",
15506           "variant", G_TYPE_STRING, "itu", NULL);
15507       break;
15508     case FOURCC_mp4v:
15509     case FOURCC_MP4V:
15510       _codec ("MPEG-4 video");
15511       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15512           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15513       break;
15514     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
15515     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
15516       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
15517       caps = gst_caps_new_simple ("video/x-msmpeg",
15518           "msmpegversion", G_TYPE_INT, 43, NULL);
15519       break;
15520     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
15521       _codec ("DivX 3");
15522       caps = gst_caps_new_simple ("video/x-divx",
15523           "divxversion", G_TYPE_INT, 3, NULL);
15524       break;
15525     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
15526     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
15527       _codec ("DivX 4");
15528       caps = gst_caps_new_simple ("video/x-divx",
15529           "divxversion", G_TYPE_INT, 4, NULL);
15530       break;
15531     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
15532       _codec ("DivX 5");
15533       caps = gst_caps_new_simple ("video/x-divx",
15534           "divxversion", G_TYPE_INT, 5, NULL);
15535       break;
15536
15537     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
15538       _codec ("FFV1");
15539       caps = gst_caps_new_simple ("video/x-ffv",
15540           "ffvversion", G_TYPE_INT, 1, NULL);
15541       break;
15542
15543     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
15544     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
15545     case FOURCC_XVID:
15546     case FOURCC_xvid:
15547     case FOURCC_FMP4:
15548     case FOURCC_fmp4:
15549     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
15550       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
15551           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15552       _codec ("MPEG-4");
15553       break;
15554
15555     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
15556       _codec ("Cinepak");
15557       caps = gst_caps_new_empty_simple ("video/x-cinepak");
15558       break;
15559     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
15560       _codec ("Apple QuickDraw");
15561       caps = gst_caps_new_empty_simple ("video/x-qdrw");
15562       break;
15563     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
15564       _codec ("Apple video");
15565       caps = gst_caps_new_empty_simple ("video/x-apple-video");
15566       break;
15567     case FOURCC_H264:
15568     case FOURCC_avc1:
15569       _codec ("H.264 / AVC");
15570       caps = gst_caps_new_simple ("video/x-h264",
15571           "stream-format", G_TYPE_STRING, "avc",
15572           "alignment", G_TYPE_STRING, "au", NULL);
15573       break;
15574     case FOURCC_avc3:
15575       _codec ("H.264 / AVC");
15576       caps = gst_caps_new_simple ("video/x-h264",
15577           "stream-format", G_TYPE_STRING, "avc3",
15578           "alignment", G_TYPE_STRING, "au", NULL);
15579       break;
15580     case FOURCC_H265:
15581     case FOURCC_hvc1:
15582       _codec ("H.265 / HEVC");
15583       caps = gst_caps_new_simple ("video/x-h265",
15584           "stream-format", G_TYPE_STRING, "hvc1",
15585           "alignment", G_TYPE_STRING, "au", NULL);
15586       break;
15587     case FOURCC_hev1:
15588       _codec ("H.265 / HEVC");
15589       caps = gst_caps_new_simple ("video/x-h265",
15590           "stream-format", G_TYPE_STRING, "hev1",
15591           "alignment", G_TYPE_STRING, "au", NULL);
15592       break;
15593     case FOURCC_rle_:
15594       _codec ("Run-length encoding");
15595       caps = gst_caps_new_simple ("video/x-rle",
15596           "layout", G_TYPE_STRING, "quicktime", NULL);
15597       break;
15598     case FOURCC_WRLE:
15599       _codec ("Run-length encoding");
15600       caps = gst_caps_new_simple ("video/x-rle",
15601           "layout", G_TYPE_STRING, "microsoft", NULL);
15602       break;
15603     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
15604     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
15605       _codec ("Indeo Video 3");
15606       caps = gst_caps_new_simple ("video/x-indeo",
15607           "indeoversion", G_TYPE_INT, 3, NULL);
15608       break;
15609     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
15610     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
15611       _codec ("Intel Video 4");
15612       caps = gst_caps_new_simple ("video/x-indeo",
15613           "indeoversion", G_TYPE_INT, 4, NULL);
15614       break;
15615     case FOURCC_dvcp:
15616     case FOURCC_dvc_:
15617     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
15618     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
15619     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
15620     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
15621     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
15622     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
15623       _codec ("DV Video");
15624       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
15625           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15626       break;
15627     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
15628     case FOURCC_dv5p:          /* DVCPRO50 PAL */
15629       _codec ("DVCPro50 Video");
15630       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
15631           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15632       break;
15633     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
15634     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
15635       _codec ("DVCProHD Video");
15636       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
15637           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
15638       break;
15639     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
15640       _codec ("Apple Graphics (SMC)");
15641       caps = gst_caps_new_empty_simple ("video/x-smc");
15642       break;
15643     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
15644       _codec ("VP3");
15645       caps = gst_caps_new_empty_simple ("video/x-vp3");
15646       break;
15647     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
15648       _codec ("VP6 Flash");
15649       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
15650       break;
15651     case FOURCC_XiTh:
15652       _codec ("Theora");
15653       caps = gst_caps_new_empty_simple ("video/x-theora");
15654       /* theora uses one byte of padding in the data stream because it does not
15655        * allow 0 sized packets while theora does */
15656       entry->padding = 1;
15657       break;
15658     case FOURCC_drac:
15659       _codec ("Dirac");
15660       caps = gst_caps_new_empty_simple ("video/x-dirac");
15661       break;
15662     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
15663       _codec ("TIFF still images");
15664       caps = gst_caps_new_empty_simple ("image/tiff");
15665       break;
15666     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
15667       _codec ("Apple Intermediate Codec");
15668       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
15669       break;
15670     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
15671       _codec ("AVID DNxHD");
15672       caps = gst_caps_from_string ("video/x-dnxhd");
15673       break;
15674     case FOURCC_VP80:
15675     case FOURCC_vp08:
15676       _codec ("On2 VP8");
15677       caps = gst_caps_from_string ("video/x-vp8");
15678       break;
15679     case FOURCC_vp09:
15680       _codec ("Google VP9");
15681       caps = gst_caps_from_string ("video/x-vp9");
15682       break;
15683     case FOURCC_apcs:
15684       _codec ("Apple ProRes LT");
15685       caps =
15686           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
15687           NULL);
15688       break;
15689     case FOURCC_apch:
15690       _codec ("Apple ProRes HQ");
15691       caps =
15692           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
15693           NULL);
15694       break;
15695     case FOURCC_apcn:
15696       _codec ("Apple ProRes");
15697       caps =
15698           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15699           "standard", NULL);
15700       break;
15701     case FOURCC_apco:
15702       _codec ("Apple ProRes Proxy");
15703       caps =
15704           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15705           "proxy", NULL);
15706       break;
15707     case FOURCC_ap4h:
15708       _codec ("Apple ProRes 4444");
15709       caps =
15710           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15711           "4444", NULL);
15712       break;
15713     case FOURCC_ap4x:
15714       _codec ("Apple ProRes 4444 XQ");
15715       caps =
15716           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
15717           "4444xq", NULL);
15718       break;
15719     case FOURCC_cfhd:
15720       _codec ("GoPro CineForm");
15721       caps = gst_caps_from_string ("video/x-cineform");
15722       break;
15723     case FOURCC_vc_1:
15724     case FOURCC_ovc1:
15725       _codec ("VC-1");
15726       caps = gst_caps_new_simple ("video/x-wmv",
15727           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
15728       break;
15729     case FOURCC_av01:
15730       _codec ("AV1");
15731       caps = gst_caps_new_empty_simple ("video/x-av1");
15732       break;
15733     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
15734     default:
15735     {
15736       caps = _get_unknown_codec_name ("video", fourcc);
15737       break;
15738     }
15739   }
15740
15741   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
15742     GstVideoInfo info;
15743
15744     gst_video_info_init (&info);
15745     gst_video_info_set_format (&info, format, entry->width, entry->height);
15746
15747     caps = gst_video_info_to_caps (&info);
15748     *codec_name = gst_pb_utils_get_codec_description (caps);
15749
15750     /* enable clipping for raw video streams */
15751     stream->need_clip = TRUE;
15752     stream->alignment = 32;
15753   }
15754
15755   return caps;
15756 }
15757
15758 static guint
15759 round_up_pow2 (guint n)
15760 {
15761   n = n - 1;
15762   n = n | (n >> 1);
15763   n = n | (n >> 2);
15764   n = n | (n >> 4);
15765   n = n | (n >> 8);
15766   n = n | (n >> 16);
15767   return n + 1;
15768 }
15769
15770 static GstCaps *
15771 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
15772     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
15773     int len, gchar ** codec_name)
15774 {
15775   GstCaps *caps;
15776   const GstStructure *s;
15777   const gchar *name;
15778   gint endian = 0;
15779   GstAudioFormat format = 0;
15780   gint depth;
15781
15782   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
15783
15784   depth = entry->bytes_per_packet * 8;
15785
15786   switch (fourcc) {
15787     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
15788     case FOURCC_raw_:
15789       /* 8-bit audio is unsigned */
15790       if (depth == 8)
15791         format = GST_AUDIO_FORMAT_U8;
15792       /* otherwise it's signed and big-endian just like 'twos' */
15793     case FOURCC_twos:
15794       endian = G_BIG_ENDIAN;
15795       /* fall-through */
15796     case FOURCC_sowt:
15797     {
15798       gchar *str;
15799
15800       if (!endian)
15801         endian = G_LITTLE_ENDIAN;
15802
15803       if (!format)
15804         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
15805
15806       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
15807       _codec (str);
15808       g_free (str);
15809
15810       caps = gst_caps_new_simple ("audio/x-raw",
15811           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
15812           "layout", G_TYPE_STRING, "interleaved", NULL);
15813       stream->alignment = GST_ROUND_UP_8 (depth);
15814       stream->alignment = round_up_pow2 (stream->alignment);
15815       break;
15816     }
15817     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
15818       _codec ("Raw 64-bit floating-point audio");
15819       caps = gst_caps_new_simple ("audio/x-raw",
15820           "format", G_TYPE_STRING, "F64BE",
15821           "layout", G_TYPE_STRING, "interleaved", NULL);
15822       stream->alignment = 8;
15823       break;
15824     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
15825       _codec ("Raw 32-bit floating-point audio");
15826       caps = gst_caps_new_simple ("audio/x-raw",
15827           "format", G_TYPE_STRING, "F32BE",
15828           "layout", G_TYPE_STRING, "interleaved", NULL);
15829       stream->alignment = 4;
15830       break;
15831     case FOURCC_in24:
15832       _codec ("Raw 24-bit PCM audio");
15833       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
15834        * endian later */
15835       caps = gst_caps_new_simple ("audio/x-raw",
15836           "format", G_TYPE_STRING, "S24BE",
15837           "layout", G_TYPE_STRING, "interleaved", NULL);
15838       stream->alignment = 4;
15839       break;
15840     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
15841       _codec ("Raw 32-bit PCM audio");
15842       caps = gst_caps_new_simple ("audio/x-raw",
15843           "format", G_TYPE_STRING, "S32BE",
15844           "layout", G_TYPE_STRING, "interleaved", NULL);
15845       stream->alignment = 4;
15846       break;
15847     case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
15848       _codec ("Raw 16-bit PCM audio");
15849       caps = gst_caps_new_simple ("audio/x-raw",
15850           "format", G_TYPE_STRING, "S16LE",
15851           "layout", G_TYPE_STRING, "interleaved", NULL);
15852       stream->alignment = 2;
15853       break;
15854     case FOURCC_ulaw:
15855       _codec ("Mu-law audio");
15856       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
15857       break;
15858     case FOURCC_alaw:
15859       _codec ("A-law audio");
15860       caps = gst_caps_new_empty_simple ("audio/x-alaw");
15861       break;
15862     case 0x0200736d:
15863     case 0x6d730002:
15864       _codec ("Microsoft ADPCM");
15865       /* Microsoft ADPCM-ACM code 2 */
15866       caps = gst_caps_new_simple ("audio/x-adpcm",
15867           "layout", G_TYPE_STRING, "microsoft", NULL);
15868       break;
15869     case 0x1100736d:
15870     case 0x6d730011:
15871       _codec ("DVI/IMA ADPCM");
15872       caps = gst_caps_new_simple ("audio/x-adpcm",
15873           "layout", G_TYPE_STRING, "dvi", NULL);
15874       break;
15875     case 0x1700736d:
15876     case 0x6d730017:
15877       _codec ("DVI/Intel IMA ADPCM");
15878       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
15879       caps = gst_caps_new_simple ("audio/x-adpcm",
15880           "layout", G_TYPE_STRING, "quicktime", NULL);
15881       break;
15882     case 0x5500736d:
15883     case 0x6d730055:
15884       /* MPEG layer 3, CBR only (pre QT4.1) */
15885     case FOURCC__mp3:
15886       _codec ("MPEG-1 layer 3");
15887       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
15888       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
15889           "mpegversion", G_TYPE_INT, 1, NULL);
15890       break;
15891     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
15892       _codec ("MPEG-1 layer 2");
15893       /* MPEG layer 2 */
15894       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
15895           "mpegversion", G_TYPE_INT, 1, NULL);
15896       break;
15897     case 0x20736d:
15898     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
15899       _codec ("EAC-3 audio");
15900       caps = gst_caps_new_simple ("audio/x-eac3",
15901           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15902       entry->sampled = TRUE;
15903       break;
15904     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
15905     case FOURCC_ac_3:
15906       _codec ("AC-3 audio");
15907       caps = gst_caps_new_simple ("audio/x-ac3",
15908           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15909       entry->sampled = TRUE;
15910       break;
15911     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
15912     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
15913       _codec ("DTS audio");
15914       caps = gst_caps_new_simple ("audio/x-dts",
15915           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15916       entry->sampled = TRUE;
15917       break;
15918     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
15919     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
15920       _codec ("DTS-HD audio");
15921       caps = gst_caps_new_simple ("audio/x-dts",
15922           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15923       entry->sampled = TRUE;
15924       break;
15925     case FOURCC_MAC3:
15926       _codec ("MACE-3");
15927       caps = gst_caps_new_simple ("audio/x-mace",
15928           "maceversion", G_TYPE_INT, 3, NULL);
15929       break;
15930     case FOURCC_MAC6:
15931       _codec ("MACE-6");
15932       caps = gst_caps_new_simple ("audio/x-mace",
15933           "maceversion", G_TYPE_INT, 6, NULL);
15934       break;
15935     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
15936       /* ogg/vorbis */
15937       caps = gst_caps_new_empty_simple ("application/ogg");
15938       break;
15939     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
15940       _codec ("DV audio");
15941       caps = gst_caps_new_empty_simple ("audio/x-dv");
15942       break;
15943     case FOURCC_mp4a:
15944       _codec ("MPEG-4 AAC audio");
15945       caps = gst_caps_new_simple ("audio/mpeg",
15946           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
15947           "stream-format", G_TYPE_STRING, "raw", NULL);
15948       break;
15949     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
15950       _codec ("QDesign Music");
15951       caps = gst_caps_new_empty_simple ("audio/x-qdm");
15952       break;
15953     case FOURCC_QDM2:
15954       _codec ("QDesign Music v.2");
15955       /* FIXME: QDesign music version 2 (no constant) */
15956       if (FALSE && data) {
15957         caps = gst_caps_new_simple ("audio/x-qdm2",
15958             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
15959             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
15960             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
15961       } else {
15962         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
15963       }
15964       break;
15965     case FOURCC_agsm:
15966       _codec ("GSM audio");
15967       caps = gst_caps_new_empty_simple ("audio/x-gsm");
15968       break;
15969     case FOURCC_samr:
15970       _codec ("AMR audio");
15971       caps = gst_caps_new_empty_simple ("audio/AMR");
15972       break;
15973     case FOURCC_sawb:
15974       _codec ("AMR-WB audio");
15975       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
15976       break;
15977     case FOURCC_ima4:
15978       _codec ("Quicktime IMA ADPCM");
15979       caps = gst_caps_new_simple ("audio/x-adpcm",
15980           "layout", G_TYPE_STRING, "quicktime", NULL);
15981       break;
15982     case FOURCC_alac:
15983       _codec ("Apple lossless audio");
15984       caps = gst_caps_new_empty_simple ("audio/x-alac");
15985       break;
15986     case FOURCC_fLaC:
15987       _codec ("Free Lossless Audio Codec");
15988       caps = gst_caps_new_simple ("audio/x-flac",
15989           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
15990       break;
15991     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
15992       _codec ("QualComm PureVoice");
15993       caps = gst_caps_from_string ("audio/qcelp");
15994       break;
15995     case FOURCC_wma_:
15996     case FOURCC_owma:
15997       _codec ("WMA");
15998       caps = gst_caps_new_empty_simple ("audio/x-wma");
15999       break;
16000     case FOURCC_opus:
16001       _codec ("Opus");
16002       caps = gst_caps_new_empty_simple ("audio/x-opus");
16003       break;
16004     case FOURCC_lpcm:
16005     {
16006       guint32 flags = 0;
16007       guint32 depth = 0;
16008       guint32 width = 0;
16009       GstAudioFormat format;
16010       enum
16011       {
16012         FLAG_IS_FLOAT = 0x1,
16013         FLAG_IS_BIG_ENDIAN = 0x2,
16014         FLAG_IS_SIGNED = 0x4,
16015         FLAG_IS_PACKED = 0x8,
16016         FLAG_IS_ALIGNED_HIGH = 0x10,
16017         FLAG_IS_NON_INTERLEAVED = 0x20
16018       };
16019       _codec ("Raw LPCM audio");
16020
16021       if (data && len >= 36) {
16022         depth = QT_UINT32 (data + 24);
16023         flags = QT_UINT32 (data + 28);
16024         width = QT_UINT32 (data + 32) * 8 / entry->n_channels;
16025       }
16026       if ((flags & FLAG_IS_FLOAT) == 0) {
16027         if (depth == 0)
16028           depth = 16;
16029         if (width == 0)
16030           width = 16;
16031         if ((flags & FLAG_IS_ALIGNED_HIGH))
16032           depth = width;
16033
16034         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
16035             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
16036             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
16037         caps = gst_caps_new_simple ("audio/x-raw",
16038             "format", G_TYPE_STRING,
16039             format !=
16040             GST_AUDIO_FORMAT_UNKNOWN ? gst_audio_format_to_string (format) :
16041             "UNKNOWN", "layout", G_TYPE_STRING,
16042             (flags & FLAG_IS_NON_INTERLEAVED) ? "non-interleaved" :
16043             "interleaved", NULL);
16044         stream->alignment = GST_ROUND_UP_8 (depth);
16045         stream->alignment = round_up_pow2 (stream->alignment);
16046       } else {
16047         if (width == 0)
16048           width = 32;
16049         if (width == 64) {
16050           if (flags & FLAG_IS_BIG_ENDIAN)
16051             format = GST_AUDIO_FORMAT_F64BE;
16052           else
16053             format = GST_AUDIO_FORMAT_F64LE;
16054         } else {
16055           if (flags & FLAG_IS_BIG_ENDIAN)
16056             format = GST_AUDIO_FORMAT_F32BE;
16057           else
16058             format = GST_AUDIO_FORMAT_F32LE;
16059         }
16060         caps = gst_caps_new_simple ("audio/x-raw",
16061             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
16062             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
16063             "non-interleaved" : "interleaved", NULL);
16064         stream->alignment = width / 8;
16065       }
16066       break;
16067     }
16068     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
16069       /* ? */
16070     default:
16071     {
16072       caps = _get_unknown_codec_name ("audio", fourcc);
16073       break;
16074     }
16075   }
16076
16077   if (caps) {
16078     GstCaps *templ_caps =
16079         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
16080     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
16081     gst_caps_unref (caps);
16082     gst_caps_unref (templ_caps);
16083     caps = intersection;
16084   }
16085
16086   /* enable clipping for raw audio streams */
16087   s = gst_caps_get_structure (caps, 0);
16088   name = gst_structure_get_name (s);
16089   if (g_str_has_prefix (name, "audio/x-raw")) {
16090     stream->need_clip = TRUE;
16091     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
16092     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
16093   }
16094   return caps;
16095 }
16096
16097 static GstCaps *
16098 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16099     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16100     const guint8 * stsd_entry_data, gchar ** codec_name)
16101 {
16102   GstCaps *caps;
16103
16104   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
16105
16106   switch (fourcc) {
16107     case FOURCC_mp4s:
16108       _codec ("DVD subtitle");
16109       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
16110       stream->need_process = TRUE;
16111       break;
16112     case FOURCC_text:
16113       _codec ("Quicktime timed text");
16114       goto text;
16115     case FOURCC_tx3g:
16116       _codec ("3GPP timed text");
16117     text:
16118       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
16119           "utf8", NULL);
16120       /* actual text piece needs to be extracted */
16121       stream->need_process = TRUE;
16122       break;
16123     case FOURCC_stpp:
16124       _codec ("XML subtitles");
16125       caps = gst_caps_new_empty_simple ("application/ttml+xml");
16126       break;
16127     case FOURCC_c608:
16128       _codec ("CEA 608 Closed Caption");
16129       caps =
16130           gst_caps_new_simple ("closedcaption/x-cea-608", "format",
16131           G_TYPE_STRING, "s334-1a", NULL);
16132       stream->need_process = TRUE;
16133       stream->need_split = TRUE;
16134       break;
16135     case FOURCC_c708:
16136       _codec ("CEA 708 Closed Caption");
16137       caps =
16138           gst_caps_new_simple ("closedcaption/x-cea-708", "format",
16139           G_TYPE_STRING, "cdp", NULL);
16140       stream->need_process = TRUE;
16141       break;
16142
16143     default:
16144     {
16145       caps = _get_unknown_codec_name ("text", fourcc);
16146       break;
16147     }
16148   }
16149   return caps;
16150 }
16151
16152 static GstCaps *
16153 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
16154     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
16155     const guint8 * stsd_entry_data, gchar ** codec_name)
16156 {
16157   GstCaps *caps;
16158
16159   switch (fourcc) {
16160     case FOURCC_m1v:
16161       _codec ("MPEG 1 video");
16162       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
16163           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
16164       break;
16165     default:
16166       caps = NULL;
16167       break;
16168   }
16169   return caps;
16170 }
16171
16172 static void
16173 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
16174     const gchar * system_id)
16175 {
16176   gint i;
16177
16178   if (!qtdemux->protection_system_ids)
16179     qtdemux->protection_system_ids =
16180         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
16181   /* Check whether we already have an entry for this system ID. */
16182   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
16183     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
16184     if (g_ascii_strcasecmp (system_id, id) == 0) {
16185       return;
16186     }
16187   }
16188   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
16189   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
16190           -1));
16191 }