b43cfc970a3f6eca8a4343acd8985d4da39e01f5
[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
60 #include "qtatomparser.h"
61 #include "qtdemux_types.h"
62 #include "qtdemux_dump.h"
63 #include "fourcc.h"
64 #include "descriptors.h"
65 #include "qtdemux_lang.h"
66 #include "qtdemux.h"
67 #include "qtpalette.h"
68
69 #include "gst/riff/riff-media.h"
70 #include "gst/riff/riff-read.h"
71
72 #include <gst/pbutils/pbutils.h>
73
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77
78 #include <math.h>
79 #include <gst/math-compat.h>
80
81 #ifdef HAVE_ZLIB
82 #include <zlib.h>
83 #endif
84
85 /* max. size considered 'sane' for non-mdat atoms */
86 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
87
88 /* if the sample index is larger than this, something is likely wrong */
89 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
90
91 /* For converting qt creation times to unix epoch times */
92 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
93 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
94 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
95     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
96
97 #define QTDEMUX_TREE_NODE_FOURCC(n) (QT_FOURCC(((guint8 *) (n)->data) + 4))
98
99 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
100
101 #define ABSDIFF(x, y) ( (x) > (y) ? ((x) - (y)) : ((y) - (x)) )
102
103 GST_DEBUG_CATEGORY (qtdemux_debug);
104
105 typedef struct _QtDemuxSegment QtDemuxSegment;
106 typedef struct _QtDemuxSample QtDemuxSample;
107
108 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
109
110 struct _QtDemuxSample
111 {
112   guint32 size;
113   gint32 pts_offset;            /* Add this value to timestamp to get the pts */
114   guint64 offset;
115   guint64 timestamp;            /* DTS In mov time */
116   guint32 duration;             /* In mov time */
117   gboolean keyframe;            /* TRUE when this packet is a keyframe */
118 };
119
120 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
121 typedef struct _QtDemuxSphericalMetadata QtDemuxSphericalMetadata;
122
123 struct _QtDemuxSphericalMetadata
124 {
125   gboolean is_spherical;
126   gboolean is_stitched;
127   char *stitching_software;
128   char *projection_type;
129   char *stereo_mode;
130   int source_count;
131   int init_view_heading;
132   int init_view_pitch;
133   int init_view_roll;
134   int timestamp;
135   int full_pano_width_pixels;
136   int full_pano_height_pixels;
137   int cropped_area_image_width;
138   int cropped_area_image_height;
139   int cropped_area_left;
140   int cropped_area_top;
141   QTDEMUX_AMBISONIC_TYPE ambisonic_type;
142   QTDEMUX_AMBISONIC_FORMAT ambisonic_format;
143   QTDEMUX_AMBISONIC_ORDER ambisonic_order;
144 };
145
146 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
147
148 /* Macros for converting to/from timescale */
149 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
150 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
151
152 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
153 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
154
155 /* timestamp is the DTS */
156 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
157 /* timestamp + offset + cslg_shift is the outgoing PTS */
158 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
159 /* timestamp + offset is the PTS used for internal seek calcuations */
160 #define QTSAMPLE_PTS_NO_CSLG(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
161 /* timestamp + duration - dts is the duration */
162 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
163
164 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
165
166 /*
167  * Quicktime has tracks and segments. A track is a continuous piece of
168  * multimedia content. The track is not always played from start to finish but
169  * instead, pieces of the track are 'cut out' and played in sequence. This is
170  * what the segments do.
171  *
172  * Inside the track we have keyframes (K) and delta frames. The track has its
173  * own timing, which starts from 0 and extends to end. The position in the track
174  * is called the media_time.
175  *
176  * The segments now describe the pieces that should be played from this track
177  * and are basically tuples of media_time/duration/rate entries. We can have
178  * multiple segments and they are all played after one another. An example:
179  *
180  * segment 1: media_time: 1 second, duration: 1 second, rate 1
181  * segment 2: media_time: 3 second, duration: 2 second, rate 2
182  *
183  * To correctly play back this track, one must play: 1 second of media starting
184  * from media_time 1 followed by 2 seconds of media starting from media_time 3
185  * at a rate of 2.
186  *
187  * Each of the segments will be played at a specific time, the first segment at
188  * time 0, the second one after the duration of the first one, etc.. Note that
189  * the time in resulting playback is not identical to the media_time of the
190  * track anymore.
191  *
192  * Visually, assuming the track has 4 second of media_time:
193  *
194  *                (a)                   (b)          (c)              (d)
195  *         .-----------------------------------------------------------.
196  * track:  | K.....K.........K........K.......K.......K...........K... |
197  *         '-----------------------------------------------------------'
198  *         0              1              2              3              4
199  *           .------------^              ^   .----------^              ^
200  *          /              .-------------'  /       .------------------'
201  *         /              /          .-----'       /
202  *         .--------------.         .--------------.
203  *         | segment 1    |         | segment 2    |
204  *         '--------------'         '--------------'
205  *
206  * The challenge here is to cut out the right pieces of the track for each of
207  * the playback segments. This fortunately can easily be done with the SEGMENT
208  * events of GStreamer.
209  *
210  * For playback of segment 1, we need to provide the decoder with the keyframe
211  * (a), in the above figure, but we must instruct it only to output the decoded
212  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
213  * position set to the time of the segment: 0.
214  *
215  * We then proceed to push data from keyframe (a) to frame (b). The decoder
216  * decodes but clips all before media_time 1.
217  *
218  * After finishing a segment, we push out a new SEGMENT event with the clipping
219  * boundaries of the new data.
220  *
221  * This is a good usecase for the GStreamer accumulated SEGMENT events.
222  */
223
224 struct _QtDemuxSegment
225 {
226   /* global time and duration, all gst time */
227   GstClockTime time;
228   GstClockTime stop_time;
229   GstClockTime duration;
230   /* media time of trak, all gst time */
231   GstClockTime media_start;
232   GstClockTime media_stop;
233   gdouble rate;
234   /* Media start time in trak timescale units */
235   guint32 trak_media_start;
236 };
237
238 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
239
240 /* Used with fragmented MP4 files (mfra atom) */
241 typedef struct
242 {
243   GstClockTime ts;
244   guint64 moof_offset;
245 } QtDemuxRandomAccessEntry;
246
247 typedef struct _QtDemuxStreamStsdEntry
248 {
249   GstCaps *caps;
250   guint32 fourcc;
251   gboolean sparse;
252
253   /* video info */
254   gint width;
255   gint height;
256   gint par_w;
257   gint par_h;
258   /* Numerator/denominator framerate */
259   gint fps_n;
260   gint fps_d;
261   GstVideoColorimetry colorimetry;
262   guint16 bits_per_sample;
263   guint16 color_table_id;
264   GstMemory *rgb8_palette;
265   guint interlace_mode;
266   guint field_order;
267
268   /* audio info */
269   gdouble rate;
270   gint n_channels;
271   guint samples_per_packet;
272   guint samples_per_frame;
273   guint bytes_per_packet;
274   guint bytes_per_sample;
275   guint bytes_per_frame;
276   guint compression;
277
278   /* if we use chunks or samples */
279   gboolean sampled;
280   guint padding;
281
282 } QtDemuxStreamStsdEntry;
283
284 #define CUR_STREAM(s) (&((s)->stsd_entries[(s)->cur_stsd_entry_index]))
285
286 struct _QtDemuxStream
287 {
288   GstPad *pad;
289
290   QtDemuxStreamStsdEntry *stsd_entries;
291   guint stsd_entries_length;
292   guint cur_stsd_entry_index;
293
294   /* stream type */
295   guint32 subtype;
296
297   gboolean new_caps;            /* If TRUE, caps need to be generated (by
298                                  * calling _configure_stream()) This happens
299                                  * for MSS and fragmented streams */
300
301   gboolean new_stream;          /* signals that a stream_start is required */
302   gboolean on_keyframe;         /* if this stream last pushed buffer was a
303                                  * keyframe. This is important to identify
304                                  * where to stop pushing buffers after a
305                                  * segment stop time */
306
307   /* if the stream has a redirect URI in its headers, we store it here */
308   gchar *redirect_uri;
309
310   /* track id */
311   guint track_id;
312
313   /* duration/scale */
314   guint64 duration;             /* in timescale units */
315   guint32 timescale;
316
317   /* language */
318   gchar lang_id[4];             /* ISO 639-2T language code */
319
320   /* our samples */
321   guint32 n_samples;
322   QtDemuxSample *samples;
323   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
324   guint32 first_duration;       /* duration in timescale of first sample, used for figuring out
325                                    the framerate */
326   guint32 n_samples_moof;       /* sample count in a moof */
327   guint64 duration_moof;        /* duration in timescale of a moof, used for figure out
328                                  * the framerate of fragmented format stream */
329   guint64 duration_last_moof;
330
331   guint32 offset_in_sample;     /* Offset in the current sample, used for
332                                  * streams which have got exceedingly big
333                                  * sample size (such as 24s of raw audio).
334                                  * Only used when max_buffer_size is non-NULL */
335   guint32 max_buffer_size;      /* Maximum allowed size for output buffers.
336                                  * Currently only set for raw audio streams*/
337
338   /* video info */
339   /* aspect ratio */
340   gint display_width;
341   gint display_height;
342
343   /* allocation */
344   gboolean use_allocator;
345   GstAllocator *allocator;
346   GstAllocationParams params;
347
348   gsize alignment;
349
350   /* when a discontinuity is pending */
351   gboolean discont;
352
353   /* list of buffers to push first */
354   GSList *buffers;
355
356   /* if we need to clip this buffer. This is only needed for uncompressed
357    * data */
358   gboolean need_clip;
359
360   /* buffer needs some custom processing, e.g. subtitles */
361   gboolean need_process;
362
363   /* current position */
364   guint32 segment_index;
365   guint32 sample_index;
366   GstClockTime time_position;   /* in gst time */
367   guint64 accumulated_base;
368
369   /* the Gst segment we are processing out, used for clipping */
370   GstSegment segment;
371
372   /* quicktime segments */
373   guint32 n_segments;
374   QtDemuxSegment *segments;
375   gboolean dummy_segment;
376   guint32 from_sample;
377   guint32 to_sample;
378
379   gboolean sent_eos;
380   GstTagList *stream_tags;
381   gboolean send_global_tags;
382
383   GstEvent *pending_event;
384
385   GstByteReader stco;
386   GstByteReader stsz;
387   GstByteReader stsc;
388   GstByteReader stts;
389   GstByteReader stss;
390   GstByteReader stps;
391   GstByteReader ctts;
392
393   gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
394   gint64 stbl_index;
395   /* stco */
396   guint co_size;
397   GstByteReader co_chunk;
398   guint32 first_chunk;
399   guint32 current_chunk;
400   guint32 last_chunk;
401   guint32 samples_per_chunk;
402   guint32 stsd_sample_description_id;
403   guint32 stco_sample_index;
404   /* stsz */
405   guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
406   /* stsc */
407   guint32 stsc_index;
408   guint32 n_samples_per_chunk;
409   guint32 stsc_chunk_index;
410   guint32 stsc_sample_index;
411   guint64 chunk_offset;
412   /* stts */
413   guint32 stts_index;
414   guint32 stts_samples;
415   guint32 n_sample_times;
416   guint32 stts_sample_index;
417   guint64 stts_time;
418   guint32 stts_duration;
419   /* stss */
420   gboolean stss_present;
421   guint32 n_sample_syncs;
422   guint32 stss_index;
423   /* stps */
424   gboolean stps_present;
425   guint32 n_sample_partial_syncs;
426   guint32 stps_index;
427   QtDemuxRandomAccessEntry *ra_entries;
428   guint n_ra_entries;
429
430   const QtDemuxRandomAccessEntry *pending_seek;
431
432   /* ctts */
433   gboolean ctts_present;
434   guint32 n_composition_times;
435   guint32 ctts_index;
436   guint32 ctts_sample_index;
437   guint32 ctts_count;
438   gint32 ctts_soffset;
439
440   /* cslg */
441   guint32 cslg_shift;
442
443   /* fragmented */
444   gboolean parsed_trex;
445   guint32 def_sample_description_index; /* index is 1-based */
446   guint32 def_sample_duration;
447   guint32 def_sample_size;
448   guint32 def_sample_flags;
449
450   gboolean disabled;
451
452   /* stereoscopic video streams */
453   GstVideoMultiviewMode multiview_mode;
454   GstVideoMultiviewFlags multiview_flags;
455
456   /* protected streams */
457   gboolean protected;
458   guint32 protection_scheme_type;
459   guint32 protection_scheme_version;
460   gpointer protection_scheme_info;      /* specific to the protection scheme */
461   GQueue protection_scheme_event_queue;
462 };
463
464 /* Contains properties and cryptographic info for a set of samples from a
465  * track protected using Common Encryption (cenc) */
466 struct _QtDemuxCencSampleSetInfo
467 {
468   GstStructure *default_properties;
469
470   /* @crypto_info holds one GstStructure per sample */
471   GPtrArray *crypto_info;
472 };
473
474 static const gchar *
475 qt_demux_state_string (enum QtDemuxState state)
476 {
477   switch (state) {
478     case QTDEMUX_STATE_INITIAL:
479       return "<INITIAL>";
480     case QTDEMUX_STATE_HEADER:
481       return "<HEADER>";
482     case QTDEMUX_STATE_MOVIE:
483       return "<MOVIE>";
484     case QTDEMUX_STATE_BUFFER_MDAT:
485       return "<BUFFER_MDAT>";
486     default:
487       return "<UNKNOWN>";
488   }
489 }
490
491 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
492 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
493     guint32 fourcc, GstByteReader * parser);
494 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
495 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
496     guint32 fourcc, GstByteReader * parser);
497
498 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
499
500 static GstStaticPadTemplate gst_qtdemux_sink_template =
501     GST_STATIC_PAD_TEMPLATE ("sink",
502     GST_PAD_SINK,
503     GST_PAD_ALWAYS,
504     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
505         "application/x-3gp")
506     );
507
508 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
509 GST_STATIC_PAD_TEMPLATE ("video_%u",
510     GST_PAD_SRC,
511     GST_PAD_SOMETIMES,
512     GST_STATIC_CAPS_ANY);
513
514 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
515 GST_STATIC_PAD_TEMPLATE ("audio_%u",
516     GST_PAD_SRC,
517     GST_PAD_SOMETIMES,
518     GST_STATIC_CAPS_ANY);
519
520 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
521 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
522     GST_PAD_SRC,
523     GST_PAD_SOMETIMES,
524     GST_STATIC_CAPS_ANY);
525
526 #define gst_qtdemux_parent_class parent_class
527 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
528
529 static void gst_qtdemux_dispose (GObject * object);
530
531 static guint32
532 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
533     GstClockTime media_time);
534 static guint32
535 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
536     QtDemuxStream * str, gint64 media_offset);
537
538 #if 0
539 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
540 static GstIndex *gst_qtdemux_get_index (GstElement * element);
541 #endif
542 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
543     GstStateChange transition);
544 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
545 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
546     GstObject * parent, GstPadMode mode, gboolean active);
547
548 static void gst_qtdemux_loop (GstPad * pad);
549 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
550     GstBuffer * inbuf);
551 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
552     GstEvent * event);
553 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
554 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
555     QtDemuxStream * stream);
556 static void gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
557     QtDemuxStream * stream);
558 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
559     gboolean force);
560
561 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
562     const guint8 * buffer, guint length);
563 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
564     const guint8 * buffer, guint length);
565 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
566 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
567     GNode * udta);
568
569 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
570     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, GNode * esds,
571     GstTagList * list);
572 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
573     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
574     const guint8 * stsd_entry_data, gchar ** codec_name);
575 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
576     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
577     const guint8 * data, int len, gchar ** codec_name);
578 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
579     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
580     gchar ** codec_name);
581 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
582     QtDemuxStream * stream, QtDemuxStreamStsdEntry * entry, guint32 fourcc,
583     const guint8 * stsd_entry_data, gchar ** codec_name);
584
585 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
586     QtDemuxStream * stream, guint32 n);
587 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
588 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
589     QtDemuxStream * stream);
590 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
591     QtDemuxStream * stream);
592 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
593 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
594 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
595     QtDemuxStream * stream);
596 static gboolean gst_qtdemux_activate_segment (GstQTDemux * qtdemux,
597     QtDemuxStream * stream, guint32 seg_idx, GstClockTime offset);
598 static gboolean gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux,
599     QtDemuxStream * stream, gint seg_idx, GstClockTime offset,
600     GstClockTime * _start, GstClockTime * _stop);
601 static void gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
602     QtDemuxStream * stream, gint segment_index, GstClockTime pos);
603
604 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
605 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
606
607 static gchar *qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes);
608
609 static GstStructure *qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
610     QtDemuxStream * stream, guint sample_index);
611 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
612     const gchar * id);
613 static void qtdemux_gst_structure_free (GstStructure * gststructure);
614
615 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
616 static void gst_tag_register_spherical_tags (void);
617 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
618
619 static void
620 gst_qtdemux_class_init (GstQTDemuxClass * klass)
621 {
622   GObjectClass *gobject_class;
623   GstElementClass *gstelement_class;
624
625   gobject_class = (GObjectClass *) klass;
626   gstelement_class = (GstElementClass *) klass;
627
628   parent_class = g_type_class_peek_parent (klass);
629
630   gobject_class->dispose = gst_qtdemux_dispose;
631
632   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
633 #if 0
634   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
635   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
636 #endif
637
638   gst_tag_register_musicbrainz_tags ();
639
640 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
641   gst_tag_register_spherical_tags ();
642 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
643
644   gst_element_class_add_static_pad_template (gstelement_class,
645       &gst_qtdemux_sink_template);
646   gst_element_class_add_static_pad_template (gstelement_class,
647       &gst_qtdemux_videosrc_template);
648   gst_element_class_add_static_pad_template (gstelement_class,
649       &gst_qtdemux_audiosrc_template);
650   gst_element_class_add_static_pad_template (gstelement_class,
651       &gst_qtdemux_subsrc_template);
652   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
653       "Codec/Demuxer",
654       "Demultiplex a QuickTime file into audio and video streams",
655       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
656
657   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
658
659 }
660
661 static void
662 gst_qtdemux_init (GstQTDemux * qtdemux)
663 {
664   qtdemux->sinkpad =
665       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
666   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
667   gst_pad_set_activatemode_function (qtdemux->sinkpad,
668       qtdemux_sink_activate_mode);
669   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
670   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
671   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
672
673   qtdemux->state = QTDEMUX_STATE_INITIAL;
674   qtdemux->pullbased = FALSE;
675   qtdemux->posted_redirect = FALSE;
676   qtdemux->neededbytes = 16;
677   qtdemux->todrop = 0;
678   qtdemux->adapter = gst_adapter_new ();
679   qtdemux->offset = 0;
680   qtdemux->first_mdat = -1;
681   qtdemux->got_moov = FALSE;
682   qtdemux->mdatoffset = -1;
683   qtdemux->mdatbuffer = NULL;
684   qtdemux->restoredata_buffer = NULL;
685   qtdemux->restoredata_offset = -1;
686   qtdemux->fragment_start = -1;
687   qtdemux->fragment_start_offset = -1;
688   qtdemux->media_caps = NULL;
689   qtdemux->exposed = FALSE;
690   qtdemux->mss_mode = FALSE;
691   qtdemux->pending_newsegment = NULL;
692   qtdemux->upstream_format_is_time = FALSE;
693   qtdemux->have_group_id = FALSE;
694   qtdemux->group_id = G_MAXUINT;
695   qtdemux->cenc_aux_info_offset = 0;
696   qtdemux->cenc_aux_info_sizes = NULL;
697   qtdemux->cenc_aux_sample_count = 0;
698   qtdemux->protection_system_ids = NULL;
699   g_queue_init (&qtdemux->protection_event_queue);
700   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
701   qtdemux->tag_list = gst_tag_list_new_empty ();
702   gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
703   qtdemux->flowcombiner = gst_flow_combiner_new ();
704
705 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
706   qtdemux->spherical_metadata = (QtDemuxSphericalMetadata *)
707       malloc (sizeof (QtDemuxSphericalMetadata));
708
709   if (qtdemux->spherical_metadata) {
710     qtdemux->spherical_metadata->is_spherical = FALSE;
711     qtdemux->spherical_metadata->is_stitched = FALSE;
712     qtdemux->spherical_metadata->stitching_software = NULL;
713     qtdemux->spherical_metadata->projection_type = NULL;
714     qtdemux->spherical_metadata->stereo_mode = NULL;
715     qtdemux->spherical_metadata->source_count = 0;
716     qtdemux->spherical_metadata->init_view_heading = 0;
717     qtdemux->spherical_metadata->init_view_pitch = 0;
718     qtdemux->spherical_metadata->init_view_roll = 0;
719     qtdemux->spherical_metadata->timestamp = 0;
720     qtdemux->spherical_metadata->full_pano_width_pixels = 0;
721     qtdemux->spherical_metadata->full_pano_height_pixels = 0;
722     qtdemux->spherical_metadata->cropped_area_image_width = 0;
723     qtdemux->spherical_metadata->cropped_area_image_height = 0;
724     qtdemux->spherical_metadata->cropped_area_left = 0;
725     qtdemux->spherical_metadata->cropped_area_top = 0;
726     qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
727     qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_UNKNOWN;
728     qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_UNKNOWN;
729   }
730 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
731
732   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
733 }
734
735 static void
736 gst_qtdemux_dispose (GObject * object)
737 {
738   GstQTDemux *qtdemux = GST_QTDEMUX (object);
739
740 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
741   if (qtdemux->spherical_metadata) {
742     if (qtdemux->spherical_metadata->stitching_software)
743       free(qtdemux->spherical_metadata->stitching_software);
744     if (qtdemux->spherical_metadata->projection_type)
745       free(qtdemux->spherical_metadata->projection_type);
746     if (qtdemux->spherical_metadata->stereo_mode)
747       free(qtdemux->spherical_metadata->stereo_mode);
748
749     free(qtdemux->spherical_metadata);
750     qtdemux->spherical_metadata = NULL;
751   }
752 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
753
754   if (qtdemux->adapter) {
755     g_object_unref (G_OBJECT (qtdemux->adapter));
756     qtdemux->adapter = NULL;
757   }
758   gst_tag_list_unref (qtdemux->tag_list);
759   gst_flow_combiner_free (qtdemux->flowcombiner);
760   g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
761       NULL);
762   g_queue_clear (&qtdemux->protection_event_queue);
763
764   g_free (qtdemux->cenc_aux_info_sizes);
765   qtdemux->cenc_aux_info_sizes = NULL;
766
767   G_OBJECT_CLASS (parent_class)->dispose (object);
768 }
769
770 static void
771 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
772 {
773   if (qtdemux->posted_redirect) {
774     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
775         (_("This file contains no playable streams.")),
776         ("no known streams found, a redirect message has been posted"));
777   } else {
778     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
779         (_("This file contains no playable streams.")),
780         ("no known streams found"));
781   }
782 }
783
784 static GstBuffer *
785 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
786 {
787   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
788       mem, size, 0, size, mem, free_func);
789 }
790
791 static GstFlowReturn
792 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
793     GstBuffer ** buf)
794 {
795   GstFlowReturn flow;
796   GstMapInfo map;
797   gsize bsize;
798
799   if (G_UNLIKELY (size == 0)) {
800     GstFlowReturn ret;
801     GstBuffer *tmp = NULL;
802
803     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
804     if (ret != GST_FLOW_OK)
805       return ret;
806
807     gst_buffer_map (tmp, &map, GST_MAP_READ);
808     size = QT_UINT32 (map.data);
809     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
810
811     gst_buffer_unmap (tmp, &map);
812     gst_buffer_unref (tmp);
813   }
814
815   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
816   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
817     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
818       /* we're pulling header but already got most interesting bits,
819        * so never mind the rest (e.g. tags) (that much) */
820       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
821           size);
822       return GST_FLOW_EOS;
823     } else {
824       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
825           (_("This file is invalid and cannot be played.")),
826           ("atom has bogus size %" G_GUINT64_FORMAT, size));
827       return GST_FLOW_ERROR;
828     }
829   }
830
831   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
832
833   if (G_UNLIKELY (flow != GST_FLOW_OK))
834     return flow;
835
836   bsize = gst_buffer_get_size (*buf);
837   /* Catch short reads - we don't want any partial atoms */
838   if (G_UNLIKELY (bsize < size)) {
839     GST_WARNING_OBJECT (qtdemux,
840         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
841     gst_buffer_unref (*buf);
842     *buf = NULL;
843     return GST_FLOW_EOS;
844   }
845
846   return flow;
847 }
848
849 #if 1
850 static gboolean
851 gst_qtdemux_src_convert (GstQTDemux * qtdemux, GstPad * pad,
852     GstFormat src_format, gint64 src_value, GstFormat dest_format,
853     gint64 * dest_value)
854 {
855   gboolean res = TRUE;
856   QtDemuxStream *stream = gst_pad_get_element_private (pad);
857   gint32 index;
858
859   if (stream->subtype != FOURCC_vide) {
860     res = FALSE;
861     goto done;
862   }
863
864   switch (src_format) {
865     case GST_FORMAT_TIME:
866       switch (dest_format) {
867         case GST_FORMAT_BYTES:{
868           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
869           if (-1 == index) {
870             res = FALSE;
871             goto done;
872           }
873
874           *dest_value = stream->samples[index].offset;
875
876           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
877               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
878               GST_TIME_ARGS (src_value), *dest_value);
879           break;
880         }
881         default:
882           res = FALSE;
883           break;
884       }
885       break;
886     case GST_FORMAT_BYTES:
887       switch (dest_format) {
888         case GST_FORMAT_TIME:{
889           index =
890               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
891               stream, src_value);
892
893           if (-1 == index) {
894             res = FALSE;
895             goto done;
896           }
897
898           *dest_value =
899               QTSTREAMTIME_TO_GSTTIME (stream,
900               stream->samples[index].timestamp);
901           GST_DEBUG_OBJECT (qtdemux,
902               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
903               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
904           break;
905         }
906         default:
907           res = FALSE;
908           break;
909       }
910       break;
911     default:
912       res = FALSE;
913       break;
914   }
915
916 done:
917   return res;
918 }
919 #endif
920
921 static gboolean
922 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
923 {
924   gboolean res = FALSE;
925
926   *duration = GST_CLOCK_TIME_NONE;
927
928   if (qtdemux->duration != 0 &&
929       qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
930     *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
931     res = TRUE;
932   } else {
933     *duration = GST_CLOCK_TIME_NONE;
934   }
935
936   return res;
937 }
938
939 static gboolean
940 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
941     GstQuery * query)
942 {
943   gboolean res = FALSE;
944   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
945
946   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
947
948   switch (GST_QUERY_TYPE (query)) {
949     case GST_QUERY_POSITION:{
950       GstFormat fmt;
951
952       gst_query_parse_position (query, &fmt, NULL);
953       if (fmt == GST_FORMAT_TIME
954           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
955         gst_query_set_position (query, GST_FORMAT_TIME,
956             qtdemux->segment.position);
957         res = TRUE;
958       }
959     }
960       break;
961     case GST_QUERY_DURATION:{
962       GstFormat fmt;
963
964       gst_query_parse_duration (query, &fmt, NULL);
965       if (fmt == GST_FORMAT_TIME) {
966         /* First try to query upstream */
967         res = gst_pad_query_default (pad, parent, query);
968         if (!res) {
969           GstClockTime duration;
970           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
971             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
972             res = TRUE;
973           }
974         }
975       }
976       break;
977     }
978     case GST_QUERY_CONVERT:{
979       GstFormat src_fmt, dest_fmt;
980       gint64 src_value, dest_value = 0;
981
982       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
983
984       res = gst_qtdemux_src_convert (qtdemux, pad,
985           src_fmt, src_value, dest_fmt, &dest_value);
986       if (res) {
987         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
988         res = TRUE;
989       }
990       break;
991     }
992     case GST_QUERY_FORMATS:
993       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
994       res = TRUE;
995       break;
996     case GST_QUERY_SEEKING:{
997       GstFormat fmt;
998       gboolean seekable;
999
1000       /* try upstream first */
1001       res = gst_pad_query_default (pad, parent, query);
1002
1003       if (!res) {
1004         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1005         if (fmt == GST_FORMAT_TIME) {
1006           GstClockTime duration;
1007
1008           gst_qtdemux_get_duration (qtdemux, &duration);
1009           seekable = TRUE;
1010           if (!qtdemux->pullbased) {
1011             GstQuery *q;
1012
1013             /* we might be able with help from upstream */
1014             seekable = FALSE;
1015             q = gst_query_new_seeking (GST_FORMAT_BYTES);
1016             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
1017               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
1018               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
1019             }
1020             gst_query_unref (q);
1021           }
1022           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
1023           res = TRUE;
1024         }
1025       }
1026       break;
1027     }
1028     case GST_QUERY_SEGMENT:
1029     {
1030       GstFormat format;
1031       gint64 start, stop;
1032
1033       format = qtdemux->segment.format;
1034
1035       start =
1036           gst_segment_to_stream_time (&qtdemux->segment, format,
1037           qtdemux->segment.start);
1038       if ((stop = qtdemux->segment.stop) == -1)
1039         stop = qtdemux->segment.duration;
1040       else
1041         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
1042
1043       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
1044       res = TRUE;
1045       break;
1046     }
1047     default:
1048       res = gst_pad_query_default (pad, parent, query);
1049       break;
1050   }
1051
1052   return res;
1053 }
1054
1055 static void
1056 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
1057 {
1058   if (G_LIKELY (stream->pad)) {
1059     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
1060         GST_DEBUG_PAD_NAME (stream->pad));
1061
1062     if (!gst_tag_list_is_empty (stream->stream_tags)) {
1063       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
1064           stream->stream_tags);
1065       gst_pad_push_event (stream->pad,
1066           gst_event_new_tag (gst_tag_list_ref (stream->stream_tags)));
1067 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
1068       /* post message qtdemux tag (for early recive application) */
1069       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
1070             gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
1071                   gst_tag_list_copy (stream->stream_tags)));
1072 #endif
1073     }
1074
1075     if (G_UNLIKELY (stream->send_global_tags)) {
1076       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1077           qtdemux->tag_list);
1078       gst_pad_push_event (stream->pad,
1079           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1080       stream->send_global_tags = FALSE;
1081     }
1082   }
1083 }
1084
1085 /* push event on all source pads; takes ownership of the event */
1086 static void
1087 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1088 {
1089   guint n;
1090   gboolean has_valid_stream = FALSE;
1091   GstEventType etype = GST_EVENT_TYPE (event);
1092
1093   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1094       GST_EVENT_TYPE_NAME (event));
1095
1096   for (n = 0; n < qtdemux->n_streams; n++) {
1097     GstPad *pad;
1098     QtDemuxStream *stream = qtdemux->streams[n];
1099     GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
1100
1101     if ((pad = stream->pad)) {
1102       has_valid_stream = TRUE;
1103
1104       if (etype == GST_EVENT_EOS) {
1105         /* let's not send twice */
1106         if (stream->sent_eos)
1107           continue;
1108         stream->sent_eos = TRUE;
1109       }
1110
1111       gst_pad_push_event (pad, gst_event_ref (event));
1112     }
1113   }
1114
1115   gst_event_unref (event);
1116
1117   /* if it is EOS and there are no pads, post an error */
1118   if (!has_valid_stream && etype == GST_EVENT_EOS) {
1119     gst_qtdemux_post_no_playable_stream_error (qtdemux);
1120   }
1121 }
1122
1123 /* push a pending newsegment event, if any from the streaming thread */
1124 static void
1125 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1126 {
1127   if (qtdemux->pending_newsegment) {
1128     gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1129     qtdemux->pending_newsegment = NULL;
1130   }
1131 }
1132
1133 typedef struct
1134 {
1135   guint64 media_time;
1136 } FindData;
1137
1138 static gint
1139 find_func (QtDemuxSample * s1, gint64 * media_time, gpointer user_data)
1140 {
1141   if ((gint64) s1->timestamp + s1->pts_offset > *media_time)
1142     return 1;
1143   if ((gint64) s1->timestamp + s1->pts_offset == *media_time)
1144     return 0;
1145
1146   return -1;
1147 }
1148
1149 /* find the index of the sample that includes the data for @media_time using a
1150  * binary search.  Only to be called in optimized cases of linear search below.
1151  *
1152  * Returns the index of the sample.
1153  */
1154 static guint32
1155 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1156     guint64 media_time)
1157 {
1158   QtDemuxSample *result;
1159   guint32 index;
1160
1161   /* convert media_time to mov format */
1162   media_time =
1163       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1164
1165   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1166       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1167       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1168
1169   if (G_LIKELY (result))
1170     index = result - str->samples;
1171   else
1172     index = 0;
1173
1174   return index;
1175 }
1176
1177
1178
1179 /* find the index of the sample that includes the data for @media_offset using a
1180  * linear search
1181  *
1182  * Returns the index of the sample.
1183  */
1184 static guint32
1185 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1186     QtDemuxStream * str, gint64 media_offset)
1187 {
1188   QtDemuxSample *result = str->samples;
1189   guint32 index = 0;
1190
1191   if (result == NULL || str->n_samples == 0)
1192     return -1;
1193
1194   if (media_offset == result->offset)
1195     return index;
1196
1197   result++;
1198   while (index < str->n_samples - 1) {
1199     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1200       goto parse_failed;
1201
1202     if (media_offset < result->offset)
1203       break;
1204
1205     index++;
1206     result++;
1207   }
1208   return index;
1209
1210   /* ERRORS */
1211 parse_failed:
1212   {
1213     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1214     return -1;
1215   }
1216 }
1217
1218 /* find the index of the sample that includes the data for @media_time using a
1219  * linear search, and keeping in mind that not all samples may have been parsed
1220  * yet.  If possible, it will delegate to binary search.
1221  *
1222  * Returns the index of the sample.
1223  */
1224 static guint32
1225 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1226     GstClockTime media_time)
1227 {
1228   guint32 index = 0;
1229   guint64 mov_time;
1230   QtDemuxSample *sample;
1231
1232   /* convert media_time to mov format */
1233   mov_time =
1234       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1235
1236   sample = str->samples;
1237   if (mov_time == sample->timestamp + sample->pts_offset)
1238     return index;
1239
1240   /* use faster search if requested time in already parsed range */
1241   sample = str->samples + str->stbl_index;
1242   if (str->stbl_index >= 0 &&
1243       mov_time <= (sample->timestamp + sample->pts_offset))
1244     return gst_qtdemux_find_index (qtdemux, str, media_time);
1245
1246   while (index < str->n_samples - 1) {
1247     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1248       goto parse_failed;
1249
1250     sample = str->samples + index + 1;
1251     if (mov_time < (sample->timestamp + sample->pts_offset))
1252       break;
1253
1254     index++;
1255   }
1256   return index;
1257
1258   /* ERRORS */
1259 parse_failed:
1260   {
1261     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1262     return -1;
1263   }
1264 }
1265
1266 /* find the index of the keyframe needed to decode the sample at @index
1267  * of stream @str, or of a subsequent keyframe (depending on @next)
1268  *
1269  * Returns the index of the keyframe.
1270  */
1271 static guint32
1272 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1273     guint32 index, gboolean next)
1274 {
1275   guint32 new_index = index;
1276
1277   if (index >= str->n_samples) {
1278     new_index = str->n_samples;
1279     goto beach;
1280   }
1281
1282   /* all keyframes, return index */
1283   if (str->all_keyframe) {
1284     new_index = index;
1285     goto beach;
1286   }
1287
1288   /* else search until we have a keyframe */
1289   while (new_index < str->n_samples) {
1290     if (next && !qtdemux_parse_samples (qtdemux, str, new_index))
1291       goto parse_failed;
1292
1293     if (str->samples[new_index].keyframe)
1294       break;
1295
1296     if (new_index == 0)
1297       break;
1298
1299     if (next)
1300       new_index++;
1301     else
1302       new_index--;
1303   }
1304
1305   if (new_index == str->n_samples) {
1306     GST_DEBUG_OBJECT (qtdemux, "no next keyframe");
1307     new_index = -1;
1308   }
1309
1310 beach:
1311   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index %s index %u "
1312       "gave %u", next ? "after" : "before", index, new_index);
1313
1314   return new_index;
1315
1316   /* ERRORS */
1317 parse_failed:
1318   {
1319     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", new_index);
1320     return -1;
1321   }
1322 }
1323
1324 /* find the segment for @time_position for @stream
1325  *
1326  * Returns the index of the segment containing @time_position.
1327  * Returns the last segment and sets the @eos variable to TRUE
1328  * if the time is beyond the end. @eos may be NULL
1329  */
1330 static guint32
1331 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1332     GstClockTime time_position)
1333 {
1334   gint i;
1335   guint32 seg_idx;
1336
1337   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1338       GST_TIME_ARGS (time_position));
1339
1340   seg_idx = -1;
1341   for (i = 0; i < stream->n_segments; i++) {
1342     QtDemuxSegment *segment = &stream->segments[i];
1343
1344     GST_LOG_OBJECT (stream->pad,
1345         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1346         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1347
1348     /* For the last segment we include stop_time in the last segment */
1349     if (i < stream->n_segments - 1) {
1350       if (segment->time <= time_position && time_position < segment->stop_time) {
1351         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1352         seg_idx = i;
1353         break;
1354       }
1355     } else {
1356       /* Last segment always matches */
1357       seg_idx = i;
1358       break;
1359     }
1360   }
1361   return seg_idx;
1362 }
1363
1364 /* move the stream @str to the sample position @index.
1365  *
1366  * Updates @str->sample_index and marks discontinuity if needed.
1367  */
1368 static void
1369 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1370     guint32 index)
1371 {
1372   /* no change needed */
1373   if (index == str->sample_index)
1374     return;
1375
1376   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1377       str->n_samples);
1378
1379   /* position changed, we have a discont */
1380   str->sample_index = index;
1381   str->offset_in_sample = 0;
1382   /* Each time we move in the stream we store the position where we are
1383    * starting from */
1384   str->from_sample = index;
1385   str->discont = TRUE;
1386 }
1387
1388 static void
1389 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1390     gboolean use_sparse, gboolean next, gint64 * key_time, gint64 * key_offset)
1391 {
1392   guint64 min_offset;
1393   gint64 min_byte_offset = -1;
1394   gint n;
1395
1396   min_offset = desired_time;
1397
1398   /* for each stream, find the index of the sample in the segment
1399    * and move back to the previous keyframe. */
1400   for (n = 0; n < qtdemux->n_streams; n++) {
1401     QtDemuxStream *str;
1402     guint32 index, kindex;
1403     guint32 seg_idx;
1404     GstClockTime media_start;
1405     GstClockTime media_time;
1406     GstClockTime seg_time;
1407     QtDemuxSegment *seg;
1408     gboolean empty_segment = FALSE;
1409
1410     str = qtdemux->streams[n];
1411
1412     if (CUR_STREAM (str)->sparse && !use_sparse)
1413       continue;
1414
1415     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1416     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1417
1418     /* get segment and time in the segment */
1419     seg = &str->segments[seg_idx];
1420     seg_time = (desired_time - seg->time) * seg->rate;
1421
1422     while (QTSEGMENT_IS_EMPTY (seg)) {
1423       seg_time = 0;
1424       empty_segment = TRUE;
1425       GST_DEBUG_OBJECT (str->pad, "Segment %d is empty, moving to next one",
1426           seg_idx);
1427       seg_idx++;
1428       if (seg_idx == str->n_segments)
1429         break;
1430       seg = &str->segments[seg_idx];
1431     }
1432
1433     if (seg_idx == str->n_segments) {
1434       /* FIXME track shouldn't have the last segment as empty, but if it
1435        * happens we better handle it */
1436       continue;
1437     }
1438
1439     /* get the media time in the segment */
1440     media_start = seg->media_start + seg_time;
1441
1442     /* get the index of the sample with media time */
1443     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1444     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1445         " at offset %" G_GUINT64_FORMAT " (empty segment: %d)",
1446         GST_TIME_ARGS (media_start), index, str->samples[index].offset,
1447         empty_segment);
1448
1449     /* shift to next frame if we are looking for next keyframe */
1450     if (next && QTSAMPLE_PTS_NO_CSLG (str, &str->samples[index]) < media_start
1451         && index < str->stbl_index)
1452       index++;
1453
1454     if (!empty_segment) {
1455       /* find previous keyframe */
1456       kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, next);
1457
1458       /* we will settle for one before if none found after */
1459       if (next && kindex == -1)
1460         kindex = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
1461
1462       /* if the keyframe is at a different position, we need to update the
1463        * requested seek time */
1464       if (index != kindex) {
1465         index = kindex;
1466
1467         /* get timestamp of keyframe */
1468         media_time = QTSAMPLE_PTS_NO_CSLG (str, &str->samples[kindex]);
1469         GST_DEBUG_OBJECT (qtdemux,
1470             "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1471             G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1472             str->samples[kindex].offset);
1473
1474         /* keyframes in the segment get a chance to change the
1475          * desired_offset. keyframes out of the segment are
1476          * ignored. */
1477         if (media_time >= seg->media_start) {
1478           GstClockTime seg_time;
1479
1480           /* this keyframe is inside the segment, convert back to
1481            * segment time */
1482           seg_time = (media_time - seg->media_start) + seg->time;
1483           if ((!next && (seg_time < min_offset)) ||
1484               (next && (seg_time > min_offset)))
1485             min_offset = seg_time;
1486         }
1487       }
1488     }
1489
1490     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1491       min_byte_offset = str->samples[index].offset;
1492   }
1493
1494   if (key_time)
1495     *key_time = min_offset;
1496   if (key_offset)
1497     *key_offset = min_byte_offset;
1498 }
1499
1500 static gboolean
1501 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1502     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1503 {
1504   gboolean res;
1505
1506   g_return_val_if_fail (format != NULL, FALSE);
1507   g_return_val_if_fail (cur != NULL, FALSE);
1508   g_return_val_if_fail (stop != NULL, FALSE);
1509
1510   if (*format == GST_FORMAT_TIME)
1511     return TRUE;
1512
1513   res = TRUE;
1514   if (cur_type != GST_SEEK_TYPE_NONE)
1515     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1516   if (res && stop_type != GST_SEEK_TYPE_NONE)
1517     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1518
1519   if (res)
1520     *format = GST_FORMAT_TIME;
1521
1522   return res;
1523 }
1524
1525 /* perform seek in push based mode:
1526    find BYTE position to move to based on time and delegate to upstream
1527 */
1528 static gboolean
1529 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1530 {
1531   gdouble rate;
1532   GstFormat format;
1533   GstSeekFlags flags;
1534   GstSeekType cur_type, stop_type;
1535   gint64 cur, stop, key_cur;
1536   gboolean res;
1537   gint64 byte_cur;
1538   gint64 original_stop;
1539   guint32 seqnum;
1540
1541   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1542
1543   gst_event_parse_seek (event, &rate, &format, &flags,
1544       &cur_type, &cur, &stop_type, &stop);
1545   seqnum = gst_event_get_seqnum (event);
1546
1547   /* only forward streaming and seeking is possible */
1548   if (rate <= 0)
1549     goto unsupported_seek;
1550
1551   /* convert to TIME if needed and possible */
1552   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1553           stop_type, &stop))
1554     goto no_format;
1555
1556   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1557    * the original stop position to use when upstream pushes the new segment
1558    * for this seek */
1559   original_stop = stop;
1560   stop = -1;
1561
1562   /* find reasonable corresponding BYTE position,
1563    * also try to mind about keyframes, since we can not go back a bit for them
1564    * later on */
1565   /* determining @next here based on SNAP_BEFORE/SNAP_AFTER should
1566    * mostly just work, but let's not yet boldly go there  ... */
1567   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, FALSE, &key_cur, &byte_cur);
1568
1569   if (byte_cur == -1)
1570     goto abort_seek;
1571
1572   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1573       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1574       stop);
1575
1576   GST_OBJECT_LOCK (qtdemux);
1577   qtdemux->seek_offset = byte_cur;
1578   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1579     qtdemux->push_seek_start = cur;
1580   } else {
1581     qtdemux->push_seek_start = key_cur;
1582   }
1583
1584   if (stop_type == GST_SEEK_TYPE_NONE) {
1585     qtdemux->push_seek_stop = qtdemux->segment.stop;
1586   } else {
1587     qtdemux->push_seek_stop = original_stop;
1588   }
1589   GST_OBJECT_UNLOCK (qtdemux);
1590
1591   /* BYTE seek event */
1592   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1593       stop_type, stop);
1594   gst_event_set_seqnum (event, seqnum);
1595   res = gst_pad_push_event (qtdemux->sinkpad, event);
1596
1597   return res;
1598
1599   /* ERRORS */
1600 abort_seek:
1601   {
1602     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1603         "seek aborted.");
1604     return FALSE;
1605   }
1606 unsupported_seek:
1607   {
1608     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1609     return FALSE;
1610   }
1611 no_format:
1612   {
1613     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1614     return FALSE;
1615   }
1616 }
1617
1618 /* perform the seek.
1619  *
1620  * We set all segment_indexes in the streams to unknown and
1621  * adjust the time_position to the desired position. this is enough
1622  * to trigger a segment switch in the streaming thread to start
1623  * streaming from the desired position.
1624  *
1625  * Keyframe seeking is a little more complicated when dealing with
1626  * segments. Ideally we want to move to the previous keyframe in
1627  * the segment but there might not be a keyframe in the segment. In
1628  * fact, none of the segments could contain a keyframe. We take a
1629  * practical approach: seek to the previous keyframe in the segment,
1630  * if there is none, seek to the beginning of the segment.
1631  *
1632  * Called with STREAM_LOCK
1633  */
1634 static gboolean
1635 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1636     guint32 seqnum, GstSeekFlags flags)
1637 {
1638   gint64 desired_offset;
1639   gint n;
1640
1641   desired_offset = segment->position;
1642
1643   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1644       GST_TIME_ARGS (desired_offset));
1645
1646   /* may not have enough fragmented info to do this adjustment,
1647    * and we can't scan (and probably should not) at this time with
1648    * possibly flushing upstream */
1649   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1650     gint64 min_offset;
1651     gboolean next, before, after;
1652
1653     before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
1654     after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
1655     next = after && !before;
1656     if (segment->rate < 0)
1657       next = !next;
1658
1659     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, next, &min_offset,
1660         NULL);
1661     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1662         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1663     desired_offset = min_offset;
1664   }
1665
1666   /* and set all streams to the final position */
1667   gst_flow_combiner_reset (qtdemux->flowcombiner);
1668   qtdemux->segment_seqnum = seqnum;
1669   for (n = 0; n < qtdemux->n_streams; n++) {
1670     QtDemuxStream *stream = qtdemux->streams[n];
1671
1672     stream->time_position = desired_offset;
1673     stream->accumulated_base = 0;
1674     stream->sample_index = -1;
1675     stream->offset_in_sample = 0;
1676     stream->segment_index = -1;
1677     stream->sent_eos = FALSE;
1678
1679     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1680       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1681   }
1682   segment->position = desired_offset;
1683   segment->time = desired_offset;
1684   if (segment->rate >= 0) {
1685     segment->start = desired_offset;
1686
1687     /* we stop at the end */
1688     if (segment->stop == -1)
1689       segment->stop = segment->duration;
1690   } else {
1691     segment->stop = desired_offset;
1692   }
1693
1694   if (qtdemux->fragmented)
1695     qtdemux->fragmented_seek_pending = TRUE;
1696
1697   return TRUE;
1698 }
1699
1700 /* do a seek in pull based mode */
1701 static gboolean
1702 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1703 {
1704   gdouble rate;
1705   GstFormat format;
1706   GstSeekFlags flags;
1707   GstSeekType cur_type, stop_type;
1708   gint64 cur, stop;
1709   gboolean flush;
1710   gboolean update;
1711   GstSegment seeksegment;
1712   guint32 seqnum = 0;
1713   GstEvent *flush_event;
1714   gboolean ret;
1715
1716   if (event) {
1717     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1718
1719     gst_event_parse_seek (event, &rate, &format, &flags,
1720         &cur_type, &cur, &stop_type, &stop);
1721     seqnum = gst_event_get_seqnum (event);
1722
1723     /* we have to have a format as the segment format. Try to convert
1724      * if not. */
1725     if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1726             stop_type, &stop))
1727       goto no_format;
1728
1729     GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1730   } else {
1731     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1732     flags = 0;
1733   }
1734
1735   flush = flags & GST_SEEK_FLAG_FLUSH;
1736
1737   /* stop streaming, either by flushing or by pausing the task */
1738   if (flush) {
1739     flush_event = gst_event_new_flush_start ();
1740     if (seqnum)
1741       gst_event_set_seqnum (flush_event, seqnum);
1742     /* unlock upstream pull_range */
1743     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1744     /* make sure out loop function exits */
1745     gst_qtdemux_push_event (qtdemux, flush_event);
1746   } else {
1747     /* non flushing seek, pause the task */
1748     gst_pad_pause_task (qtdemux->sinkpad);
1749   }
1750
1751   /* wait for streaming to finish */
1752   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1753
1754   /* copy segment, we need this because we still need the old
1755    * segment when we close the current segment. */
1756   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1757
1758   if (event) {
1759     /* configure the segment with the seek variables */
1760     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1761     if (!gst_segment_do_seek (&seeksegment, rate, format, flags,
1762             cur_type, cur, stop_type, stop, &update)) {
1763       ret = FALSE;
1764       GST_ERROR_OBJECT (qtdemux, "inconsistent seek values, doing nothing");
1765     } else {
1766       /* now do the seek */
1767       ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1768     }
1769   } else {
1770     /* now do the seek */
1771     ret = gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1772   }
1773
1774   /* prepare for streaming again */
1775   if (flush) {
1776     flush_event = gst_event_new_flush_stop (TRUE);
1777     if (seqnum)
1778       gst_event_set_seqnum (flush_event, seqnum);
1779
1780     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1781     gst_qtdemux_push_event (qtdemux, flush_event);
1782   }
1783
1784   /* commit the new segment */
1785   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1786
1787   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1788     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1789         qtdemux->segment.format, qtdemux->segment.position);
1790     if (seqnum)
1791       gst_message_set_seqnum (msg, seqnum);
1792     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1793   }
1794
1795   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1796   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1797       qtdemux->sinkpad, NULL);
1798
1799   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1800
1801   return ret;
1802
1803   /* ERRORS */
1804 no_format:
1805   {
1806     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1807     return FALSE;
1808   }
1809 }
1810
1811 static gboolean
1812 qtdemux_ensure_index (GstQTDemux * qtdemux)
1813 {
1814   guint i;
1815
1816   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1817
1818   /* Build complete index */
1819   for (i = 0; i < qtdemux->n_streams; i++) {
1820     QtDemuxStream *stream = qtdemux->streams[i];
1821
1822     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1823       goto parse_error;
1824   }
1825   return TRUE;
1826
1827   /* ERRORS */
1828 parse_error:
1829   {
1830     GST_LOG_OBJECT (qtdemux,
1831         "Building complete index of stream %u for seeking failed!", i);
1832     return FALSE;
1833   }
1834 }
1835
1836 static gboolean
1837 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1838     GstEvent * event)
1839 {
1840   gboolean res = TRUE;
1841   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1842
1843   switch (GST_EVENT_TYPE (event)) {
1844     case GST_EVENT_SEEK:
1845     {
1846 #ifndef GST_DISABLE_GST_DEBUG
1847       GstClockTime ts = gst_util_get_timestamp ();
1848 #endif
1849       guint32 seqnum = gst_event_get_seqnum (event);
1850
1851       if (seqnum == qtdemux->segment_seqnum) {
1852         GST_LOG_OBJECT (pad,
1853             "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
1854         gst_event_unref (event);
1855         return TRUE;
1856       }
1857
1858       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1859         /* seek should be handled by upstream, we might need to re-download fragments */
1860         GST_DEBUG_OBJECT (qtdemux,
1861             "let upstream handle seek for fragmented playback");
1862         goto upstream;
1863       }
1864
1865       /* Build complete index for seeking;
1866        * if not a fragmented file at least */
1867       if (!qtdemux->fragmented)
1868         if (!qtdemux_ensure_index (qtdemux))
1869           goto index_failed;
1870 #ifndef GST_DISABLE_GST_DEBUG
1871       ts = gst_util_get_timestamp () - ts;
1872       GST_INFO_OBJECT (qtdemux,
1873           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1874 #endif
1875     }
1876       if (qtdemux->pullbased) {
1877         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1878       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1879         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1880         res = TRUE;
1881       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1882           && !qtdemux->fragmented) {
1883         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1884       } else {
1885         GST_DEBUG_OBJECT (qtdemux,
1886             "ignoring seek in push mode in current state");
1887         res = FALSE;
1888       }
1889       gst_event_unref (event);
1890       break;
1891     default:
1892     upstream:
1893       res = gst_pad_event_default (pad, parent, event);
1894       break;
1895   }
1896
1897 done:
1898   return res;
1899
1900   /* ERRORS */
1901 index_failed:
1902   {
1903     GST_ERROR_OBJECT (qtdemux, "Index failed");
1904     gst_event_unref (event);
1905     res = FALSE;
1906     goto done;
1907   }
1908 }
1909
1910 /* stream/index return sample that is min/max w.r.t. byte position,
1911  * time is min/max w.r.t. time of samples,
1912  * the latter need not be time of the former sample */
1913 static void
1914 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1915     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1916 {
1917   gint i, n, index;
1918   gint64 time, min_time;
1919   QtDemuxStream *stream;
1920
1921   min_time = -1;
1922   stream = NULL;
1923   index = -1;
1924
1925   for (n = 0; n < qtdemux->n_streams; ++n) {
1926     QtDemuxStream *str;
1927     gint inc;
1928     gboolean set_sample;
1929
1930     str = qtdemux->streams[n];
1931     set_sample = !set;
1932
1933     if (fw) {
1934       i = 0;
1935       inc = 1;
1936     } else {
1937       i = str->n_samples - 1;
1938       inc = -1;
1939     }
1940
1941     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1942       if (str->samples[i].size == 0)
1943         continue;
1944
1945       if (fw && (str->samples[i].offset < byte_pos))
1946         continue;
1947
1948       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1949         continue;
1950
1951       /* move stream to first available sample */
1952       if (set) {
1953         gst_qtdemux_move_stream (qtdemux, str, i);
1954         set_sample = TRUE;
1955       }
1956
1957       /* avoid index from sparse streams since they might be far away */
1958       if (!CUR_STREAM (str)->sparse) {
1959         /* determine min/max time */
1960         time = QTSAMPLE_PTS (str, &str->samples[i]);
1961         if (min_time == -1 || (!fw && time > min_time) ||
1962             (fw && time < min_time)) {
1963           min_time = time;
1964         }
1965
1966         /* determine stream with leading sample, to get its position */
1967         if (!stream ||
1968             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1969             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1970           stream = str;
1971           index = i;
1972         }
1973       }
1974       break;
1975     }
1976
1977     /* no sample for this stream, mark eos */
1978     if (!set_sample)
1979       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1980   }
1981
1982   if (_time)
1983     *_time = min_time;
1984   if (_stream)
1985     *_stream = stream;
1986   if (_index)
1987     *_index = index;
1988 }
1989
1990 static QtDemuxStream *
1991 _create_stream (void)
1992 {
1993   QtDemuxStream *stream;
1994
1995   stream = g_new0 (QtDemuxStream, 1);
1996   /* new streams always need a discont */
1997   stream->discont = TRUE;
1998   /* we enable clipping for raw audio/video streams */
1999   stream->need_clip = FALSE;
2000   stream->need_process = FALSE;
2001   stream->segment_index = -1;
2002   stream->time_position = 0;
2003   stream->sample_index = -1;
2004   stream->offset_in_sample = 0;
2005   stream->new_stream = TRUE;
2006   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
2007   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
2008   stream->protected = FALSE;
2009   stream->protection_scheme_type = 0;
2010   stream->protection_scheme_version = 0;
2011   stream->protection_scheme_info = NULL;
2012   stream->n_samples_moof = 0;
2013   stream->duration_moof = 0;
2014   stream->duration_last_moof = 0;
2015   stream->alignment = 1;
2016   stream->stream_tags = gst_tag_list_new_empty ();
2017   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2018   g_queue_init (&stream->protection_scheme_event_queue);
2019   return stream;
2020 }
2021
2022 static gboolean
2023 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
2024 {
2025   GstStructure *structure;
2026   const gchar *variant;
2027   const GstCaps *mediacaps = NULL;
2028
2029   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
2030
2031   structure = gst_caps_get_structure (caps, 0);
2032   variant = gst_structure_get_string (structure, "variant");
2033
2034   if (variant && strcmp (variant, "mss-fragmented") == 0) {
2035     QtDemuxStream *stream;
2036     const GValue *value;
2037
2038     demux->fragmented = TRUE;
2039     demux->mss_mode = TRUE;
2040
2041     if (demux->n_streams > 1) {
2042       /* can't do this, we can only renegotiate for another mss format */
2043       return FALSE;
2044     }
2045
2046     value = gst_structure_get_value (structure, "media-caps");
2047     /* create stream */
2048     if (value) {
2049       const GValue *timescale_v;
2050
2051       /* TODO update when stream changes during playback */
2052
2053       if (demux->n_streams == 0) {
2054         stream = _create_stream ();
2055         demux->streams[demux->n_streams] = stream;
2056         demux->n_streams = 1;
2057         /* mss has no stsd/stsd entry, use id 0 as default */
2058         stream->stsd_entries_length = 1;
2059         stream->stsd_sample_description_id = stream->cur_stsd_entry_index = 0;
2060         stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, 1);
2061       } else {
2062         stream = demux->streams[0];
2063       }
2064
2065       timescale_v = gst_structure_get_value (structure, "timescale");
2066       if (timescale_v) {
2067         stream->timescale = g_value_get_uint64 (timescale_v);
2068       } else {
2069         /* default mss timescale */
2070         stream->timescale = 10000000;
2071       }
2072       demux->timescale = stream->timescale;
2073
2074       mediacaps = gst_value_get_caps (value);
2075       if (!CUR_STREAM (stream)->caps
2076           || !gst_caps_is_equal_fixed (mediacaps, CUR_STREAM (stream)->caps)) {
2077         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
2078             mediacaps);
2079         stream->new_caps = TRUE;
2080       }
2081       gst_caps_replace (&CUR_STREAM (stream)->caps, (GstCaps *) mediacaps);
2082       structure = gst_caps_get_structure (mediacaps, 0);
2083       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
2084         stream->subtype = FOURCC_vide;
2085
2086         gst_structure_get_int (structure, "width", &CUR_STREAM (stream)->width);
2087         gst_structure_get_int (structure, "height",
2088             &CUR_STREAM (stream)->height);
2089         gst_structure_get_fraction (structure, "framerate",
2090             &CUR_STREAM (stream)->fps_n, &CUR_STREAM (stream)->fps_d);
2091       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
2092         gint rate = 0;
2093         stream->subtype = FOURCC_soun;
2094         gst_structure_get_int (structure, "channels",
2095             &CUR_STREAM (stream)->n_channels);
2096         gst_structure_get_int (structure, "rate", &rate);
2097         CUR_STREAM (stream)->rate = rate;
2098       }
2099     }
2100     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
2101   } else {
2102     demux->mss_mode = FALSE;
2103   }
2104
2105   return TRUE;
2106 }
2107
2108 static void
2109 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
2110 {
2111   gint n;
2112
2113   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
2114   gst_pad_stop_task (qtdemux->sinkpad);
2115
2116   if (hard || qtdemux->upstream_format_is_time) {
2117     qtdemux->state = QTDEMUX_STATE_INITIAL;
2118     qtdemux->neededbytes = 16;
2119     qtdemux->todrop = 0;
2120     qtdemux->pullbased = FALSE;
2121     qtdemux->posted_redirect = FALSE;
2122     qtdemux->first_mdat = -1;
2123     qtdemux->header_size = 0;
2124     qtdemux->mdatoffset = -1;
2125     qtdemux->restoredata_offset = -1;
2126     if (qtdemux->mdatbuffer)
2127       gst_buffer_unref (qtdemux->mdatbuffer);
2128     if (qtdemux->restoredata_buffer)
2129       gst_buffer_unref (qtdemux->restoredata_buffer);
2130     qtdemux->mdatbuffer = NULL;
2131     qtdemux->restoredata_buffer = NULL;
2132     qtdemux->mdatleft = 0;
2133     qtdemux->mdatsize = 0;
2134     if (qtdemux->comp_brands)
2135       gst_buffer_unref (qtdemux->comp_brands);
2136     qtdemux->comp_brands = NULL;
2137     qtdemux->last_moov_offset = -1;
2138     if (qtdemux->moov_node_compressed) {
2139       g_node_destroy (qtdemux->moov_node_compressed);
2140       if (qtdemux->moov_node)
2141         g_free (qtdemux->moov_node->data);
2142     }
2143     qtdemux->moov_node_compressed = NULL;
2144     if (qtdemux->moov_node)
2145       g_node_destroy (qtdemux->moov_node);
2146     qtdemux->moov_node = NULL;
2147     if (qtdemux->tag_list)
2148       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
2149     qtdemux->tag_list = gst_tag_list_new_empty ();
2150     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
2151 #if 0
2152     if (qtdemux->element_index)
2153       gst_object_unref (qtdemux->element_index);
2154     qtdemux->element_index = NULL;
2155 #endif
2156     qtdemux->major_brand = 0;
2157     if (qtdemux->pending_newsegment)
2158       gst_event_unref (qtdemux->pending_newsegment);
2159     qtdemux->pending_newsegment = NULL;
2160     qtdemux->upstream_format_is_time = FALSE;
2161     qtdemux->upstream_seekable = FALSE;
2162     qtdemux->upstream_size = 0;
2163
2164     qtdemux->fragment_start = -1;
2165     qtdemux->fragment_start_offset = -1;
2166     qtdemux->duration = 0;
2167     qtdemux->moof_offset = 0;
2168     qtdemux->chapters_track_id = 0;
2169     qtdemux->have_group_id = FALSE;
2170     qtdemux->group_id = G_MAXUINT;
2171
2172     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2173         NULL);
2174     g_queue_clear (&qtdemux->protection_event_queue);
2175   }
2176   qtdemux->offset = 0;
2177   gst_adapter_clear (qtdemux->adapter);
2178   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2179   qtdemux->segment_seqnum = 0;
2180
2181   if (hard) {
2182     for (n = 0; n < qtdemux->n_streams; n++) {
2183       gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2184       qtdemux->streams[n] = NULL;
2185     }
2186     qtdemux->n_streams = 0;
2187     qtdemux->n_video_streams = 0;
2188     qtdemux->n_audio_streams = 0;
2189     qtdemux->n_sub_streams = 0;
2190     qtdemux->exposed = FALSE;
2191     qtdemux->fragmented = FALSE;
2192     qtdemux->mss_mode = FALSE;
2193     gst_caps_replace (&qtdemux->media_caps, NULL);
2194     qtdemux->timescale = 0;
2195     qtdemux->got_moov = FALSE;
2196     if (qtdemux->protection_system_ids) {
2197       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2198       qtdemux->protection_system_ids = NULL;
2199     }
2200   } else if (qtdemux->mss_mode) {
2201     gst_flow_combiner_reset (qtdemux->flowcombiner);
2202     for (n = 0; n < qtdemux->n_streams; n++)
2203       gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2204   } else {
2205     gst_flow_combiner_reset (qtdemux->flowcombiner);
2206     for (n = 0; n < qtdemux->n_streams; n++) {
2207       qtdemux->streams[n]->sent_eos = FALSE;
2208       qtdemux->streams[n]->time_position = 0;
2209       qtdemux->streams[n]->accumulated_base = 0;
2210     }
2211     if (!qtdemux->pending_newsegment) {
2212       qtdemux->pending_newsegment = gst_event_new_segment (&qtdemux->segment);
2213       if (qtdemux->segment_seqnum)
2214         gst_event_set_seqnum (qtdemux->pending_newsegment,
2215             qtdemux->segment_seqnum);
2216     }
2217   }
2218 }
2219
2220
2221 /* Maps the @segment to the qt edts internal segments and pushes
2222  * the correspnding segment event.
2223  *
2224  * If it ends up being at a empty segment, a gap will be pushed and the next
2225  * edts segment will be activated in sequence.
2226  *
2227  * To be used in push-mode only */
2228 static void
2229 gst_qtdemux_map_and_push_segments (GstQTDemux * qtdemux, GstSegment * segment)
2230 {
2231   gint n, i;
2232
2233   for (n = 0; n < qtdemux->n_streams; n++) {
2234     QtDemuxStream *stream = qtdemux->streams[n];
2235
2236     stream->time_position = segment->start;
2237
2238     /* in push mode we should be guaranteed that we will have empty segments
2239      * at the beginning and then one segment after, other scenarios are not
2240      * supported and are discarded when parsing the edts */
2241     for (i = 0; i < stream->n_segments; i++) {
2242       if (stream->segments[i].stop_time > segment->start) {
2243         gst_qtdemux_activate_segment (qtdemux, stream, i,
2244             stream->time_position);
2245         if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
2246           /* push the empty segment and move to the next one */
2247           gst_qtdemux_send_gap_for_segment (qtdemux, stream, i,
2248               stream->time_position);
2249           continue;
2250         }
2251
2252         g_assert (i == stream->n_segments - 1);
2253       }
2254     }
2255   }
2256 }
2257
2258 static gboolean
2259 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2260     GstEvent * event)
2261 {
2262   GstQTDemux *demux = GST_QTDEMUX (parent);
2263   gboolean res = TRUE;
2264
2265   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2266
2267   switch (GST_EVENT_TYPE (event)) {
2268     case GST_EVENT_SEGMENT:
2269     {
2270       gint64 offset = 0;
2271       QtDemuxStream *stream;
2272       gint idx;
2273       GstSegment segment;
2274
2275       /* some debug output */
2276       gst_event_copy_segment (event, &segment);
2277       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2278           &segment);
2279
2280       /* erase any previously set segment */
2281       gst_event_replace (&demux->pending_newsegment, NULL);
2282
2283       if (segment.format == GST_FORMAT_TIME) {
2284         GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2285         gst_event_replace (&demux->pending_newsegment, event);
2286         demux->upstream_format_is_time = TRUE;
2287       } else {
2288         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2289             "not in time format");
2290
2291         /* chain will send initial newsegment after pads have been added */
2292         if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2293           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2294           goto exit;
2295         }
2296       }
2297
2298       /* check if this matches a time seek we received previously
2299        * FIXME for backwards compatibility reasons we use the
2300        * seek_offset here to compare. In the future we might want to
2301        * change this to use the seqnum as it uniquely should identify
2302        * the segment that corresponds to the seek. */
2303       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2304           ", received segment offset %" G_GINT64_FORMAT,
2305           demux->seek_offset, segment.start);
2306       if (segment.format == GST_FORMAT_BYTES
2307           && demux->seek_offset == segment.start) {
2308         GST_OBJECT_LOCK (demux);
2309         offset = segment.start;
2310
2311         segment.format = GST_FORMAT_TIME;
2312         segment.start = demux->push_seek_start;
2313         segment.stop = demux->push_seek_stop;
2314         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2315             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2316             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2317         GST_OBJECT_UNLOCK (demux);
2318       }
2319
2320       /* we only expect a BYTE segment, e.g. following a seek */
2321       if (segment.format == GST_FORMAT_BYTES) {
2322         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2323           offset = segment.start;
2324
2325           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2326               NULL, (gint64 *) & segment.start);
2327           if ((gint64) segment.start < 0)
2328             segment.start = 0;
2329         }
2330         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2331           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2332               NULL, (gint64 *) & segment.stop);
2333           /* keyframe seeking should already arrange for start >= stop,
2334            * but make sure in other rare cases */
2335           segment.stop = MAX (segment.stop, segment.start);
2336         }
2337       } else if (segment.format == GST_FORMAT_TIME) {
2338         /* push all data on the adapter before starting this
2339          * new segment */
2340         gst_qtdemux_process_adapter (demux, TRUE);
2341       } else {
2342         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2343         goto exit;
2344       }
2345
2346       /* We shouldn't modify upstream driven TIME FORMAT segment */
2347       if (!demux->upstream_format_is_time) {
2348         /* accept upstream's notion of segment and distribute along */
2349         segment.format = GST_FORMAT_TIME;
2350         segment.position = segment.time = segment.start;
2351         segment.duration = demux->segment.duration;
2352         segment.base = gst_segment_to_running_time (&demux->segment,
2353             GST_FORMAT_TIME, demux->segment.position);
2354       }
2355
2356       gst_segment_copy_into (&segment, &demux->segment);
2357       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2358
2359       /* map segment to internal qt segments and push on each stream */
2360       if (demux->n_streams) {
2361         if (demux->fragmented) {
2362           GstEvent *segment_event = gst_event_new_segment (&segment);
2363
2364           gst_event_replace (&demux->pending_newsegment, NULL);
2365           gst_event_set_seqnum (segment_event, demux->segment_seqnum);
2366           gst_qtdemux_push_event (demux, segment_event);
2367         } else {
2368           gst_event_replace (&demux->pending_newsegment, NULL);
2369           gst_qtdemux_map_and_push_segments (demux, &segment);
2370         }
2371       }
2372
2373       /* clear leftover in current segment, if any */
2374       gst_adapter_clear (demux->adapter);
2375
2376       /* set up streaming thread */
2377       demux->offset = offset;
2378       if (demux->upstream_format_is_time) {
2379         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2380             "set values to restart reading from a new atom");
2381         demux->neededbytes = 16;
2382         demux->todrop = 0;
2383       } else {
2384         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2385             NULL);
2386         if (stream) {
2387           demux->todrop = stream->samples[idx].offset - offset;
2388           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2389         } else {
2390           /* set up for EOS */
2391           demux->neededbytes = -1;
2392           demux->todrop = 0;
2393         }
2394       }
2395     exit:
2396       gst_event_unref (event);
2397       res = TRUE;
2398       goto drop;
2399     }
2400     case GST_EVENT_FLUSH_START:
2401     {
2402       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2403         gst_event_unref (event);
2404         goto drop;
2405       }
2406       break;
2407     }
2408     case GST_EVENT_FLUSH_STOP:
2409     {
2410       guint64 dur;
2411
2412       dur = demux->segment.duration;
2413       gst_qtdemux_reset (demux, FALSE);
2414       demux->segment.duration = dur;
2415
2416       if (gst_event_get_seqnum (event) == demux->offset_seek_seqnum) {
2417         gst_event_unref (event);
2418         goto drop;
2419       }
2420       break;
2421     }
2422     case GST_EVENT_EOS:
2423       /* If we are in push mode, and get an EOS before we've seen any streams,
2424        * then error out - we have nowhere to send the EOS */
2425       if (!demux->pullbased) {
2426         gint i;
2427         gboolean has_valid_stream = FALSE;
2428         for (i = 0; i < demux->n_streams; i++) {
2429           if (demux->streams[i]->pad != NULL) {
2430             has_valid_stream = TRUE;
2431             break;
2432           }
2433         }
2434         if (!has_valid_stream)
2435           gst_qtdemux_post_no_playable_stream_error (demux);
2436         else {
2437           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2438               (guint) gst_adapter_available (demux->adapter));
2439           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2440             res = FALSE;
2441           }
2442         }
2443       }
2444       break;
2445     case GST_EVENT_CAPS:{
2446       GstCaps *caps = NULL;
2447
2448       gst_event_parse_caps (event, &caps);
2449       gst_qtdemux_setcaps (demux, caps);
2450       res = TRUE;
2451       gst_event_unref (event);
2452       goto drop;
2453     }
2454     case GST_EVENT_PROTECTION:
2455     {
2456       const gchar *system_id = NULL;
2457
2458       gst_event_parse_protection (event, &system_id, NULL, NULL);
2459       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2460           system_id);
2461       gst_qtdemux_append_protection_system_id (demux, system_id);
2462       /* save the event for later, for source pads that have not been created */
2463       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2464       /* send it to all pads that already exist */
2465       gst_qtdemux_push_event (demux, event);
2466       res = TRUE;
2467       goto drop;
2468     }
2469     default:
2470       break;
2471   }
2472
2473   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2474
2475 drop:
2476   return res;
2477 }
2478
2479 #if 0
2480 static void
2481 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2482 {
2483   GstQTDemux *demux = GST_QTDEMUX (element);
2484
2485   GST_OBJECT_LOCK (demux);
2486   if (demux->element_index)
2487     gst_object_unref (demux->element_index);
2488   if (index) {
2489     demux->element_index = gst_object_ref (index);
2490   } else {
2491     demux->element_index = NULL;
2492   }
2493   GST_OBJECT_UNLOCK (demux);
2494   /* object lock might be taken again */
2495   if (index)
2496     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2497   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2498       demux->element_index, demux->index_id);
2499 }
2500
2501 static GstIndex *
2502 gst_qtdemux_get_index (GstElement * element)
2503 {
2504   GstIndex *result = NULL;
2505   GstQTDemux *demux = GST_QTDEMUX (element);
2506
2507   GST_OBJECT_LOCK (demux);
2508   if (demux->element_index)
2509     result = gst_object_ref (demux->element_index);
2510   GST_OBJECT_UNLOCK (demux);
2511
2512   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2513
2514   return result;
2515 }
2516 #endif
2517
2518 static void
2519 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2520 {
2521   g_free ((gpointer) stream->stco.data);
2522   stream->stco.data = NULL;
2523   g_free ((gpointer) stream->stsz.data);
2524   stream->stsz.data = NULL;
2525   g_free ((gpointer) stream->stsc.data);
2526   stream->stsc.data = NULL;
2527   g_free ((gpointer) stream->stts.data);
2528   stream->stts.data = NULL;
2529   g_free ((gpointer) stream->stss.data);
2530   stream->stss.data = NULL;
2531   g_free ((gpointer) stream->stps.data);
2532   stream->stps.data = NULL;
2533   g_free ((gpointer) stream->ctts.data);
2534   stream->ctts.data = NULL;
2535 }
2536
2537 static void
2538 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2539     QtDemuxStream * stream)
2540 {
2541   g_free (stream->segments);
2542   stream->segments = NULL;
2543   stream->segment_index = -1;
2544   stream->accumulated_base = 0;
2545 }
2546
2547 static void
2548 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2549     QtDemuxStream * stream)
2550 {
2551   g_free (stream->samples);
2552   stream->samples = NULL;
2553   gst_qtdemux_stbl_free (stream);
2554
2555   /* fragments */
2556   g_free (stream->ra_entries);
2557   stream->ra_entries = NULL;
2558   stream->n_ra_entries = 0;
2559
2560   stream->sample_index = -1;
2561   stream->stbl_index = -1;
2562   stream->n_samples = 0;
2563   stream->time_position = 0;
2564
2565   stream->n_samples_moof = 0;
2566   stream->duration_moof = 0;
2567   stream->duration_last_moof = 0;
2568 }
2569
2570 static void
2571 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2572 {
2573   gint i;
2574   if (stream->allocator)
2575     gst_object_unref (stream->allocator);
2576   while (stream->buffers) {
2577     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2578     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2579   }
2580   for (i = 0; i < stream->stsd_entries_length; i++) {
2581     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2582     if (entry->rgb8_palette) {
2583       gst_memory_unref (entry->rgb8_palette);
2584       entry->rgb8_palette = NULL;
2585     }
2586     entry->sparse = FALSE;
2587   }
2588
2589   gst_tag_list_unref (stream->stream_tags);
2590   stream->stream_tags = gst_tag_list_new_empty ();
2591   gst_tag_list_set_scope (stream->stream_tags, GST_TAG_SCOPE_STREAM);
2592   g_free (stream->redirect_uri);
2593   stream->redirect_uri = NULL;
2594   stream->sent_eos = FALSE;
2595   stream->protected = FALSE;
2596   if (stream->protection_scheme_info) {
2597     if (stream->protection_scheme_type == FOURCC_cenc) {
2598       QtDemuxCencSampleSetInfo *info =
2599           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2600       if (info->default_properties)
2601         gst_structure_free (info->default_properties);
2602       if (info->crypto_info)
2603         g_ptr_array_free (info->crypto_info, TRUE);
2604     }
2605     g_free (stream->protection_scheme_info);
2606     stream->protection_scheme_info = NULL;
2607   }
2608   stream->protection_scheme_type = 0;
2609   stream->protection_scheme_version = 0;
2610   g_queue_foreach (&stream->protection_scheme_event_queue,
2611       (GFunc) gst_event_unref, NULL);
2612   g_queue_clear (&stream->protection_scheme_event_queue);
2613   gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2614   gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2615 }
2616
2617 static void
2618 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2619 {
2620   gint i;
2621   gst_qtdemux_stream_clear (qtdemux, stream);
2622   for (i = 0; i < stream->stsd_entries_length; i++) {
2623     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[i];
2624     if (entry->caps) {
2625       gst_caps_unref (entry->caps);
2626       entry->caps = NULL;
2627     }
2628   }
2629   gst_tag_list_unref (stream->stream_tags);
2630   if (stream->pad) {
2631     gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2632     gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2633   }
2634   g_free (stream->stsd_entries);
2635   g_free (stream);
2636 }
2637
2638 static void
2639 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2640 {
2641   g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2642
2643   gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2644   qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2645   qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2646   qtdemux->n_streams--;
2647 }
2648
2649 static GstStateChangeReturn
2650 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2651 {
2652   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2653   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2654
2655   switch (transition) {
2656     case GST_STATE_CHANGE_PAUSED_TO_READY:
2657       break;
2658     default:
2659       break;
2660   }
2661
2662   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2663
2664   switch (transition) {
2665     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2666       gst_qtdemux_reset (qtdemux, TRUE);
2667       break;
2668     }
2669     default:
2670       break;
2671   }
2672
2673   return result;
2674 }
2675
2676 static void
2677 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2678 {
2679   /* counts as header data */
2680   qtdemux->header_size += length;
2681
2682   /* only consider at least a sufficiently complete ftyp atom */
2683   if (length >= 20) {
2684     GstBuffer *buf;
2685
2686     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2687     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2688         GST_FOURCC_ARGS (qtdemux->major_brand));
2689     if (qtdemux->comp_brands)
2690       gst_buffer_unref (qtdemux->comp_brands);
2691     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2692     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2693   }
2694 }
2695
2696 static void
2697 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2698     GstTagList * xmptaglist)
2699 {
2700   /* Strip out bogus fields */
2701   if (xmptaglist) {
2702     if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2703       gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2704       gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2705     } else {
2706       gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2707     }
2708
2709     GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2710
2711     /* prioritize native tags using _KEEP mode */
2712     gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2713     gst_tag_list_unref (xmptaglist);
2714   }
2715 }
2716
2717 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
2718 static void
2719 _get_int_value_from_xml_string (GstQTDemux * qtdemux,
2720     const char *xml_str, const char *param_name, int *value)
2721 {
2722   char *value_start, *value_end, *endptr;
2723   const short value_length_max = 12;
2724   char init_view_ret[12];
2725   int value_length = 0;
2726   int i = 0;
2727
2728   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2729
2730   if (!value_start) {
2731     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2732         param_name);
2733     return;
2734   }
2735
2736   value_start += strlen (param_name);
2737   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2738     value_start++;
2739
2740   value_end = strchr (value_start, '<');
2741   if (!value_end) {
2742     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2743     return;
2744   }
2745
2746   value_length = value_end - value_start;
2747   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2748           || (value_start[value_length - 1] == '\t')))
2749     value_length--;
2750
2751   if (value_start[i] == '+' || value_start[i] == '-')
2752     i++;
2753   while (i < value_length) {
2754     if (value_start[i] < '0' || value_start[i] > '9') {
2755       GST_ERROR_OBJECT (qtdemux,
2756           "error: incorrect value, integer was expected\n");
2757       return;
2758     }
2759     i++;
2760   }
2761
2762   if (value_length >= value_length_max || value_length < 1) {
2763     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2764     return;
2765   }
2766
2767   strncpy (init_view_ret, value_start, value_length_max);
2768   init_view_ret[value_length] = '\0';
2769
2770   *value = strtol (init_view_ret, &endptr, 10);
2771   if (endptr == init_view_ret) {
2772     GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n");
2773     return;
2774   }
2775
2776   return;
2777 }
2778
2779 static void
2780 _get_string_value_from_xml_string (GstQTDemux * qtdemux,
2781     const char *xml_str, const char *param_name, char **value)
2782 {
2783   char *value_start, *value_end;
2784   const short value_length_max = 256;
2785   int value_length = 0;
2786
2787   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2788
2789   if (!value_start) {
2790     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2791         param_name);
2792     return;
2793   }
2794
2795   value_start += strlen (param_name);
2796   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2797     value_start++;
2798
2799   value_end = strchr (value_start, '<');
2800   if (!value_end) {
2801     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2802     return;
2803   }
2804
2805   value_length = value_end - value_start;
2806   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2807           || (value_start[value_length - 1] == '\t')))
2808     value_length--;
2809
2810   if (value_length >= value_length_max || value_length < 1) {
2811     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2812     return;
2813   }
2814
2815   *value = strndup(value_start, value_length);
2816
2817   return;
2818 }
2819
2820 static void
2821 _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
2822     const char *xml_str, const char *param_name, gboolean * value)
2823 {
2824   char *value_start, *value_end;
2825   int value_length = 0;
2826
2827   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2828
2829   if (!value_start) {
2830     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2831         param_name);
2832     return;
2833   }
2834
2835   value_start += strlen (param_name);
2836   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2837     value_start++;
2838
2839   value_end = strchr (value_start, '<');
2840   if (!value_end) {
2841     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2842     return;
2843   }
2844
2845   value_length = value_end - value_start;
2846   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2847           || (value_start[value_length - 1] == '\t')))
2848     value_length--;
2849
2850   if (value_length < 1) {
2851     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2852     return;
2853   }
2854
2855   *value = g_strstr_len(value_start, value_length, "true") ? TRUE : FALSE;
2856
2857   return;
2858 }
2859
2860 static void
2861 _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux, const char *xmlStr)
2862 {
2863   const char is_spherical_str[] = "<GSpherical:Spherical>";
2864   const char is_stitched_str[] = "<GSpherical:Stitched>";
2865   const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
2866   const char projection_type_str[] = "<GSpherical:ProjectionType>";
2867   const char stereo_mode_str[] = "<GSpherical:StereoMode>";
2868   const char source_count_str[] = "<GSpherical:SourceCount>";
2869   const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
2870   const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
2871   const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
2872   const char timestamp_str[] = "<GSpherical:Timestamp>";
2873   const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
2874   const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
2875   const char cropped_area_image_width_str[] =
2876       "<GSpherical:CroppedAreaImageWidthPixels>";
2877   const char cropped_area_image_height_str[] =
2878       "<GSpherical:CroppedAreaImageHeightPixels>";
2879   const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
2880   const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
2881
2882   QtDemuxSphericalMetadata * spherical_metadata = qtdemux->spherical_metadata;
2883
2884   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
2885       (gboolean *) & spherical_metadata->is_spherical);
2886   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
2887       (gboolean *) & spherical_metadata->is_stitched);
2888
2889   if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
2890     _get_string_value_from_xml_string (qtdemux, xmlStr,
2891         stitching_software_str, &spherical_metadata->stitching_software);
2892     _get_string_value_from_xml_string (qtdemux, xmlStr,
2893         projection_type_str, &spherical_metadata->projection_type);
2894     _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
2895         &spherical_metadata->stereo_mode);
2896     _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
2897         &spherical_metadata->source_count);
2898     _get_int_value_from_xml_string (qtdemux, xmlStr,
2899         init_view_heading_str, &spherical_metadata->init_view_heading);
2900     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
2901         &spherical_metadata->init_view_pitch);
2902     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
2903         &spherical_metadata->init_view_roll);
2904     _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
2905         &spherical_metadata->timestamp);
2906     _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
2907         &spherical_metadata->full_pano_width_pixels);
2908     _get_int_value_from_xml_string (qtdemux, xmlStr,
2909         full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
2910     _get_int_value_from_xml_string (qtdemux, xmlStr,
2911         cropped_area_image_width_str,
2912         &spherical_metadata->cropped_area_image_width);
2913     _get_int_value_from_xml_string (qtdemux, xmlStr,
2914         cropped_area_image_height_str,
2915         &spherical_metadata->cropped_area_image_height);
2916     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
2917         &spherical_metadata->cropped_area_left);
2918     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
2919         &spherical_metadata->cropped_area_top);
2920   }
2921
2922   return;
2923 }
2924
2925 static void
2926 gst_tag_register_spherical_tags (void) {
2927   gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
2928       G_TYPE_INT,
2929       _("tag-spherical"),
2930       _("Flag indicating if the video is a spherical video"),
2931       NULL);
2932   gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
2933       G_TYPE_INT,
2934       _("tag-stitched"),
2935       _("Flag indicating if the video is stitched"),
2936       NULL);
2937   gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
2938       G_TYPE_STRING,
2939       _("tag-stitching-software"),
2940       _("Software used to stitch the spherical video"),
2941       NULL);
2942   gst_tag_register ("projection_type", GST_TAG_FLAG_META,
2943       G_TYPE_STRING,
2944       _("tag-projection-type"),
2945       _("Projection type used in the video frames"),
2946       NULL);
2947   gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
2948       G_TYPE_STRING,
2949       _("tag-stereo-mode"),
2950       _("Description of stereoscopic 3D layout"),
2951       NULL);
2952   gst_tag_register ("source_count", GST_TAG_FLAG_META,
2953       G_TYPE_INT,
2954       _("tag-source-count"),
2955       _("Number of cameras used to create the spherical video"),
2956       NULL);
2957   gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
2958       G_TYPE_INT,
2959       _("tag-init-view-heading"),
2960       _("The heading angle of the initial view in degrees"),
2961       NULL);
2962   gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
2963       G_TYPE_INT,
2964       _("tag-init-view-pitch"),
2965       _("The pitch angle of the initial view in degrees"),
2966       NULL);
2967   gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
2968       G_TYPE_INT,
2969       _("tag-init-view-roll"),
2970       _("The roll angle of the initial view in degrees"),
2971       NULL);
2972   gst_tag_register ("timestamp", GST_TAG_FLAG_META,
2973       G_TYPE_INT,
2974       _("tag-timestamp"),
2975       _("Epoch timestamp of when the first frame in the video was recorded"),
2976       NULL);
2977   gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
2978       G_TYPE_INT,
2979       _("tag-full-pano-width"),
2980       _("Width of the encoded video frame in pixels"),
2981       NULL);
2982   gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
2983       G_TYPE_INT,
2984       _("tag-full-pano-height"),
2985       _("Height of the encoded video frame in pixels"),
2986       NULL);
2987   gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
2988       G_TYPE_INT,
2989       _("tag-cropped-area-image-width"),
2990       _("Width of the video frame to display (e.g. cropping)"),
2991       NULL);
2992   gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
2993       G_TYPE_INT,
2994       _("tag-cropped-area-image-height"),
2995       _("Height of the video frame to display (e.g. cropping)"),
2996       NULL);
2997   gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
2998       G_TYPE_INT,
2999       _("tag-cropped-area-left"),
3000       _("Column where the left edge of the image was cropped from the"
3001           " full sized panorama"),
3002       NULL);
3003   gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
3004       G_TYPE_INT,
3005       _("tag-cropped-area-top"),
3006       _("Row where the top edge of the image was cropped from the"
3007           " full sized panorama"),
3008       NULL);
3009   gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
3010       G_TYPE_INT,
3011       _("tag-ambisonic-type"),
3012       _("Specifies the type of ambisonic audio represented"),
3013       NULL);
3014   gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
3015       G_TYPE_INT,
3016       _("tag-ambisonic-format"),
3017       _("Specifies the ambisonic audio format"),
3018       NULL);
3019   gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
3020       G_TYPE_INT,
3021       _("tag-ambisonic-order"),
3022       _("Specifies the ambisonic audio channel order"),
3023       NULL);
3024
3025   return;
3026 }
3027
3028 static void
3029 _send_spherical_metadata_msg_to_bus (GstQTDemux * qtdemux)
3030 {
3031   GstTagList *taglist;
3032   QtDemuxSphericalMetadata *spherical_metadata = qtdemux->spherical_metadata;
3033
3034   GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
3035       spherical_metadata->is_spherical);
3036   GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
3037       spherical_metadata->is_stitched);
3038   GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
3039       spherical_metadata->stitching_software);
3040   GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
3041       spherical_metadata->projection_type);
3042   GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
3043       spherical_metadata->stereo_mode);
3044   GST_DEBUG_OBJECT (qtdemux, "source_count %d",
3045       spherical_metadata->source_count);
3046   GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
3047       spherical_metadata->init_view_heading);
3048   GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
3049       spherical_metadata->init_view_pitch);
3050   GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
3051       spherical_metadata->init_view_roll);
3052   GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
3053   GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
3054       spherical_metadata->full_pano_width_pixels);
3055   GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
3056       spherical_metadata->full_pano_height_pixels);
3057   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
3058       spherical_metadata->cropped_area_image_width);
3059   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
3060       spherical_metadata->cropped_area_image_height);
3061   GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
3062       spherical_metadata->cropped_area_left);
3063   GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
3064       spherical_metadata->cropped_area_top);
3065   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
3066       spherical_metadata->ambisonic_type);
3067   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
3068       spherical_metadata->ambisonic_order);
3069   GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
3070       spherical_metadata->ambisonic_format);
3071
3072   taglist = gst_tag_list_new_empty ();
3073   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3074       "is_spherical", spherical_metadata->is_spherical,
3075       "is_stitched", spherical_metadata->is_stitched,
3076       "source_count", spherical_metadata->source_count,
3077       "init_view_heading", spherical_metadata->init_view_heading,
3078       "init_view_pitch", spherical_metadata->init_view_pitch,
3079       "init_view_roll", spherical_metadata->init_view_roll,
3080       "timestamp", spherical_metadata->timestamp,
3081       "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
3082       "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
3083       "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
3084       "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
3085       "cropped_area_left", spherical_metadata->cropped_area_left,
3086       "cropped_area_top", spherical_metadata->cropped_area_top,
3087       "ambisonic_type", spherical_metadata->ambisonic_type,
3088       "ambisonic_format", spherical_metadata->ambisonic_format,
3089       "ambisonic_order", spherical_metadata->ambisonic_order,
3090       NULL);
3091
3092   if (spherical_metadata->stitching_software)
3093     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3094         "stitching_software", spherical_metadata->stitching_software,
3095         NULL);
3096   if (spherical_metadata->projection_type)
3097     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3098         "projection_type", spherical_metadata->projection_type,
3099         NULL);
3100   if (spherical_metadata->stereo_mode)
3101     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3102         "stereo_mode", spherical_metadata->stereo_mode,
3103         NULL);
3104
3105   gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3106           gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
3107                   gst_tag_list_copy (taglist)));
3108
3109   gst_tag_list_unref(taglist);
3110
3111   return;
3112 }
3113
3114 static void
3115 qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3116 {
3117   guint offset = 0;
3118
3119   guint8 version = 0;
3120   guint8 ambisonic_type  = 0;
3121   guint32 ambisonic_order = 0;
3122   guint8 ambisonic_channel_ordering = 0;
3123   guint8 ambisonic_normalization = 0;
3124   guint32 num_channels = 0;
3125   guint32 channel_map[49] = { 0 };      /* Up to 6th order */
3126
3127   int i;
3128
3129   GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
3130
3131   qtdemux->header_size += length;
3132   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3133
3134   if (length <= offset + 16) {
3135     GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
3136     return;
3137   }
3138
3139   version = QT_UINT8 (buffer + offset);
3140   ambisonic_type = QT_UINT8 (buffer + offset + 1);
3141   ambisonic_order = QT_UINT32 (buffer + offset + 2);
3142   ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
3143   ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
3144   num_channels = QT_UINT32 (buffer + offset + 8);
3145   for (i = 0; i < num_channels; ++i)
3146     channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
3147
3148   GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
3149   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
3150   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
3151   GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
3152       ambisonic_channel_ordering);
3153   GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
3154       ambisonic_normalization);
3155   GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
3156   for (i = 0; i < num_channels; ++i)
3157     GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
3158
3159   if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
3160     if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
3161       qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
3162
3163     if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
3164       if (num_channels == 4) {
3165         qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
3166
3167         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
3168             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
3169             && (channel_map[0] == 0) && (channel_map[1] == 1)
3170             && (channel_map[2] == 2) && (channel_map[3] == 3))
3171           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
3172
3173         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
3174             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
3175             && (channel_map[0] == 0) && (channel_map[1] == 3)
3176             && (channel_map[2] == 1) && (channel_map[3] == 2))
3177           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
3178       }
3179     }
3180   }
3181
3182   return;
3183 }
3184 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3185
3186 static void
3187 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
3188     guint offset)
3189 {
3190   GstByteReader br;
3191   guint8 version;
3192   guint32 flags = 0;
3193   guint i;
3194   guint8 iv_size = 8;
3195   QtDemuxStream *stream;
3196   GstStructure *structure;
3197   QtDemuxCencSampleSetInfo *ss_info = NULL;
3198   const gchar *system_id;
3199   gboolean uses_sub_sample_encryption = FALSE;
3200
3201   if (qtdemux->n_streams == 0)
3202     return;
3203
3204   stream = qtdemux->streams[0];
3205
3206   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
3207   if (!gst_structure_has_name (structure, "application/x-cenc")) {
3208     GST_WARNING_OBJECT (qtdemux,
3209         "Attempting PIFF box parsing on an unencrypted stream.");
3210     return;
3211   }
3212
3213   gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
3214       G_TYPE_STRING, &system_id, NULL);
3215   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
3216
3217   stream->protected = TRUE;
3218   stream->protection_scheme_type = FOURCC_cenc;
3219
3220   if (!stream->protection_scheme_info)
3221     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
3222
3223   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3224
3225   if (ss_info->default_properties)
3226     gst_structure_free (ss_info->default_properties);
3227
3228   ss_info->default_properties =
3229       gst_structure_new ("application/x-cenc",
3230       "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
3231
3232   if (ss_info->crypto_info) {
3233     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3234     g_ptr_array_free (ss_info->crypto_info, TRUE);
3235     ss_info->crypto_info = NULL;
3236   }
3237
3238   /* skip UUID */
3239   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
3240
3241   if (!gst_byte_reader_get_uint8 (&br, &version)) {
3242     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
3243     return;
3244   }
3245
3246   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
3247     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
3248     return;
3249   }
3250
3251   if ((flags & 0x000001)) {
3252     guint32 algorithm_id = 0;
3253     const guint8 *kid;
3254     GstBuffer *kid_buf;
3255     gboolean is_encrypted = TRUE;
3256
3257     if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
3258       GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
3259       return;
3260     }
3261
3262     algorithm_id >>= 8;
3263     if (algorithm_id == 0) {
3264       is_encrypted = FALSE;
3265     } else if (algorithm_id == 1) {
3266       /* FIXME: maybe store this in properties? */
3267       GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
3268     } else if (algorithm_id == 2) {
3269       /* FIXME: maybe store this in properties? */
3270       GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
3271     }
3272
3273     if (!gst_byte_reader_get_uint8 (&br, &iv_size))
3274       return;
3275
3276     if (!gst_byte_reader_get_data (&br, 16, &kid))
3277       return;
3278
3279     kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
3280     gst_buffer_fill (kid_buf, 0, kid, 16);
3281     if (ss_info->default_properties)
3282       gst_structure_free (ss_info->default_properties);
3283     ss_info->default_properties =
3284         gst_structure_new ("application/x-cenc",
3285         "iv_size", G_TYPE_UINT, iv_size,
3286         "encrypted", G_TYPE_BOOLEAN, is_encrypted,
3287         "kid", GST_TYPE_BUFFER, kid_buf, NULL);
3288     GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
3289         "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
3290     gst_buffer_unref (kid_buf);
3291   } else if ((flags & 0x000002)) {
3292     uses_sub_sample_encryption = TRUE;
3293   }
3294
3295   if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
3296     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
3297     return;
3298   }
3299
3300   ss_info->crypto_info =
3301       g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
3302       (GDestroyNotify) qtdemux_gst_structure_free);
3303
3304   for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
3305     GstStructure *properties;
3306     guint8 *data;
3307     GstBuffer *buf;
3308
3309     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3310     if (properties == NULL) {
3311       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3312       return;
3313     }
3314
3315     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
3316       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
3317       gst_structure_free (properties);
3318       return;
3319     }
3320     buf = gst_buffer_new_wrapped (data, iv_size);
3321     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3322     gst_buffer_unref (buf);
3323
3324     if (uses_sub_sample_encryption) {
3325       guint16 n_subsamples;
3326
3327       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
3328           || n_subsamples == 0) {
3329         GST_ERROR_OBJECT (qtdemux,
3330             "failed to get subsample count for sample %u", i);
3331         gst_structure_free (properties);
3332         return;
3333       }
3334       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3335       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
3336         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3337             i);
3338         gst_structure_free (properties);
3339         return;
3340       }
3341       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3342       gst_structure_set (properties,
3343           "subsample_count", G_TYPE_UINT, n_subsamples,
3344           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3345       gst_buffer_unref (buf);
3346     } else {
3347       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3348     }
3349
3350     g_ptr_array_add (ss_info->crypto_info, properties);
3351   }
3352 }
3353
3354 static void
3355 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3356 {
3357   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
3358     0x97, 0xA9, 0x42, 0xE8,
3359     0x9C, 0x71, 0x99, 0x94,
3360     0x91, 0xE3, 0xAF, 0xAC
3361   };
3362   static const guint8 playready_uuid[] = {
3363     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
3364     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
3365   };
3366
3367   static const guint8 piff_sample_encryption_uuid[] = {
3368     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3369     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3370   };
3371
3372 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3373   static const guint8 spherical_uuid[] = {
3374     0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
3375     0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd
3376   };
3377 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3378
3379   guint offset;
3380
3381   /* counts as header data */
3382   qtdemux->header_size += length;
3383
3384   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3385
3386   if (length <= offset + 16) {
3387     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3388     return;
3389   }
3390
3391 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3392   if (memcmp (buffer + offset, spherical_uuid, 16) == 0) {
3393     const char *contents;
3394
3395     GST_DEBUG_OBJECT (qtdemux, "spherical uuid was found");
3396     contents = (char *) (buffer + offset + 16);
3397     GST_DEBUG_OBJECT (qtdemux, "contents: %s\n", contents);
3398
3399     if (qtdemux->spherical_metadata)
3400       _parse_spatial_video_metadata_from_xml_string (qtdemux, contents);
3401
3402     return;
3403   }
3404 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3405
3406   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3407     GstBuffer *buf;
3408     GstTagList *taglist;
3409
3410     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3411         length - offset - 16, NULL);
3412     taglist = gst_tag_list_from_xmp_buffer (buf);
3413     gst_buffer_unref (buf);
3414
3415     /* make sure we have a usable taglist */
3416     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3417
3418     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3419
3420   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3421     int len;
3422     const gunichar2 *s_utf16;
3423     char *contents;
3424
3425     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3426     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3427     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3428     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3429
3430     g_free (contents);
3431
3432     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3433         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3434         (NULL));
3435   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3436     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3437   } else {
3438     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3439         GST_READ_UINT32_LE (buffer + offset),
3440         GST_READ_UINT32_LE (buffer + offset + 4),
3441         GST_READ_UINT32_LE (buffer + offset + 8),
3442         GST_READ_UINT32_LE (buffer + offset + 12));
3443   }
3444 }
3445
3446 static void
3447 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3448 {
3449   GstSidxParser sidx_parser;
3450   GstIsoffParserResult res;
3451   guint consumed;
3452
3453   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3454
3455   res =
3456       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3457       &consumed);
3458   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3459   if (res == GST_ISOFF_QT_PARSER_DONE) {
3460     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3461   }
3462   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3463 }
3464
3465 /* caller verifies at least 8 bytes in buf */
3466 static void
3467 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3468     guint64 * plength, guint32 * pfourcc)
3469 {
3470   guint64 length;
3471   guint32 fourcc;
3472
3473   length = QT_UINT32 (data);
3474   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3475   fourcc = QT_FOURCC (data + 4);
3476   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3477
3478   if (length == 0) {
3479     length = G_MAXUINT64;
3480   } else if (length == 1 && size >= 16) {
3481     /* this means we have an extended size, which is the 64 bit value of
3482      * the next 8 bytes */
3483     length = QT_UINT64 (data + 8);
3484     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3485   }
3486
3487   if (plength)
3488     *plength = length;
3489   if (pfourcc)
3490     *pfourcc = fourcc;
3491 }
3492
3493 static gboolean
3494 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3495 {
3496   guint32 version = 0;
3497   GstClockTime duration = 0;
3498
3499   if (!gst_byte_reader_get_uint32_be (br, &version))
3500     goto failed;
3501
3502   version >>= 24;
3503   if (version == 1) {
3504     if (!gst_byte_reader_get_uint64_be (br, &duration))
3505       goto failed;
3506   } else {
3507     guint32 dur = 0;
3508
3509     if (!gst_byte_reader_get_uint32_be (br, &dur))
3510       goto failed;
3511     duration = dur;
3512   }
3513
3514   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3515   qtdemux->duration = duration;
3516
3517   return TRUE;
3518
3519 failed:
3520   {
3521     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3522     return FALSE;
3523   }
3524 }
3525
3526 static gboolean
3527 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3528     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3529 {
3530   if (!stream->parsed_trex && qtdemux->moov_node) {
3531     GNode *mvex, *trex;
3532     GstByteReader trex_data;
3533
3534     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3535     if (mvex) {
3536       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3537           &trex_data);
3538       while (trex) {
3539         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3540
3541         /* skip version/flags */
3542         if (!gst_byte_reader_skip (&trex_data, 4))
3543           goto next;
3544         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3545           goto next;
3546         if (id != stream->track_id)
3547           goto next;
3548         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3549           goto next;
3550         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3551           goto next;
3552         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3553           goto next;
3554         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3555           goto next;
3556
3557         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3558             "duration %d,  size %d, flags 0x%x", stream->track_id,
3559             dur, size, flags);
3560
3561         stream->parsed_trex = TRUE;
3562         stream->def_sample_description_index = sdi;
3563         stream->def_sample_duration = dur;
3564         stream->def_sample_size = size;
3565         stream->def_sample_flags = flags;
3566
3567       next:
3568         /* iterate all siblings */
3569         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3570             &trex_data);
3571       }
3572     }
3573   }
3574
3575   *ds_duration = stream->def_sample_duration;
3576   *ds_size = stream->def_sample_size;
3577   *ds_flags = stream->def_sample_flags;
3578
3579   /* even then, above values are better than random ... */
3580   if (G_UNLIKELY (!stream->parsed_trex)) {
3581     GST_WARNING_OBJECT (qtdemux,
3582         "failed to find fragment defaults for stream %d", stream->track_id);
3583     return FALSE;
3584   }
3585
3586   return TRUE;
3587 }
3588
3589 /* This method should be called whenever a more accurate duration might
3590  * have been found. It will update all relevant variables if/where needed
3591  */
3592 static void
3593 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3594 {
3595   guint i;
3596   guint64 movdur;
3597   GstClockTime prevdur;
3598
3599   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3600
3601   if (movdur > qtdemux->duration) {
3602     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3603     GST_DEBUG_OBJECT (qtdemux,
3604         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3605         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3606     qtdemux->duration = movdur;
3607     GST_DEBUG_OBJECT (qtdemux,
3608         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3609         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3610         GST_TIME_ARGS (qtdemux->segment.stop));
3611     if (qtdemux->segment.duration == prevdur) {
3612       /* If the current segment has duration/stop identical to previous duration
3613        * update them also (because they were set at that point in time with
3614        * the wrong duration */
3615       /* We convert the value *from* the timescale version to avoid rounding errors */
3616       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3617       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3618       qtdemux->segment.duration = fixeddur;
3619       qtdemux->segment.stop = fixeddur;
3620     }
3621   }
3622   for (i = 0; i < qtdemux->n_streams; i++) {
3623     QtDemuxStream *stream = qtdemux->streams[i];
3624     if (stream) {
3625       movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3626       if (movdur > stream->duration) {
3627         GST_DEBUG_OBJECT (qtdemux,
3628             "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3629             GST_TIME_ARGS (duration));
3630         stream->duration = movdur;
3631         if (stream->dummy_segment) {
3632           /* Update all dummy values to new duration */
3633           stream->segments[0].stop_time = duration;
3634           stream->segments[0].duration = duration;
3635           stream->segments[0].media_stop = duration;
3636
3637           /* let downstream know we possibly have a new stop time */
3638           if (stream->segment_index != -1) {
3639             GstClockTime pos;
3640
3641             if (qtdemux->segment.rate >= 0) {
3642               pos = stream->segment.start;
3643             } else {
3644               pos = stream->segment.stop;
3645             }
3646
3647             gst_qtdemux_stream_update_segment (qtdemux, stream,
3648                 stream->segment_index, pos, NULL, NULL);
3649           }
3650         }
3651       }
3652     }
3653   }
3654 }
3655
3656 static gboolean
3657 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3658     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3659     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3660     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3661     gboolean has_tfdt)
3662 {
3663   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3664   guint64 timestamp;
3665   gint32 data_offset = 0;
3666   guint32 flags = 0, first_flags = 0, samples_count = 0;
3667   gint i;
3668   guint8 *data;
3669   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3670   QtDemuxSample *sample;
3671   gboolean ismv = FALSE;
3672   gint64 initial_offset;
3673
3674   GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3675       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3676       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3677       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3678
3679   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3680     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3681     return TRUE;
3682   }
3683
3684   /* presence of stss or not can't really tell us much,
3685    * and flags and so on tend to be marginally reliable in these files */
3686   if (stream->subtype == FOURCC_soun) {
3687     GST_DEBUG_OBJECT (qtdemux,
3688         "sound track in fragmented file; marking all keyframes");
3689     stream->all_keyframe = TRUE;
3690   }
3691
3692   if (!gst_byte_reader_skip (trun, 1) ||
3693       !gst_byte_reader_get_uint24_be (trun, &flags))
3694     goto fail;
3695
3696   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3697     goto fail;
3698
3699   if (flags & TR_DATA_OFFSET) {
3700     /* note this is really signed */
3701     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3702       goto fail;
3703     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3704     /* default base offset = first byte of moof */
3705     if (*base_offset == -1) {
3706       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3707       *base_offset = moof_offset;
3708     }
3709     *running_offset = *base_offset + data_offset;
3710   } else {
3711     /* if no offset at all, that would mean data starts at moof start,
3712      * which is a bit wrong and is ismv crappy way, so compensate
3713      * assuming data is in mdat following moof */
3714     if (*base_offset == -1) {
3715       *base_offset = moof_offset + moof_length + 8;
3716       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3717       ismv = TRUE;
3718     }
3719     if (*running_offset == -1)
3720       *running_offset = *base_offset;
3721   }
3722
3723   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3724       *running_offset);
3725   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3726       data_offset, flags, samples_count);
3727
3728   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3729     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3730       GST_DEBUG_OBJECT (qtdemux,
3731           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3732       flags ^= TR_FIRST_SAMPLE_FLAGS;
3733     } else {
3734       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3735         goto fail;
3736       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3737     }
3738   }
3739
3740   /* FIXME ? spec says other bits should also be checked to determine
3741    * entry size (and prefix size for that matter) */
3742   entry_size = 0;
3743   dur_offset = size_offset = 0;
3744   if (flags & TR_SAMPLE_DURATION) {
3745     GST_LOG_OBJECT (qtdemux, "entry duration present");
3746     dur_offset = entry_size;
3747     entry_size += 4;
3748   }
3749   if (flags & TR_SAMPLE_SIZE) {
3750     GST_LOG_OBJECT (qtdemux, "entry size present");
3751     size_offset = entry_size;
3752     entry_size += 4;
3753   }
3754   if (flags & TR_SAMPLE_FLAGS) {
3755     GST_LOG_OBJECT (qtdemux, "entry flags present");
3756     flags_offset = entry_size;
3757     entry_size += 4;
3758   }
3759   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3760     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3761     ct_offset = entry_size;
3762     entry_size += 4;
3763   }
3764
3765   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3766     goto fail;
3767   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3768
3769   if (stream->n_samples + samples_count >=
3770       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3771     goto index_too_big;
3772
3773   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3774       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3775       (stream->n_samples + samples_count) *
3776       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3777
3778   /* create a new array of samples if it's the first sample parsed */
3779   if (stream->n_samples == 0) {
3780     g_assert (stream->samples == NULL);
3781     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3782     /* or try to reallocate it with space enough to insert the new samples */
3783   } else
3784     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3785         stream->n_samples + samples_count);
3786   if (stream->samples == NULL)
3787     goto out_of_memory;
3788
3789   if (qtdemux->fragment_start != -1) {
3790     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3791     qtdemux->fragment_start = -1;
3792   } else {
3793     if (stream->n_samples == 0) {
3794       if (decode_ts > 0) {
3795         timestamp = decode_ts;
3796       } else if (stream->pending_seek != NULL) {
3797         /* if we don't have a timestamp from a tfdt box, we'll use the one
3798          * from the mfra seek table */
3799         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3800             GST_TIME_ARGS (stream->pending_seek->ts));
3801
3802         /* FIXME: this is not fully correct, the timestamp refers to the random
3803          * access sample refered to in the tfra entry, which may not necessarily
3804          * be the first sample in the tfrag/trun (but hopefully/usually is) */
3805         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3806       } else {
3807         timestamp = 0;
3808       }
3809
3810       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3811       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3812           GST_TIME_ARGS (gst_ts));
3813     } else {
3814       /* subsequent fragments extend stream */
3815       timestamp =
3816           stream->samples[stream->n_samples - 1].timestamp +
3817           stream->samples[stream->n_samples - 1].duration;
3818
3819       /* If this is a GST_FORMAT_BYTES stream and there's a significant
3820        * difference (1 sec.) between decode_ts and timestamp, prefer the
3821        * former */
3822       if (has_tfdt && !qtdemux->upstream_format_is_time
3823           && ABSDIFF (decode_ts, timestamp) >
3824           MAX (stream->duration_last_moof / 2,
3825               GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3826         GST_INFO_OBJECT (qtdemux,
3827             "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3828             ") are significantly different (more than %" GST_TIME_FORMAT
3829             "), using decode_ts",
3830             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3831             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3832             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3833                     MAX (stream->duration_last_moof / 2,
3834                         GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3835         timestamp = decode_ts;
3836       }
3837
3838       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3839       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3840           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3841     }
3842   }
3843
3844   initial_offset = *running_offset;
3845
3846   sample = stream->samples + stream->n_samples;
3847   for (i = 0; i < samples_count; i++) {
3848     guint32 dur, size, sflags, ct;
3849
3850     /* first read sample data */
3851     if (flags & TR_SAMPLE_DURATION) {
3852       dur = QT_UINT32 (data + dur_offset);
3853     } else {
3854       dur = d_sample_duration;
3855     }
3856     if (flags & TR_SAMPLE_SIZE) {
3857       size = QT_UINT32 (data + size_offset);
3858     } else {
3859       size = d_sample_size;
3860     }
3861     if (flags & TR_FIRST_SAMPLE_FLAGS) {
3862       if (i == 0) {
3863         sflags = first_flags;
3864       } else {
3865         sflags = d_sample_flags;
3866       }
3867     } else if (flags & TR_SAMPLE_FLAGS) {
3868       sflags = QT_UINT32 (data + flags_offset);
3869     } else {
3870       sflags = d_sample_flags;
3871     }
3872     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3873       ct = QT_UINT32 (data + ct_offset);
3874     } else {
3875       ct = 0;
3876     }
3877     data += entry_size;
3878
3879     /* fill the sample information */
3880     sample->offset = *running_offset;
3881     sample->pts_offset = ct;
3882     sample->size = size;
3883     sample->timestamp = timestamp;
3884     sample->duration = dur;
3885     /* sample-is-difference-sample */
3886     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3887      * now idea how it relates to bitfield other than massive LE/BE confusion */
3888     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3889     *running_offset += size;
3890     timestamp += dur;
3891     stream->duration_moof += dur;
3892     sample++;
3893   }
3894
3895   /* Update total duration if needed */
3896   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3897
3898   /* Pre-emptively figure out size of mdat based on trun information.
3899    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3900    * size, else we will still be able to use this when dealing with gap'ed
3901    * input */
3902   qtdemux->mdatleft = *running_offset - initial_offset;
3903   qtdemux->mdatoffset = initial_offset;
3904   qtdemux->mdatsize = qtdemux->mdatleft;
3905
3906   stream->n_samples += samples_count;
3907   stream->n_samples_moof += samples_count;
3908
3909   if (stream->pending_seek != NULL)
3910     stream->pending_seek = NULL;
3911
3912   return TRUE;
3913
3914 fail:
3915   {
3916     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3917     return FALSE;
3918   }
3919 out_of_memory:
3920   {
3921     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3922         stream->n_samples);
3923     return FALSE;
3924   }
3925 index_too_big:
3926   {
3927     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3928         "be larger than %uMB (broken file?)", stream->n_samples,
3929         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3930     return FALSE;
3931   }
3932 }
3933
3934 /* find stream with @id */
3935 static inline QtDemuxStream *
3936 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3937 {
3938   QtDemuxStream *stream;
3939   gint i;
3940
3941   /* check */
3942   if (G_UNLIKELY (!id)) {
3943     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3944     return NULL;
3945   }
3946
3947   /* try to get it fast and simple */
3948   if (G_LIKELY (id <= qtdemux->n_streams)) {
3949     stream = qtdemux->streams[id - 1];
3950     if (G_LIKELY (stream->track_id == id))
3951       return stream;
3952   }
3953
3954   /* linear search otherwise */
3955   for (i = 0; i < qtdemux->n_streams; i++) {
3956     stream = qtdemux->streams[i];
3957     if (stream->track_id == id)
3958       return stream;
3959   }
3960   if (qtdemux->mss_mode) {
3961     /* mss should have only 1 stream anyway */
3962     return qtdemux->streams[0];
3963   }
3964
3965   return NULL;
3966 }
3967
3968 static gboolean
3969 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3970     guint32 * fragment_number)
3971 {
3972   if (!gst_byte_reader_skip (mfhd, 4))
3973     goto fail;
3974   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3975     goto fail;
3976   return TRUE;
3977 fail:
3978   {
3979     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3980     return FALSE;
3981   }
3982 }
3983
3984 static gboolean
3985 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3986     QtDemuxStream ** stream, guint32 * default_sample_duration,
3987     guint32 * default_sample_size, guint32 * default_sample_flags,
3988     gint64 * base_offset)
3989 {
3990   guint32 flags = 0;
3991   guint32 track_id = 0;
3992
3993   if (!gst_byte_reader_skip (tfhd, 1) ||
3994       !gst_byte_reader_get_uint24_be (tfhd, &flags))
3995     goto invalid_track;
3996
3997   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3998     goto invalid_track;
3999
4000   *stream = qtdemux_find_stream (qtdemux, track_id);
4001   if (G_UNLIKELY (!*stream))
4002     goto unknown_stream;
4003
4004   if (flags & TF_DEFAULT_BASE_IS_MOOF)
4005     *base_offset = qtdemux->moof_offset;
4006
4007   if (flags & TF_BASE_DATA_OFFSET)
4008     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
4009       goto invalid_track;
4010
4011   /* obtain stream defaults */
4012   qtdemux_parse_trex (qtdemux, *stream,
4013       default_sample_duration, default_sample_size, default_sample_flags);
4014
4015   (*stream)->stsd_sample_description_id =
4016       (*stream)->def_sample_description_index - 1;
4017
4018   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
4019     guint32 sample_description_index;
4020     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
4021       goto invalid_track;
4022     (*stream)->stsd_sample_description_id = sample_description_index - 1;
4023   }
4024
4025   if (qtdemux->mss_mode) {
4026     /* mss has no stsd entry */
4027     (*stream)->stsd_sample_description_id = 0;
4028   }
4029
4030   if (flags & TF_DEFAULT_SAMPLE_DURATION)
4031     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
4032       goto invalid_track;
4033
4034   if (flags & TF_DEFAULT_SAMPLE_SIZE)
4035     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
4036       goto invalid_track;
4037
4038   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
4039     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
4040       goto invalid_track;
4041
4042   return TRUE;
4043
4044 invalid_track:
4045   {
4046     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
4047     return FALSE;
4048   }
4049 unknown_stream:
4050   {
4051     GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
4052     return TRUE;
4053   }
4054 }
4055
4056 static gboolean
4057 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
4058     guint64 * decode_time)
4059 {
4060   guint32 version = 0;
4061
4062   if (!gst_byte_reader_get_uint32_be (br, &version))
4063     return FALSE;
4064
4065   version >>= 24;
4066   if (version == 1) {
4067     if (!gst_byte_reader_get_uint64_be (br, decode_time))
4068       goto failed;
4069   } else {
4070     guint32 dec_time = 0;
4071     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
4072       goto failed;
4073     *decode_time = dec_time;
4074   }
4075
4076   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
4077       *decode_time);
4078
4079   return TRUE;
4080
4081 failed:
4082   {
4083     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
4084     return FALSE;
4085   }
4086 }
4087
4088 /* Returns a pointer to a GstStructure containing the properties of
4089  * the stream sample identified by @sample_index. The caller must unref
4090  * the returned object after use. Returns NULL if unsuccessful. */
4091 static GstStructure *
4092 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
4093     QtDemuxStream * stream, guint sample_index)
4094 {
4095   QtDemuxCencSampleSetInfo *info = NULL;
4096
4097   g_return_val_if_fail (stream != NULL, NULL);
4098   g_return_val_if_fail (stream->protected, NULL);
4099   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
4100
4101   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4102
4103   /* Currently, cenc properties for groups of samples are not supported, so
4104    * simply return a copy of the default sample properties */
4105   return gst_structure_copy (info->default_properties);
4106 }
4107
4108 /* Parses the sizes of sample auxiliary information contained within a stream,
4109  * as given in a saiz box. Returns array of sample_count guint8 size values,
4110  * or NULL on failure */
4111 static guint8 *
4112 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
4113     GstByteReader * br, guint32 * sample_count)
4114 {
4115   guint32 flags = 0;
4116   guint8 *info_sizes;
4117   guint8 default_info_size;
4118
4119   g_return_val_if_fail (qtdemux != NULL, NULL);
4120   g_return_val_if_fail (stream != NULL, NULL);
4121   g_return_val_if_fail (br != NULL, NULL);
4122   g_return_val_if_fail (sample_count != NULL, NULL);
4123
4124   if (!gst_byte_reader_get_uint32_be (br, &flags))
4125     return NULL;
4126
4127   if (flags & 0x1) {
4128     /* aux_info_type and aux_info_type_parameter are ignored */
4129     if (!gst_byte_reader_skip (br, 8))
4130       return NULL;
4131   }
4132
4133   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
4134     return NULL;
4135   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
4136
4137   if (!gst_byte_reader_get_uint32_be (br, sample_count))
4138     return NULL;
4139   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
4140
4141
4142   if (default_info_size == 0) {
4143     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
4144       return NULL;
4145     }
4146   } else {
4147     info_sizes = g_new (guint8, *sample_count);
4148     memset (info_sizes, default_info_size, *sample_count);
4149   }
4150
4151   return info_sizes;
4152 }
4153
4154 /* Parses the offset of sample auxiliary information contained within a stream,
4155  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
4156 static gboolean
4157 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
4158     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
4159     guint64 * offset)
4160 {
4161   guint8 version = 0;
4162   guint32 flags = 0;
4163   guint32 aux_info_type = 0;
4164   guint32 aux_info_type_parameter = 0;
4165   guint32 entry_count;
4166   guint32 off_32;
4167   guint64 off_64;
4168   const guint8 *aux_info_type_data = NULL;
4169
4170   g_return_val_if_fail (qtdemux != NULL, FALSE);
4171   g_return_val_if_fail (stream != NULL, FALSE);
4172   g_return_val_if_fail (br != NULL, FALSE);
4173   g_return_val_if_fail (offset != NULL, FALSE);
4174
4175   if (!gst_byte_reader_get_uint8 (br, &version))
4176     return FALSE;
4177
4178   if (!gst_byte_reader_get_uint24_be (br, &flags))
4179     return FALSE;
4180
4181   if (flags & 0x1) {
4182
4183     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
4184       return FALSE;
4185     aux_info_type = QT_FOURCC (aux_info_type_data);
4186
4187     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
4188       return FALSE;
4189   } else if (stream->protected) {
4190     aux_info_type = stream->protection_scheme_type;
4191   } else {
4192     aux_info_type = CUR_STREAM (stream)->fourcc;
4193   }
4194
4195   if (info_type)
4196     *info_type = aux_info_type;
4197   if (info_type_parameter)
4198     *info_type_parameter = aux_info_type_parameter;
4199
4200   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
4201       "aux_info_type_parameter:  %#06x",
4202       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
4203
4204   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
4205     return FALSE;
4206
4207   if (entry_count != 1) {
4208     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
4209     return FALSE;
4210   }
4211
4212   if (version == 0) {
4213     if (!gst_byte_reader_get_uint32_be (br, &off_32))
4214       return FALSE;
4215     *offset = (guint64) off_32;
4216   } else {
4217     if (!gst_byte_reader_get_uint64_be (br, &off_64))
4218       return FALSE;
4219     *offset = off_64;
4220   }
4221
4222   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
4223   return TRUE;
4224 }
4225
4226 static void
4227 qtdemux_gst_structure_free (GstStructure * gststructure)
4228 {
4229   if (gststructure) {
4230     gst_structure_free (gststructure);
4231   }
4232 }
4233
4234 /* Parses auxiliary information relating to samples protected using Common
4235  * Encryption (cenc); the format of this information is defined in
4236  * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
4237 static gboolean
4238 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
4239     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
4240 {
4241   QtDemuxCencSampleSetInfo *ss_info = NULL;
4242   guint8 size;
4243   gint i;
4244   GPtrArray *old_crypto_info = NULL;
4245   guint old_entries = 0;
4246
4247   g_return_val_if_fail (qtdemux != NULL, FALSE);
4248   g_return_val_if_fail (stream != NULL, FALSE);
4249   g_return_val_if_fail (br != NULL, FALSE);
4250   g_return_val_if_fail (stream->protected, FALSE);
4251   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
4252
4253   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4254
4255   if (ss_info->crypto_info) {
4256     old_crypto_info = ss_info->crypto_info;
4257     /* Count number of non-null entries remaining at the tail end */
4258     for (i = old_crypto_info->len - 1; i >= 0; i--) {
4259       if (g_ptr_array_index (old_crypto_info, i) == NULL)
4260         break;
4261       old_entries++;
4262     }
4263   }
4264
4265   ss_info->crypto_info =
4266       g_ptr_array_new_full (sample_count + old_entries,
4267       (GDestroyNotify) qtdemux_gst_structure_free);
4268
4269   /* We preserve old entries because we parse the next moof in advance
4270    * of consuming all samples from the previous moof, and otherwise
4271    * we'd discard the corresponding crypto info for the samples
4272    * from the previous fragment. */
4273   if (old_entries) {
4274     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
4275         old_entries);
4276     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
4277       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
4278               i));
4279       g_ptr_array_index (old_crypto_info, i) = NULL;
4280     }
4281   }
4282
4283   if (old_crypto_info) {
4284     /* Everything now belongs to the new array */
4285     g_ptr_array_free (old_crypto_info, TRUE);
4286   }
4287
4288   for (i = 0; i < sample_count; ++i) {
4289     GstStructure *properties;
4290     guint16 n_subsamples = 0;
4291     guint8 *data;
4292     guint iv_size;
4293     GstBuffer *buf;
4294
4295     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
4296     if (properties == NULL) {
4297       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
4298       return FALSE;
4299     }
4300     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
4301       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
4302       gst_structure_free (properties);
4303       return FALSE;
4304     }
4305     if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
4306       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4307       gst_structure_free (properties);
4308       return FALSE;
4309     }
4310     buf = gst_buffer_new_wrapped (data, iv_size);
4311     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
4312     gst_buffer_unref (buf);
4313     size = info_sizes[i];
4314     if (size > iv_size) {
4315       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4316           || !(n_subsamples > 0)) {
4317         gst_structure_free (properties);
4318         GST_ERROR_OBJECT (qtdemux,
4319             "failed to get subsample count for sample %u", i);
4320         return FALSE;
4321       }
4322       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4323       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4324         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4325             i);
4326         gst_structure_free (properties);
4327         return FALSE;
4328       }
4329       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4330       if (!buf) {
4331         gst_structure_free (properties);
4332         return FALSE;
4333       }
4334       gst_structure_set (properties,
4335           "subsample_count", G_TYPE_UINT, n_subsamples,
4336           "subsamples", GST_TYPE_BUFFER, buf, NULL);
4337       gst_buffer_unref (buf);
4338     } else {
4339       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4340     }
4341     g_ptr_array_add (ss_info->crypto_info, properties);
4342   }
4343   return TRUE;
4344 }
4345
4346 /* Converts a UUID in raw byte form to a string representation, as defined in
4347  * RFC 4122. The caller takes ownership of the returned string and is
4348  * responsible for freeing it after use. */
4349 static gchar *
4350 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4351 {
4352   const guint8 *uuid = (const guint8 *) uuid_bytes;
4353
4354   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4355       "%02x%02x-%02x%02x%02x%02x%02x%02x",
4356       uuid[0], uuid[1], uuid[2], uuid[3],
4357       uuid[4], uuid[5], uuid[6], uuid[7],
4358       uuid[8], uuid[9], uuid[10], uuid[11],
4359       uuid[12], uuid[13], uuid[14], uuid[15]);
4360 }
4361
4362 /* Parses a Protection System Specific Header box (pssh), as defined in the
4363  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4364  * information needed by a specific content protection system in order to
4365  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4366  * otherwise. */
4367 static gboolean
4368 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4369 {
4370   gchar *sysid_string;
4371   guint32 pssh_size = QT_UINT32 (node->data);
4372   GstBuffer *pssh = NULL;
4373   GstEvent *event = NULL;
4374   guint32 parent_box_type;
4375   gint i;
4376
4377   if (G_UNLIKELY (pssh_size < 32U)) {
4378     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4379     return FALSE;
4380   }
4381
4382   sysid_string =
4383       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4384
4385   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4386
4387   pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
4388   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4389       gst_buffer_get_size (pssh));
4390
4391   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4392
4393   /* Push an event containing the pssh box onto the queues of all streams. */
4394   event = gst_event_new_protection (sysid_string, pssh,
4395       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4396   for (i = 0; i < qtdemux->n_streams; ++i) {
4397     g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
4398         gst_event_ref (event));
4399   }
4400   g_free (sysid_string);
4401   gst_event_unref (event);
4402   gst_buffer_unref (pssh);
4403   return TRUE;
4404 }
4405
4406 static gboolean
4407 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4408     guint64 moof_offset, QtDemuxStream * stream)
4409 {
4410   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4411   GNode *uuid_node;
4412   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4413   GNode *saiz_node, *saio_node, *pssh_node;
4414   GstByteReader saiz_data, saio_data;
4415   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4416   gint64 base_offset, running_offset;
4417   guint32 frag_num;
4418
4419   /* NOTE @stream ignored */
4420
4421   moof_node = g_node_new ((guint8 *) buffer);
4422   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4423   qtdemux_node_dump (qtdemux, moof_node);
4424
4425   /* Get fragment number from mfhd and check it's valid */
4426   mfhd_node =
4427       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4428   if (mfhd_node == NULL)
4429     goto missing_mfhd;
4430   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4431     goto fail;
4432   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4433
4434   /* unknown base_offset to start with */
4435   base_offset = running_offset = -1;
4436   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4437   while (traf_node) {
4438     guint64 decode_time = 0;
4439
4440     /* Fragment Header node */
4441     tfhd_node =
4442         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4443         &tfhd_data);
4444     if (!tfhd_node)
4445       goto missing_tfhd;
4446     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4447             &ds_size, &ds_flags, &base_offset))
4448       goto missing_tfhd;
4449
4450     /* The following code assumes at most a single set of sample auxiliary
4451      * data in the fragment (consisting of a saiz box and a corresponding saio
4452      * box); in theory, however, there could be multiple sets of sample
4453      * auxiliary data in a fragment. */
4454     saiz_node =
4455         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4456         &saiz_data);
4457     if (saiz_node) {
4458       guint32 info_type = 0;
4459       guint64 offset = 0;
4460       guint32 info_type_parameter = 0;
4461
4462       g_free (qtdemux->cenc_aux_info_sizes);
4463
4464       qtdemux->cenc_aux_info_sizes =
4465           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4466           &qtdemux->cenc_aux_sample_count);
4467       if (qtdemux->cenc_aux_info_sizes == NULL) {
4468         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4469         goto fail;
4470       }
4471       saio_node =
4472           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4473           &saio_data);
4474       if (!saio_node) {
4475         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4476         g_free (qtdemux->cenc_aux_info_sizes);
4477         qtdemux->cenc_aux_info_sizes = NULL;
4478         goto fail;
4479       }
4480
4481       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4482                   &info_type, &info_type_parameter, &offset))) {
4483         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4484         g_free (qtdemux->cenc_aux_info_sizes);
4485         qtdemux->cenc_aux_info_sizes = NULL;
4486         goto fail;
4487       }
4488       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4489         offset += (guint64) (base_offset - qtdemux->moof_offset);
4490       if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4491         GstByteReader br;
4492         if (offset > length) {
4493           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4494           qtdemux->cenc_aux_info_offset = offset;
4495         } else {
4496           gst_byte_reader_init (&br, buffer + offset, length - offset);
4497           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4498                   qtdemux->cenc_aux_info_sizes,
4499                   qtdemux->cenc_aux_sample_count)) {
4500             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4501             g_free (qtdemux->cenc_aux_info_sizes);
4502             qtdemux->cenc_aux_info_sizes = NULL;
4503             goto fail;
4504           }
4505         }
4506       }
4507     }
4508
4509     tfdt_node =
4510         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4511         &tfdt_data);
4512     if (tfdt_node) {
4513       /* We'll use decode_time to interpolate timestamps
4514        * in case the input timestamps are missing */
4515       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4516
4517       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4518           " (%" GST_TIME_FORMAT ")", decode_time,
4519           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4520                   decode_time) : GST_CLOCK_TIME_NONE));
4521
4522       /* Discard the fragment buffer timestamp info to avoid using it.
4523        * Rely on tfdt instead as it is more accurate than the timestamp
4524        * that is fetched from a manifest/playlist and is usually
4525        * less accurate. */
4526       qtdemux->fragment_start = -1;
4527     }
4528
4529     if (G_UNLIKELY (!stream)) {
4530       /* we lost track of offset, we'll need to regain it,
4531        * but can delay complaining until later or avoid doing so altogether */
4532       base_offset = -2;
4533       goto next;
4534     }
4535     if (G_UNLIKELY (base_offset < -1))
4536       goto lost_offset;
4537
4538     if (qtdemux->upstream_format_is_time)
4539       gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
4540
4541     /* initialise moof sample data */
4542     stream->n_samples_moof = 0;
4543     stream->duration_last_moof = stream->duration_moof;
4544     stream->duration_moof = 0;
4545
4546     /* Track Run node */
4547     trun_node =
4548         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4549         &trun_data);
4550     while (trun_node) {
4551       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4552           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4553           &running_offset, decode_time, (tfdt_node != NULL));
4554       /* iterate all siblings */
4555       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4556           &trun_data);
4557     }
4558
4559     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4560     if (uuid_node) {
4561       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4562       guint32 box_length = QT_UINT32 (uuid_buffer);
4563
4564       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4565     }
4566
4567     /* if no new base_offset provided for next traf,
4568      * base is end of current traf */
4569     base_offset = running_offset;
4570     running_offset = -1;
4571
4572     if (stream->n_samples_moof && stream->duration_moof)
4573       stream->new_caps = TRUE;
4574
4575   next:
4576     /* iterate all siblings */
4577     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4578   }
4579
4580   /* parse any protection system info */
4581   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4582   while (pssh_node) {
4583     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4584     qtdemux_parse_pssh (qtdemux, pssh_node);
4585     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4586   }
4587
4588   g_node_destroy (moof_node);
4589   return TRUE;
4590
4591 missing_tfhd:
4592   {
4593     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4594     goto fail;
4595   }
4596 missing_mfhd:
4597   {
4598     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4599     goto fail;
4600   }
4601 lost_offset:
4602   {
4603     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4604     goto fail;
4605   }
4606 fail:
4607   {
4608     g_node_destroy (moof_node);
4609     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4610         (_("This file is corrupt and cannot be played.")), (NULL));
4611     return FALSE;
4612   }
4613 }
4614
4615 #if 0
4616 /* might be used if some day we actually use mfra & co
4617  * for random access to fragments,
4618  * but that will require quite some modifications and much less relying
4619  * on a sample array */
4620 #endif
4621
4622 static gboolean
4623 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4624 {
4625   QtDemuxStream *stream;
4626   guint32 ver_flags, track_id, len, num_entries, i;
4627   guint value_size, traf_size, trun_size, sample_size;
4628   guint64 time = 0, moof_offset = 0;
4629 #if 0
4630   GstBuffer *buf = NULL;
4631   GstFlowReturn ret;
4632 #endif
4633   GstByteReader tfra;
4634
4635   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4636
4637   if (!gst_byte_reader_skip (&tfra, 8))
4638     return FALSE;
4639
4640   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4641     return FALSE;
4642
4643   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4644       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4645       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4646     return FALSE;
4647
4648   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4649
4650   stream = qtdemux_find_stream (qtdemux, track_id);
4651   if (stream == NULL)
4652     goto unknown_trackid;
4653
4654   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4655   sample_size = (len & 3) + 1;
4656   trun_size = ((len & 12) >> 2) + 1;
4657   traf_size = ((len & 48) >> 4) + 1;
4658
4659   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4660       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4661
4662   if (num_entries == 0)
4663     goto no_samples;
4664
4665   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4666           value_size + value_size + traf_size + trun_size + sample_size))
4667     goto corrupt_file;
4668
4669   g_free (stream->ra_entries);
4670   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4671   stream->n_ra_entries = num_entries;
4672
4673   for (i = 0; i < num_entries; i++) {
4674     qt_atom_parser_get_offset (&tfra, value_size, &time);
4675     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4676     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4677     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4678     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4679
4680     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4681
4682     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4683         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4684
4685     stream->ra_entries[i].ts = time;
4686     stream->ra_entries[i].moof_offset = moof_offset;
4687
4688     /* don't want to go through the entire file and read all moofs at startup */
4689 #if 0
4690     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4691     if (ret != GST_FLOW_OK)
4692       goto corrupt_file;
4693     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4694         moof_offset, stream);
4695     gst_buffer_unref (buf);
4696 #endif
4697   }
4698
4699   check_update_duration (qtdemux, time);
4700
4701   return TRUE;
4702
4703 /* ERRORS */
4704 unknown_trackid:
4705   {
4706     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4707     return FALSE;
4708   }
4709 corrupt_file:
4710   {
4711     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4712     return FALSE;
4713   }
4714 no_samples:
4715   {
4716     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4717     return FALSE;
4718   }
4719 }
4720
4721 static gboolean
4722 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4723 {
4724   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4725   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4726   GstBuffer *mfro = NULL, *mfra = NULL;
4727   GstFlowReturn flow;
4728   gboolean ret = FALSE;
4729   GNode *mfra_node, *tfra_node;
4730   guint64 mfra_offset = 0;
4731   guint32 fourcc, mfra_size;
4732   gint64 len;
4733
4734   /* query upstream size in bytes */
4735   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4736     goto size_query_failed;
4737
4738   /* mfro box should be at the very end of the file */
4739   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4740   if (flow != GST_FLOW_OK)
4741     goto exit;
4742
4743   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4744
4745   fourcc = QT_FOURCC (mfro_map.data + 4);
4746   if (fourcc != FOURCC_mfro)
4747     goto exit;
4748
4749   GST_INFO_OBJECT (qtdemux, "Found mfro box");
4750   if (mfro_map.size < 16)
4751     goto invalid_mfro_size;
4752
4753   mfra_size = QT_UINT32 (mfro_map.data + 12);
4754   if (mfra_size >= len)
4755     goto invalid_mfra_size;
4756
4757   mfra_offset = len - mfra_size;
4758
4759   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4760       mfra_offset, mfra_size);
4761
4762   /* now get and parse mfra box */
4763   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4764   if (flow != GST_FLOW_OK)
4765     goto broken_file;
4766
4767   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4768
4769   mfra_node = g_node_new ((guint8 *) mfra_map.data);
4770   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4771
4772   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4773
4774   while (tfra_node) {
4775     qtdemux_parse_tfra (qtdemux, tfra_node);
4776     /* iterate all siblings */
4777     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4778   }
4779   g_node_destroy (mfra_node);
4780
4781   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4782   ret = TRUE;
4783
4784 exit:
4785
4786   if (mfro) {
4787     if (mfro_map.memory != NULL)
4788       gst_buffer_unmap (mfro, &mfro_map);
4789     gst_buffer_unref (mfro);
4790   }
4791   if (mfra) {
4792     if (mfra_map.memory != NULL)
4793       gst_buffer_unmap (mfra, &mfra_map);
4794     gst_buffer_unref (mfra);
4795   }
4796   return ret;
4797
4798 /* ERRORS */
4799 size_query_failed:
4800   {
4801     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4802     goto exit;
4803   }
4804 invalid_mfro_size:
4805   {
4806     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4807     goto exit;
4808   }
4809 invalid_mfra_size:
4810   {
4811     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4812     goto exit;
4813   }
4814 broken_file:
4815   {
4816     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4817     goto exit;
4818   }
4819 }
4820
4821 static guint64
4822 add_offset (guint64 offset, guint64 advance)
4823 {
4824   /* Avoid 64-bit overflow by clamping */
4825   if (offset > G_MAXUINT64 - advance)
4826     return G_MAXUINT64;
4827   return offset + advance;
4828 }
4829
4830 static GstFlowReturn
4831 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4832 {
4833   guint64 length = 0;
4834   guint32 fourcc = 0;
4835   GstBuffer *buf = NULL;
4836   GstFlowReturn ret = GST_FLOW_OK;
4837   guint64 cur_offset = qtdemux->offset;
4838   GstMapInfo map;
4839
4840   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4841   if (G_UNLIKELY (ret != GST_FLOW_OK))
4842     goto beach;
4843   gst_buffer_map (buf, &map, GST_MAP_READ);
4844   if (G_LIKELY (map.size >= 8))
4845     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4846   gst_buffer_unmap (buf, &map);
4847   gst_buffer_unref (buf);
4848
4849   /* maybe we already got most we needed, so only consider this eof */
4850   if (G_UNLIKELY (length == 0)) {
4851     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4852         (_("Invalid atom size.")),
4853         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4854             GST_FOURCC_ARGS (fourcc)));
4855     ret = GST_FLOW_EOS;
4856     goto beach;
4857   }
4858
4859   switch (fourcc) {
4860     case FOURCC_moof:
4861       /* record for later parsing when needed */
4862       if (!qtdemux->moof_offset) {
4863         qtdemux->moof_offset = qtdemux->offset;
4864       }
4865       if (qtdemux_pull_mfro_mfra (qtdemux)) {
4866         /* FIXME */
4867       } else {
4868         qtdemux->offset += length;      /* skip moof and keep going */
4869       }
4870       if (qtdemux->got_moov) {
4871         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4872         ret = GST_FLOW_EOS;
4873         goto beach;
4874       }
4875       break;
4876     case FOURCC_mdat:
4877     case FOURCC_free:
4878     case FOURCC_wide:
4879     case FOURCC_PICT:
4880     case FOURCC_pnot:
4881     {
4882       GST_LOG_OBJECT (qtdemux,
4883           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4884           GST_FOURCC_ARGS (fourcc), cur_offset);
4885       qtdemux->offset = add_offset (qtdemux->offset, length);
4886       break;
4887     }
4888     case FOURCC_moov:
4889     {
4890       GstBuffer *moov = NULL;
4891
4892       if (qtdemux->got_moov) {
4893         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4894         qtdemux->offset = add_offset (qtdemux->offset, length);
4895         goto beach;
4896       }
4897
4898       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4899       if (ret != GST_FLOW_OK)
4900         goto beach;
4901       gst_buffer_map (moov, &map, GST_MAP_READ);
4902
4903       if (length != map.size) {
4904         /* Some files have a 'moov' atom at the end of the file which contains
4905          * a terminal 'free' atom where the body of the atom is missing.
4906          * Check for, and permit, this special case.
4907          */
4908         if (map.size >= 8) {
4909           guint8 *final_data = map.data + (map.size - 8);
4910           guint32 final_length = QT_UINT32 (final_data);
4911           guint32 final_fourcc = QT_FOURCC (final_data + 4);
4912
4913           if (final_fourcc == FOURCC_free
4914               && map.size + final_length - 8 == length) {
4915             /* Ok, we've found that special case. Allocate a new buffer with
4916              * that free atom actually present. */
4917             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4918             gst_buffer_fill (newmoov, 0, map.data, map.size);
4919             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4920             gst_buffer_unmap (moov, &map);
4921             gst_buffer_unref (moov);
4922             moov = newmoov;
4923             gst_buffer_map (moov, &map, GST_MAP_READ);
4924           }
4925         }
4926       }
4927
4928       if (length != map.size) {
4929         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4930             (_("This file is incomplete and cannot be played.")),
4931             ("We got less than expected (received %" G_GSIZE_FORMAT
4932                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4933                 (guint) length, cur_offset));
4934         gst_buffer_unmap (moov, &map);
4935         gst_buffer_unref (moov);
4936         ret = GST_FLOW_ERROR;
4937         goto beach;
4938       }
4939       qtdemux->offset += length;
4940
4941       qtdemux_parse_moov (qtdemux, map.data, length);
4942       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4943
4944       qtdemux_parse_tree (qtdemux);
4945       if (qtdemux->moov_node_compressed) {
4946         g_node_destroy (qtdemux->moov_node_compressed);
4947         g_free (qtdemux->moov_node->data);
4948       }
4949       qtdemux->moov_node_compressed = NULL;
4950       g_node_destroy (qtdemux->moov_node);
4951       qtdemux->moov_node = NULL;
4952       gst_buffer_unmap (moov, &map);
4953       gst_buffer_unref (moov);
4954       qtdemux->got_moov = TRUE;
4955
4956       break;
4957     }
4958     case FOURCC_ftyp:
4959     {
4960       GstBuffer *ftyp = NULL;
4961
4962       /* extract major brand; might come in handy for ISO vs QT issues */
4963       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4964       if (ret != GST_FLOW_OK)
4965         goto beach;
4966       qtdemux->offset += length;
4967       gst_buffer_map (ftyp, &map, GST_MAP_READ);
4968       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4969       gst_buffer_unmap (ftyp, &map);
4970       gst_buffer_unref (ftyp);
4971       break;
4972     }
4973     case FOURCC_uuid:
4974     {
4975       GstBuffer *uuid = NULL;
4976
4977       /* uuid are extension atoms */
4978       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4979       if (ret != GST_FLOW_OK)
4980         goto beach;
4981       qtdemux->offset += length;
4982       gst_buffer_map (uuid, &map, GST_MAP_READ);
4983       qtdemux_parse_uuid (qtdemux, map.data, map.size);
4984       gst_buffer_unmap (uuid, &map);
4985       gst_buffer_unref (uuid);
4986       break;
4987     }
4988     case FOURCC_sidx:
4989     {
4990       GstBuffer *sidx = NULL;
4991       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4992       if (ret != GST_FLOW_OK)
4993         goto beach;
4994       qtdemux->offset += length;
4995       gst_buffer_map (sidx, &map, GST_MAP_READ);
4996       qtdemux_parse_sidx (qtdemux, map.data, map.size);
4997       gst_buffer_unmap (sidx, &map);
4998       gst_buffer_unref (sidx);
4999       break;
5000     }
5001     default:
5002     {
5003       GstBuffer *unknown = NULL;
5004
5005       GST_LOG_OBJECT (qtdemux,
5006           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
5007           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
5008           cur_offset);
5009       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
5010       if (ret != GST_FLOW_OK)
5011         goto beach;
5012       gst_buffer_map (unknown, &map, GST_MAP_READ);
5013       GST_MEMDUMP ("Unknown tag", map.data, map.size);
5014       gst_buffer_unmap (unknown, &map);
5015       gst_buffer_unref (unknown);
5016       qtdemux->offset += length;
5017       break;
5018     }
5019   }
5020
5021 beach:
5022   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
5023     /* digested all data, show what we have */
5024 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
5025     if (qtdemux->spherical_metadata)
5026       _send_spherical_metadata_msg_to_bus (qtdemux);
5027 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
5028     qtdemux_prepare_streams (qtdemux);
5029     ret = qtdemux_expose_streams (qtdemux);
5030
5031     qtdemux->state = QTDEMUX_STATE_MOVIE;
5032     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
5033         qtdemux->state);
5034     return ret;
5035   }
5036   return ret;
5037 }
5038
5039 /* Seeks to the previous keyframe of the indexed stream and
5040  * aligns other streams with respect to the keyframe timestamp
5041  * of indexed stream. Only called in case of Reverse Playback
5042  */
5043 static GstFlowReturn
5044 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
5045 {
5046   guint8 n = 0;
5047   guint32 seg_idx = 0, k_index = 0;
5048   guint32 ref_seg_idx, ref_k_index;
5049   GstClockTime k_pos = 0, last_stop = 0;
5050   QtDemuxSegment *seg = NULL;
5051   QtDemuxStream *ref_str = NULL;
5052   guint64 seg_media_start_mov;  /* segment media start time in mov format */
5053   guint64 target_ts;
5054
5055   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
5056    * and finally align all the other streams on that timestamp with their
5057    * respective keyframes */
5058   for (n = 0; n < qtdemux->n_streams; n++) {
5059     QtDemuxStream *str = qtdemux->streams[n];
5060
5061     /* No candidate yet, take the first stream */
5062     if (!ref_str) {
5063       ref_str = str;
5064       continue;
5065     }
5066
5067     /* So that stream has a segment, we prefer video streams */
5068     if (str->subtype == FOURCC_vide) {
5069       ref_str = str;
5070       break;
5071     }
5072   }
5073
5074   if (G_UNLIKELY (!ref_str)) {
5075     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
5076     goto eos;
5077   }
5078
5079   if (G_UNLIKELY (!ref_str->from_sample)) {
5080     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
5081     goto eos;
5082   }
5083
5084   /* So that stream has been playing from from_sample to to_sample. We will
5085    * get the timestamp of the previous sample and search for a keyframe before
5086    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
5087   if (ref_str->subtype == FOURCC_vide) {
5088     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
5089         ref_str->from_sample - 1, FALSE);
5090   } else {
5091     if (ref_str->from_sample >= 10)
5092       k_index = ref_str->from_sample - 10;
5093     else
5094       k_index = 0;
5095   }
5096
5097   target_ts =
5098       ref_str->samples[k_index].timestamp +
5099       ref_str->samples[k_index].pts_offset;
5100
5101   /* get current segment for that stream */
5102   seg = &ref_str->segments[ref_str->segment_index];
5103   /* Use segment start in original timescale for comparisons */
5104   seg_media_start_mov = seg->trak_media_start;
5105
5106   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
5107       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
5108       k_index, target_ts, seg_media_start_mov,
5109       GST_TIME_ARGS (seg->media_start));
5110
5111   /* Crawl back through segments to find the one containing this I frame */
5112   while (target_ts < seg_media_start_mov) {
5113     GST_DEBUG_OBJECT (qtdemux,
5114         "keyframe position (sample %u) is out of segment %u " " target %"
5115         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
5116         ref_str->segment_index, target_ts, seg_media_start_mov);
5117
5118     if (G_UNLIKELY (!ref_str->segment_index)) {
5119       /* Reached first segment, let's consider it's EOS */
5120       goto eos;
5121     }
5122     ref_str->segment_index--;
5123     seg = &ref_str->segments[ref_str->segment_index];
5124     /* Use segment start in original timescale for comparisons */
5125     seg_media_start_mov = seg->trak_media_start;
5126   }
5127   /* Calculate time position of the keyframe and where we should stop */
5128   k_pos =
5129       QTSTREAMTIME_TO_GSTTIME (ref_str,
5130       target_ts - seg->trak_media_start) + seg->time;
5131   last_stop =
5132       QTSTREAMTIME_TO_GSTTIME (ref_str,
5133       ref_str->samples[ref_str->from_sample].timestamp -
5134       seg->trak_media_start) + seg->time;
5135
5136   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
5137       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
5138       k_index, GST_TIME_ARGS (k_pos));
5139
5140   /* Set last_stop with the keyframe timestamp we pushed of that stream */
5141   qtdemux->segment.position = last_stop;
5142   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
5143       GST_TIME_ARGS (last_stop));
5144
5145   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
5146     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
5147     goto eos;
5148   }
5149
5150   ref_seg_idx = ref_str->segment_index;
5151   ref_k_index = k_index;
5152
5153   /* Align them all on this */
5154   for (n = 0; n < qtdemux->n_streams; n++) {
5155     guint32 index = 0;
5156     GstClockTime seg_time = 0;
5157     QtDemuxStream *str = qtdemux->streams[n];
5158
5159     /* aligning reference stream again might lead to backing up to yet another
5160      * keyframe (due to timestamp rounding issues),
5161      * potentially putting more load on downstream; so let's try to avoid */
5162     if (str == ref_str) {
5163       seg_idx = ref_seg_idx;
5164       seg = &str->segments[seg_idx];
5165       k_index = ref_k_index;
5166       GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
5167           "sample at index %d", n, ref_str->segment_index, k_index);
5168     } else {
5169       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
5170       GST_DEBUG_OBJECT (qtdemux,
5171           "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
5172           seg_idx, GST_TIME_ARGS (k_pos));
5173
5174       /* get segment and time in the segment */
5175       seg = &str->segments[seg_idx];
5176       seg_time = k_pos - seg->time;
5177
5178       /* get the media time in the segment.
5179        * No adjustment for empty "filler" segments */
5180       if (seg->media_start != GST_CLOCK_TIME_NONE)
5181         seg_time += seg->media_start;
5182
5183       /* get the index of the sample with media time */
5184       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
5185       GST_DEBUG_OBJECT (qtdemux,
5186           "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
5187           GST_TIME_ARGS (seg_time), index);
5188
5189       /* find previous keyframe */
5190       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
5191     }
5192
5193     /* Remember until where we want to go */
5194     str->to_sample = str->from_sample - 1;
5195     /* Define our time position */
5196     target_ts =
5197         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
5198     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
5199     if (seg->media_start != GST_CLOCK_TIME_NONE)
5200       str->time_position -= seg->media_start;
5201
5202     /* Now seek back in time */
5203     gst_qtdemux_move_stream (qtdemux, str, k_index);
5204     GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
5205         GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
5206         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
5207   }
5208
5209   return GST_FLOW_OK;
5210
5211 eos:
5212   return GST_FLOW_EOS;
5213 }
5214
5215 /*
5216  * Gets the current qt segment start, stop and position for the
5217  * given time offset. This is used in update_segment()
5218  */
5219 static void
5220 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5221     QtDemuxStream * stream, GstClockTime offset,
5222     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5223 {
5224   GstClockTime seg_time;
5225   GstClockTime start, stop, time;
5226   QtDemuxSegment *segment;
5227
5228   segment = &stream->segments[stream->segment_index];
5229
5230   /* get time in this segment */
5231   seg_time = (offset - segment->time) * segment->rate;
5232
5233   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5234       GST_TIME_ARGS (seg_time));
5235
5236   if (G_UNLIKELY (seg_time > segment->duration)) {
5237     GST_LOG_OBJECT (stream->pad,
5238         "seg_time > segment->duration %" GST_TIME_FORMAT,
5239         GST_TIME_ARGS (segment->duration));
5240     seg_time = segment->duration;
5241   }
5242
5243   /* qtdemux->segment.stop is in outside-time-realm, whereas
5244    * segment->media_stop is in track-time-realm.
5245    *
5246    * In order to compare the two, we need to bring segment.stop
5247    * into the track-time-realm
5248    *
5249    * FIXME - does this comment still hold? Don't see any conversion here */
5250
5251   stop = qtdemux->segment.stop;
5252   if (stop == GST_CLOCK_TIME_NONE)
5253     stop = qtdemux->segment.duration;
5254   if (stop == GST_CLOCK_TIME_NONE)
5255     stop = segment->media_stop;
5256   else
5257     stop =
5258         MIN (segment->media_stop, stop - segment->time + segment->media_start);
5259
5260   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5261     start = segment->time + seg_time;
5262     time = offset;
5263     stop = start - seg_time + segment->duration;
5264   } else if (qtdemux->segment.rate >= 0) {
5265     start = MIN (segment->media_start + seg_time, stop);
5266     time = offset;
5267   } else {
5268     if (segment->media_start >= qtdemux->segment.start) {
5269       time = segment->time;
5270     } else {
5271       time = segment->time + (qtdemux->segment.start - segment->media_start);
5272     }
5273
5274     start = MAX (segment->media_start, qtdemux->segment.start);
5275     stop = MIN (segment->media_start + seg_time, stop);
5276   }
5277
5278   *_start = start;
5279   *_stop = stop;
5280   *_time = time;
5281 }
5282
5283 /*
5284  * Updates the qt segment used for the stream and pushes a new segment event
5285  * downstream on this stream's pad.
5286  */
5287 static gboolean
5288 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5289     gint seg_idx, GstClockTime offset, GstClockTime * _start,
5290     GstClockTime * _stop)
5291 {
5292   QtDemuxSegment *segment;
5293   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5294   gdouble rate;
5295   GstEvent *event;
5296
5297   /* update the current segment */
5298   stream->segment_index = seg_idx;
5299
5300   /* get the segment */
5301   segment = &stream->segments[seg_idx];
5302
5303   if (G_UNLIKELY (offset < segment->time)) {
5304     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5305         GST_TIME_ARGS (segment->time));
5306     return FALSE;
5307   }
5308
5309   /* segment lies beyond total indicated duration */
5310   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5311           segment->time > qtdemux->segment.duration)) {
5312     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5313         " < segment->time %" GST_TIME_FORMAT,
5314         GST_TIME_ARGS (qtdemux->segment.duration),
5315         GST_TIME_ARGS (segment->time));
5316     return FALSE;
5317   }
5318
5319   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5320       &start, &stop, &time);
5321
5322   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5323       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5324       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5325
5326   /* combine global rate with that of the segment */
5327   rate = segment->rate * qtdemux->segment.rate;
5328
5329   /* Copy flags from main segment */
5330   stream->segment.flags = qtdemux->segment.flags;
5331
5332   /* update the segment values used for clipping */
5333   stream->segment.offset = qtdemux->segment.offset;
5334   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5335   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5336   stream->segment.rate = rate;
5337   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5338       stream->cslg_shift);
5339   stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5340       stream->cslg_shift);
5341   stream->segment.time = time;
5342   stream->segment.position = stream->segment.start;
5343
5344   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5345       &stream->segment);
5346
5347   /* now prepare and send the segment */
5348   if (stream->pad) {
5349     event = gst_event_new_segment (&stream->segment);
5350     if (qtdemux->segment_seqnum) {
5351       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5352     }
5353     gst_pad_push_event (stream->pad, event);
5354     /* assume we can send more data now */
5355     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5356     /* clear to send tags on this pad now */
5357     gst_qtdemux_push_tags (qtdemux, stream);
5358   }
5359
5360   if (_start)
5361     *_start = start;
5362   if (_stop)
5363     *_stop = stop;
5364
5365   return TRUE;
5366 }
5367
5368 /* activate the given segment number @seg_idx of @stream at time @offset.
5369  * @offset is an absolute global position over all the segments.
5370  *
5371  * This will push out a NEWSEGMENT event with the right values and
5372  * position the stream index to the first decodable sample before
5373  * @offset.
5374  */
5375 static gboolean
5376 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5377     guint32 seg_idx, GstClockTime offset)
5378 {
5379   QtDemuxSegment *segment;
5380   guint32 index, kf_index;
5381   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5382
5383   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5384       seg_idx, GST_TIME_ARGS (offset));
5385
5386   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5387           &start, &stop))
5388     return FALSE;
5389
5390   segment = &stream->segments[stream->segment_index];
5391
5392   /* in the fragmented case, we pick a fragment that starts before our
5393    * desired position and rely on downstream to wait for a keyframe
5394    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5395    * tfra entries tells us which trun/sample the key unit is in, but we don't
5396    * make use of this additional information at the moment) */
5397   if (qtdemux->fragmented) {
5398     stream->to_sample = G_MAXUINT32;
5399     return TRUE;
5400   }
5401
5402   /* We don't need to look for a sample in push-based */
5403   if (!qtdemux->pullbased)
5404     return TRUE;
5405
5406   /* and move to the keyframe before the indicated media time of the
5407    * segment */
5408   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5409     if (qtdemux->segment.rate >= 0) {
5410       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5411       stream->to_sample = G_MAXUINT32;
5412       GST_DEBUG_OBJECT (stream->pad,
5413           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5414           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5415           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5416     } else {
5417       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5418       stream->to_sample = index;
5419       GST_DEBUG_OBJECT (stream->pad,
5420           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5421           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5422           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5423     }
5424   } else {
5425     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5426         "this is an empty segment");
5427     return TRUE;
5428   }
5429
5430   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5431    * encountered an error and printed a message so we return appropriately */
5432   if (index == -1)
5433     return FALSE;
5434
5435   /* we're at the right spot */
5436   if (index == stream->sample_index) {
5437     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5438     return TRUE;
5439   }
5440
5441   /* find keyframe of the target index */
5442   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5443
5444 /* *INDENT-OFF* */
5445 /* indent does stupid stuff with stream->samples[].timestamp */
5446
5447   /* if we move forwards, we don't have to go back to the previous
5448    * keyframe since we already sent that. We can also just jump to
5449    * the keyframe right before the target index if there is one. */
5450   if (index > stream->sample_index) {
5451     /* moving forwards check if we move past a keyframe */
5452     if (kf_index > stream->sample_index) {
5453       GST_DEBUG_OBJECT (stream->pad,
5454            "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5455            GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5456            GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5457       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5458     } else {
5459       GST_DEBUG_OBJECT (stream->pad,
5460           "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5461           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5462           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5463     }
5464   } else {
5465     GST_DEBUG_OBJECT (stream->pad,
5466         "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5467         GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5468         GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5469     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5470   }
5471
5472 /* *INDENT-ON* */
5473
5474   return TRUE;
5475 }
5476
5477 /* prepare to get the current sample of @stream, getting essential values.
5478  *
5479  * This function will also prepare and send the segment when needed.
5480  *
5481  * Return FALSE if the stream is EOS.
5482  *
5483  * PULL-BASED
5484  */
5485 static gboolean
5486 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5487     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5488     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5489     gboolean * keyframe)
5490 {
5491   QtDemuxSample *sample;
5492   GstClockTime time_position;
5493   guint32 seg_idx;
5494
5495   g_return_val_if_fail (stream != NULL, FALSE);
5496
5497   time_position = stream->time_position;
5498   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5499     goto eos;
5500
5501   seg_idx = stream->segment_index;
5502   if (G_UNLIKELY (seg_idx == -1)) {
5503     /* find segment corresponding to time_position if we are looking
5504      * for a segment. */
5505     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5506   }
5507
5508   /* different segment, activate it, sample_index will be set. */
5509   if (G_UNLIKELY (stream->segment_index != seg_idx))
5510     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5511
5512   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5513                   segment_index]))) {
5514     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5515
5516     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5517         " prepare empty sample");
5518
5519     *empty = TRUE;
5520     *pts = *dts = time_position;
5521     *duration = seg->duration - (time_position - seg->time);
5522
5523     return TRUE;
5524   }
5525
5526   *empty = FALSE;
5527
5528   if (stream->sample_index == -1)
5529     stream->sample_index = 0;
5530
5531   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5532       stream->sample_index, stream->n_samples);
5533
5534   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5535     if (!qtdemux->fragmented)
5536       goto eos;
5537
5538     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5539     do {
5540       GstFlowReturn flow;
5541
5542       GST_OBJECT_LOCK (qtdemux);
5543       flow = qtdemux_add_fragmented_samples (qtdemux);
5544       GST_OBJECT_UNLOCK (qtdemux);
5545
5546       if (flow != GST_FLOW_OK)
5547         goto eos;
5548     }
5549     while (stream->sample_index >= stream->n_samples);
5550   }
5551
5552   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5553     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5554         stream->sample_index);
5555     return FALSE;
5556   }
5557
5558   /* now get the info for the sample we're at */
5559   sample = &stream->samples[stream->sample_index];
5560
5561   *dts = QTSAMPLE_DTS (stream, sample);
5562   *pts = QTSAMPLE_PTS (stream, sample);
5563   *offset = sample->offset;
5564   *size = sample->size;
5565   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5566   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5567
5568   return TRUE;
5569
5570   /* special cases */
5571 eos:
5572   {
5573     stream->time_position = GST_CLOCK_TIME_NONE;
5574     return FALSE;
5575   }
5576 }
5577
5578 /* move to the next sample in @stream.
5579  *
5580  * Moves to the next segment when needed.
5581  */
5582 static void
5583 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5584 {
5585   QtDemuxSample *sample;
5586   QtDemuxSegment *segment;
5587
5588   /* get current segment */
5589   segment = &stream->segments[stream->segment_index];
5590
5591   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5592     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5593     goto next_segment;
5594   }
5595
5596   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5597     /* Mark the stream as EOS */
5598     GST_DEBUG_OBJECT (qtdemux,
5599         "reached max allowed sample %u, mark EOS", stream->to_sample);
5600     stream->time_position = GST_CLOCK_TIME_NONE;
5601     return;
5602   }
5603
5604   /* move to next sample */
5605   stream->sample_index++;
5606   stream->offset_in_sample = 0;
5607
5608   /* reached the last sample, we need the next segment */
5609   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5610     goto next_segment;
5611
5612   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5613     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5614         stream->sample_index);
5615     return;
5616   }
5617
5618   /* get next sample */
5619   sample = &stream->samples[stream->sample_index];
5620
5621   /* see if we are past the segment */
5622   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5623     goto next_segment;
5624
5625   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5626     /* inside the segment, update time_position, looks very familiar to
5627      * GStreamer segments, doesn't it? */
5628     stream->time_position =
5629         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5630   } else {
5631     /* not yet in segment, time does not yet increment. This means
5632      * that we are still prerolling keyframes to the decoder so it can
5633      * decode the first sample of the segment. */
5634     stream->time_position = segment->time;
5635   }
5636   return;
5637
5638   /* move to the next segment */
5639 next_segment:
5640   {
5641     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5642
5643     if (stream->segment_index == stream->n_segments - 1) {
5644       /* are we at the end of the last segment, we're EOS */
5645       stream->time_position = GST_CLOCK_TIME_NONE;
5646     } else {
5647       /* else we're only at the end of the current segment */
5648       stream->time_position = segment->stop_time;
5649     }
5650     /* make sure we select a new segment */
5651
5652     /* accumulate previous segments */
5653     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5654       stream->accumulated_base +=
5655           (stream->segment.stop -
5656           stream->segment.start) / ABS (stream->segment.rate);
5657
5658     stream->segment_index = -1;
5659   }
5660 }
5661
5662 static void
5663 gst_qtdemux_sync_streams (GstQTDemux * demux)
5664 {
5665   gint i;
5666
5667   if (demux->n_streams <= 1)
5668     return;
5669
5670   for (i = 0; i < demux->n_streams; i++) {
5671     QtDemuxStream *stream;
5672     GstClockTime end_time;
5673
5674     stream = demux->streams[i];
5675
5676     if (!stream->pad)
5677       continue;
5678
5679     /* TODO advance time on subtitle streams here, if any some day */
5680
5681     /* some clips/trailers may have unbalanced streams at the end,
5682      * so send EOS on shorter stream to prevent stalling others */
5683
5684     /* do not mess with EOS if SEGMENT seeking */
5685     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5686       continue;
5687
5688     if (demux->pullbased) {
5689       /* loop mode is sample time based */
5690       if (!STREAM_IS_EOS (stream))
5691         continue;
5692     } else {
5693       /* push mode is byte position based */
5694       if (stream->n_samples &&
5695           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5696         continue;
5697     }
5698
5699     if (stream->sent_eos)
5700       continue;
5701
5702     /* only act if some gap */
5703     end_time = stream->segments[stream->n_segments - 1].stop_time;
5704     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5705         ", stream end: %" GST_TIME_FORMAT,
5706         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5707     if (GST_CLOCK_TIME_IS_VALID (end_time)
5708         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5709       GstEvent *event;
5710
5711       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5712           GST_PAD_NAME (stream->pad));
5713       stream->sent_eos = TRUE;
5714       event = gst_event_new_eos ();
5715       if (demux->segment_seqnum)
5716         gst_event_set_seqnum (event, demux->segment_seqnum);
5717       gst_pad_push_event (stream->pad, event);
5718     }
5719   }
5720 }
5721
5722 /* EOS and NOT_LINKED need to be combined. This means that we return:
5723  *
5724  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5725  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5726  */
5727 static GstFlowReturn
5728 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5729     GstFlowReturn ret)
5730 {
5731   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5732
5733   if (stream->pad)
5734     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5735         ret);
5736   else
5737     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5738
5739   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5740   return ret;
5741 }
5742
5743 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5744  * completely clipped
5745  *
5746  * Should be used only with raw buffers */
5747 static GstBuffer *
5748 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5749     GstBuffer * buf)
5750 {
5751   guint64 start, stop, cstart, cstop, diff;
5752   GstClockTime pts, duration;
5753   gsize size, osize;
5754   gint num_rate, denom_rate;
5755   gint frame_size;
5756   gboolean clip_data;
5757   guint offset;
5758
5759   osize = size = gst_buffer_get_size (buf);
5760   offset = 0;
5761
5762   /* depending on the type, setup the clip parameters */
5763   if (stream->subtype == FOURCC_soun) {
5764     frame_size = CUR_STREAM (stream)->bytes_per_frame;
5765     num_rate = GST_SECOND;
5766     denom_rate = (gint) CUR_STREAM (stream)->rate;
5767     clip_data = TRUE;
5768   } else if (stream->subtype == FOURCC_vide) {
5769     frame_size = size;
5770     num_rate = CUR_STREAM (stream)->fps_n;
5771     denom_rate = CUR_STREAM (stream)->fps_d;
5772     clip_data = FALSE;
5773   } else
5774     goto wrong_type;
5775
5776   if (frame_size <= 0)
5777     goto bad_frame_size;
5778
5779   /* we can only clip if we have a valid pts */
5780   pts = GST_BUFFER_PTS (buf);
5781   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5782     goto no_pts;
5783
5784   duration = GST_BUFFER_DURATION (buf);
5785
5786   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5787     duration =
5788         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5789   }
5790
5791   start = pts;
5792   stop = start + duration;
5793
5794   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5795               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5796     goto clipped;
5797
5798   /* see if some clipping happened */
5799   diff = cstart - start;
5800   if (diff > 0) {
5801     pts += diff;
5802     duration -= diff;
5803
5804     if (clip_data) {
5805       /* bring clipped time to samples and to bytes */
5806       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5807       diff *= frame_size;
5808
5809       GST_DEBUG_OBJECT (qtdemux,
5810           "clipping start to %" GST_TIME_FORMAT " %"
5811           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5812
5813       offset = diff;
5814       size -= diff;
5815     }
5816   }
5817   diff = stop - cstop;
5818   if (diff > 0) {
5819     duration -= diff;
5820
5821     if (clip_data) {
5822       /* bring clipped time to samples and then to bytes */
5823       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5824       diff *= frame_size;
5825       GST_DEBUG_OBJECT (qtdemux,
5826           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5827           " bytes", GST_TIME_ARGS (cstop), diff);
5828       size -= diff;
5829     }
5830   }
5831
5832   if (offset != 0 || size != osize)
5833     gst_buffer_resize (buf, offset, size);
5834
5835   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5836   GST_BUFFER_PTS (buf) = pts;
5837   GST_BUFFER_DURATION (buf) = duration;
5838
5839   return buf;
5840
5841   /* dropped buffer */
5842 wrong_type:
5843   {
5844     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5845     return buf;
5846   }
5847 bad_frame_size:
5848   {
5849     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5850     return buf;
5851   }
5852 no_pts:
5853   {
5854     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5855     return buf;
5856   }
5857 clipped:
5858   {
5859     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5860     gst_buffer_unref (buf);
5861     return NULL;
5862   }
5863 }
5864
5865 static GstBuffer *
5866 gst_qtdemux_align_buffer (GstQTDemux * demux,
5867     GstBuffer * buffer, gsize alignment)
5868 {
5869   GstMapInfo map;
5870
5871   gst_buffer_map (buffer, &map, GST_MAP_READ);
5872
5873   if (map.size < sizeof (guintptr)) {
5874     gst_buffer_unmap (buffer, &map);
5875     return buffer;
5876   }
5877
5878   if (((guintptr) map.data) & (alignment - 1)) {
5879     GstBuffer *new_buffer;
5880     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5881
5882     new_buffer = gst_buffer_new_allocate (NULL,
5883         gst_buffer_get_size (buffer), &params);
5884
5885     /* Copy data "by hand", so ensure alignment is kept: */
5886     gst_buffer_fill (new_buffer, 0, map.data, map.size);
5887
5888     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5889     GST_DEBUG_OBJECT (demux,
5890         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5891         alignment);
5892
5893     gst_buffer_unmap (buffer, &map);
5894     gst_buffer_unref (buffer);
5895
5896     return new_buffer;
5897   }
5898
5899   gst_buffer_unmap (buffer, &map);
5900   return buffer;
5901 }
5902
5903 /* the input buffer metadata must be writable,
5904  * but time/duration etc not yet set and need not be preserved */
5905 static GstBuffer *
5906 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5907     GstBuffer * buf)
5908 {
5909   GstMapInfo map;
5910   guint nsize = 0;
5911   gchar *str;
5912
5913   /* not many cases for now */
5914   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5915     /* send a one time dvd clut event */
5916     if (stream->pending_event && stream->pad)
5917       gst_pad_push_event (stream->pad, stream->pending_event);
5918     stream->pending_event = NULL;
5919   }
5920
5921   if (G_UNLIKELY (stream->subtype != FOURCC_text
5922           && stream->subtype != FOURCC_sbtl &&
5923           stream->subtype != FOURCC_subp)) {
5924     return buf;
5925   }
5926
5927   gst_buffer_map (buf, &map, GST_MAP_READ);
5928
5929   /* empty buffer is sent to terminate previous subtitle */
5930   if (map.size <= 2) {
5931     gst_buffer_unmap (buf, &map);
5932     gst_buffer_unref (buf);
5933     return NULL;
5934   }
5935   if (stream->subtype == FOURCC_subp) {
5936     /* That's all the processing needed for subpictures */
5937     gst_buffer_unmap (buf, &map);
5938     return buf;
5939   }
5940
5941   nsize = GST_READ_UINT16_BE (map.data);
5942   nsize = MIN (nsize, map.size - 2);
5943
5944   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5945       nsize, map.size);
5946
5947   /* takes care of UTF-8 validation or UTF-16 recognition,
5948    * no other encoding expected */
5949   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5950   gst_buffer_unmap (buf, &map);
5951   if (str) {
5952     gst_buffer_unref (buf);
5953     buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5954   } else {
5955     /* this should not really happen unless the subtitle is corrupted */
5956     gst_buffer_unref (buf);
5957     buf = NULL;
5958   }
5959
5960   /* FIXME ? convert optional subsequent style info to markup */
5961
5962   return buf;
5963 }
5964
5965 /* Sets a buffer's attributes properly and pushes it downstream.
5966  * Also checks for additional actions and custom processing that may
5967  * need to be done first.
5968  */
5969 static GstFlowReturn
5970 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5971     QtDemuxStream * stream, GstBuffer * buf,
5972     GstClockTime dts, GstClockTime pts, GstClockTime duration,
5973     gboolean keyframe, GstClockTime position, guint64 byte_position)
5974 {
5975   GstFlowReturn ret = GST_FLOW_OK;
5976
5977   /* offset the timestamps according to the edit list */
5978
5979   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5980     gchar *url;
5981     GstMapInfo map;
5982
5983     gst_buffer_map (buf, &map, GST_MAP_READ);
5984     url = g_strndup ((gchar *) map.data, map.size);
5985     gst_buffer_unmap (buf, &map);
5986     if (url != NULL && strlen (url) != 0) {
5987       /* we have RTSP redirect now */
5988       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5989           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5990               gst_structure_new ("redirect",
5991                   "new-location", G_TYPE_STRING, url, NULL)));
5992       qtdemux->posted_redirect = TRUE;
5993     } else {
5994       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5995           "posting");
5996     }
5997     g_free (url);
5998   }
5999
6000   /* position reporting */
6001   if (qtdemux->segment.rate >= 0) {
6002     qtdemux->segment.position = position;
6003     gst_qtdemux_sync_streams (qtdemux);
6004   }
6005
6006   if (G_UNLIKELY (!stream->pad)) {
6007     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6008     gst_buffer_unref (buf);
6009     goto exit;
6010   }
6011
6012   /* send out pending buffers */
6013   while (stream->buffers) {
6014     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6015
6016     if (G_UNLIKELY (stream->discont)) {
6017       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6018       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6019       stream->discont = FALSE;
6020     } else {
6021       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6022     }
6023
6024     if (stream->alignment > 1)
6025       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6026     gst_pad_push (stream->pad, buffer);
6027
6028     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6029   }
6030
6031   /* we're going to modify the metadata */
6032   buf = gst_buffer_make_writable (buf);
6033
6034   if (G_UNLIKELY (stream->need_process))
6035     buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
6036
6037   if (!buf) {
6038     goto exit;
6039   }
6040
6041   GST_BUFFER_DTS (buf) = dts;
6042   GST_BUFFER_PTS (buf) = pts;
6043   GST_BUFFER_DURATION (buf) = duration;
6044   GST_BUFFER_OFFSET (buf) = -1;
6045   GST_BUFFER_OFFSET_END (buf) = -1;
6046
6047   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6048     gst_buffer_append_memory (buf,
6049         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6050
6051   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6052     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6053   }
6054 #if 0
6055   if (G_UNLIKELY (qtdemux->element_index)) {
6056     GstClockTime stream_time;
6057
6058     stream_time =
6059         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6060         timestamp);
6061     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6062       GST_LOG_OBJECT (qtdemux,
6063           "adding association %" GST_TIME_FORMAT "-> %"
6064           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6065       gst_index_add_association (qtdemux->element_index,
6066           qtdemux->index_id,
6067           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6068           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6069           GST_FORMAT_BYTES, byte_position, NULL);
6070     }
6071   }
6072 #endif
6073
6074   if (stream->need_clip)
6075     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6076
6077   if (G_UNLIKELY (buf == NULL))
6078     goto exit;
6079
6080   if (G_UNLIKELY (stream->discont)) {
6081     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6082     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6083     stream->discont = FALSE;
6084   } else {
6085     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6086   }
6087
6088   if (!keyframe) {
6089     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6090     stream->on_keyframe = FALSE;
6091   } else {
6092     stream->on_keyframe = TRUE;
6093   }
6094
6095
6096   GST_LOG_OBJECT (qtdemux,
6097       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6098       ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
6099       GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
6100       GST_PAD_NAME (stream->pad));
6101
6102   if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
6103     GstStructure *crypto_info;
6104     QtDemuxCencSampleSetInfo *info =
6105         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6106     gint index;
6107     GstEvent *event;
6108
6109     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6110       gst_pad_push_event (stream->pad, event);
6111     }
6112
6113     if (info->crypto_info == NULL) {
6114       GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
6115       gst_buffer_unref (buf);
6116       goto exit;
6117     }
6118
6119     /* The end of the crypto_info array matches our n_samples position,
6120      * so count backward from there */
6121     index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6122     if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6123       /* steal structure from array */
6124       crypto_info = g_ptr_array_index (info->crypto_info, index);
6125       g_ptr_array_index (info->crypto_info, index) = NULL;
6126       GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6127           info->crypto_info->len);
6128       if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6129         GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
6130     } else {
6131       GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6132           index, stream->sample_index);
6133     }
6134   }
6135
6136   if (stream->alignment > 1)
6137     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6138
6139   ret = gst_pad_push (stream->pad, buf);
6140
6141   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6142     /* mark position in stream, we'll need this to know when to send GAP event */
6143     stream->segment.position = pts + duration;
6144   }
6145
6146 exit:
6147   return ret;
6148 }
6149
6150 static const QtDemuxRandomAccessEntry *
6151 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6152     GstClockTime pos, gboolean after)
6153 {
6154   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6155   guint n_entries = stream->n_ra_entries;
6156   guint i;
6157
6158   /* we assume the table is sorted */
6159   for (i = 0; i < n_entries; ++i) {
6160     if (entries[i].ts > pos)
6161       break;
6162   }
6163
6164   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6165    * probably okay to assume that the index lists the very first fragment */
6166   if (i == 0)
6167     return &entries[0];
6168
6169   if (after)
6170     return &entries[i];
6171   else
6172     return &entries[i - 1];
6173 }
6174
6175 static gboolean
6176 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6177 {
6178   const QtDemuxRandomAccessEntry *best_entry = NULL;
6179   guint i;
6180
6181   GST_OBJECT_LOCK (qtdemux);
6182
6183   g_assert (qtdemux->n_streams > 0);
6184
6185   for (i = 0; i < qtdemux->n_streams; i++) {
6186     const QtDemuxRandomAccessEntry *entry;
6187     QtDemuxStream *stream;
6188     gboolean is_audio_or_video;
6189
6190     stream = qtdemux->streams[i];
6191
6192     g_free (stream->samples);
6193     stream->samples = NULL;
6194     stream->n_samples = 0;
6195     stream->stbl_index = -1;    /* no samples have yet been parsed */
6196     stream->sample_index = -1;
6197
6198     if (stream->protection_scheme_info) {
6199       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6200       if (stream->protection_scheme_type == FOURCC_cenc) {
6201         QtDemuxCencSampleSetInfo *info =
6202             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6203         if (info->crypto_info) {
6204           g_ptr_array_free (info->crypto_info, TRUE);
6205           info->crypto_info = NULL;
6206         }
6207       }
6208     }
6209
6210     if (stream->ra_entries == NULL)
6211       continue;
6212
6213     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6214       is_audio_or_video = TRUE;
6215     else
6216       is_audio_or_video = FALSE;
6217
6218     entry =
6219         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6220         stream->time_position, !is_audio_or_video);
6221
6222     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6223         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6224
6225     stream->pending_seek = entry;
6226
6227     /* decide position to jump to just based on audio/video tracks, not subs */
6228     if (!is_audio_or_video)
6229       continue;
6230
6231     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6232       best_entry = entry;
6233   }
6234
6235   if (best_entry == NULL) {
6236     GST_OBJECT_UNLOCK (qtdemux);
6237     return FALSE;
6238   }
6239
6240   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6241       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6242       GST_TIME_ARGS (qtdemux->streams[0]->time_position),
6243       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6244
6245   qtdemux->moof_offset = best_entry->moof_offset;
6246
6247   qtdemux_add_fragmented_samples (qtdemux);
6248
6249   GST_OBJECT_UNLOCK (qtdemux);
6250   return TRUE;
6251 }
6252
6253 static GstFlowReturn
6254 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6255 {
6256   GstFlowReturn ret = GST_FLOW_OK;
6257   GstBuffer *buf = NULL;
6258   QtDemuxStream *stream;
6259   GstClockTime min_time;
6260   guint64 offset = 0;
6261   GstClockTime dts = GST_CLOCK_TIME_NONE;
6262   GstClockTime pts = GST_CLOCK_TIME_NONE;
6263   GstClockTime duration = 0;
6264   gboolean keyframe = FALSE;
6265   guint sample_size = 0;
6266   gboolean empty = 0;
6267   guint size;
6268   gint index;
6269   gint i;
6270
6271   gst_qtdemux_push_pending_newsegment (qtdemux);
6272
6273   if (qtdemux->fragmented_seek_pending) {
6274     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6275     gst_qtdemux_do_fragmented_seek (qtdemux);
6276     GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6277     qtdemux->fragmented_seek_pending = FALSE;
6278   }
6279
6280   /* Figure out the next stream sample to output, min_time is expressed in
6281    * global time and runs over the edit list segments. */
6282   min_time = G_MAXUINT64;
6283   index = -1;
6284   for (i = 0; i < qtdemux->n_streams; i++) {
6285     GstClockTime position;
6286
6287     stream = qtdemux->streams[i];
6288     position = stream->time_position;
6289
6290     /* position of -1 is EOS */
6291     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6292       min_time = position;
6293       index = i;
6294     }
6295   }
6296   /* all are EOS */
6297   if (G_UNLIKELY (index == -1)) {
6298     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6299     goto eos;
6300   }
6301
6302   /* check for segment end */
6303   if (G_UNLIKELY (qtdemux->segment.stop != -1
6304           && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6305               || (qtdemux->segment.rate < 0
6306                   && qtdemux->segment.start > min_time))
6307           && qtdemux->streams[index]->on_keyframe)) {
6308     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6309     qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
6310     goto eos_stream;
6311   }
6312
6313   /* gap events for subtitle streams */
6314   for (i = 0; i < qtdemux->n_streams; i++) {
6315     stream = qtdemux->streams[i];
6316     if (stream->pad && (stream->subtype == FOURCC_subp
6317             || stream->subtype == FOURCC_text
6318             || stream->subtype == FOURCC_sbtl)) {
6319       /* send one second gap events until the stream catches up */
6320       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6321       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6322           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6323           stream->segment.position + GST_SECOND < min_time) {
6324         GstEvent *gap =
6325             gst_event_new_gap (stream->segment.position, GST_SECOND);
6326         gst_pad_push_event (stream->pad, gap);
6327         stream->segment.position += GST_SECOND;
6328       }
6329     }
6330   }
6331
6332   stream = qtdemux->streams[index];
6333   /* fetch info for the current sample of this stream */
6334   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6335               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6336     goto eos_stream;
6337
6338   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6339   if (stream->new_caps) {
6340     gst_qtdemux_configure_stream (qtdemux, stream);
6341     qtdemux_do_allocation (qtdemux, stream);
6342   }
6343
6344   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6345   if (G_UNLIKELY (qtdemux->
6346           segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6347     if (stream->subtype == FOURCC_vide && !keyframe) {
6348       GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
6349       goto next;
6350     }
6351   }
6352
6353   GST_DEBUG_OBJECT (qtdemux,
6354       "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
6355       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6356       ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
6357       GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
6358
6359   if (G_UNLIKELY (empty)) {
6360     /* empty segment, push a gap and move to the next one */
6361     gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6362     stream->segment.position = pts + duration;
6363     goto next;
6364   }
6365
6366   /* hmm, empty sample, skip and move to next sample */
6367   if (G_UNLIKELY (sample_size <= 0))
6368     goto next;
6369
6370   /* last pushed sample was out of boundary, goto next sample */
6371   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6372     goto next;
6373
6374   if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6375     size = sample_size;
6376   } else {
6377     GST_DEBUG_OBJECT (qtdemux,
6378         "size %d larger than stream max_buffer_size %d, trimming",
6379         sample_size, stream->max_buffer_size);
6380     size =
6381         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6382   }
6383
6384   if (qtdemux->cenc_aux_info_offset > 0) {
6385     GstMapInfo map;
6386     GstByteReader br;
6387     GstBuffer *aux_info = NULL;
6388
6389     /* pull the data stored before the sample */
6390     ret =
6391         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6392         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6393     if (G_UNLIKELY (ret != GST_FLOW_OK))
6394       goto beach;
6395     gst_buffer_map (aux_info, &map, GST_MAP_READ);
6396     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6397     gst_byte_reader_init (&br, map.data + 8, map.size);
6398     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6399             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6400       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6401       gst_buffer_unmap (aux_info, &map);
6402       gst_buffer_unref (aux_info);
6403       ret = GST_FLOW_ERROR;
6404       goto beach;
6405     }
6406     gst_buffer_unmap (aux_info, &map);
6407     gst_buffer_unref (aux_info);
6408   }
6409
6410   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6411       offset);
6412
6413   if (stream->use_allocator) {
6414     /* if we have a per-stream allocator, use it */
6415     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6416   }
6417
6418   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6419       size, &buf);
6420   if (G_UNLIKELY (ret != GST_FLOW_OK))
6421     goto beach;
6422
6423   if (size != sample_size) {
6424     pts += gst_util_uint64_scale_int (GST_SECOND,
6425         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6426         stream->timescale);
6427     dts +=
6428         gst_util_uint64_scale_int (GST_SECOND,
6429         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6430         stream->timescale);
6431     duration =
6432         gst_util_uint64_scale_int (GST_SECOND,
6433         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6434   }
6435
6436   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6437       dts, pts, duration, keyframe, min_time, offset);
6438
6439   if (size != sample_size) {
6440     QtDemuxSample *sample = &stream->samples[stream->sample_index];
6441     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6442
6443     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6444         sample->timestamp +
6445         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6446     if (time_position >= segment->media_start) {
6447       /* inside the segment, update time_position, looks very familiar to
6448        * GStreamer segments, doesn't it? */
6449       stream->time_position = (time_position - segment->media_start) +
6450           segment->time;
6451     } else {
6452       /* not yet in segment, time does not yet increment. This means
6453        * that we are still prerolling keyframes to the decoder so it can
6454        * decode the first sample of the segment. */
6455       stream->time_position = segment->time;
6456     }
6457   }
6458
6459   /* combine flows */
6460   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6461   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6462    * we have no more data for the pad to push */
6463   if (ret == GST_FLOW_EOS)
6464     ret = GST_FLOW_OK;
6465
6466   stream->offset_in_sample += size;
6467   if (stream->offset_in_sample >= sample_size) {
6468     gst_qtdemux_advance_sample (qtdemux, stream);
6469   }
6470   goto beach;
6471
6472 next:
6473   gst_qtdemux_advance_sample (qtdemux, stream);
6474
6475 beach:
6476   return ret;
6477
6478   /* special cases */
6479 eos:
6480   {
6481     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6482     ret = GST_FLOW_EOS;
6483     goto beach;
6484   }
6485 eos_stream:
6486   {
6487     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6488     /* EOS will be raised if all are EOS */
6489     ret = GST_FLOW_OK;
6490     goto beach;
6491   }
6492 }
6493
6494 static void
6495 gst_qtdemux_loop (GstPad * pad)
6496 {
6497   GstQTDemux *qtdemux;
6498   guint64 cur_offset;
6499   GstFlowReturn ret;
6500
6501   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6502
6503   cur_offset = qtdemux->offset;
6504   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6505       cur_offset, qt_demux_state_string (qtdemux->state));
6506
6507   switch (qtdemux->state) {
6508     case QTDEMUX_STATE_INITIAL:
6509     case QTDEMUX_STATE_HEADER:
6510       ret = gst_qtdemux_loop_state_header (qtdemux);
6511       break;
6512     case QTDEMUX_STATE_MOVIE:
6513       ret = gst_qtdemux_loop_state_movie (qtdemux);
6514       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6515         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6516       }
6517       break;
6518     default:
6519       /* ouch */
6520       goto invalid_state;
6521   }
6522
6523   /* if something went wrong, pause */
6524   if (ret != GST_FLOW_OK)
6525     goto pause;
6526
6527 done:
6528   gst_object_unref (qtdemux);
6529   return;
6530
6531   /* ERRORS */
6532 invalid_state:
6533   {
6534     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6535         (NULL), ("streaming stopped, invalid state"));
6536     gst_pad_pause_task (pad);
6537     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6538     goto done;
6539   }
6540 pause:
6541   {
6542     const gchar *reason = gst_flow_get_name (ret);
6543
6544     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6545
6546     gst_pad_pause_task (pad);
6547
6548     /* fatal errors need special actions */
6549     /* check EOS */
6550     if (ret == GST_FLOW_EOS) {
6551       if (qtdemux->n_streams == 0) {
6552         /* we have no streams, post an error */
6553         gst_qtdemux_post_no_playable_stream_error (qtdemux);
6554       }
6555       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6556         gint64 stop;
6557
6558         if ((stop = qtdemux->segment.stop) == -1)
6559           stop = qtdemux->segment.duration;
6560
6561         if (qtdemux->segment.rate >= 0) {
6562           GstMessage *message;
6563           GstEvent *event;
6564
6565           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6566           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6567               GST_FORMAT_TIME, stop);
6568           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6569           if (qtdemux->segment_seqnum) {
6570             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6571             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6572           }
6573           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6574           gst_qtdemux_push_event (qtdemux, event);
6575         } else {
6576           GstMessage *message;
6577           GstEvent *event;
6578
6579           /*  For Reverse Playback */
6580           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6581           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6582               GST_FORMAT_TIME, qtdemux->segment.start);
6583           event = gst_event_new_segment_done (GST_FORMAT_TIME,
6584               qtdemux->segment.start);
6585           if (qtdemux->segment_seqnum) {
6586             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6587             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6588           }
6589           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6590           gst_qtdemux_push_event (qtdemux, event);
6591         }
6592       } else {
6593         GstEvent *event;
6594
6595         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6596         event = gst_event_new_eos ();
6597         if (qtdemux->segment_seqnum)
6598           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6599         gst_qtdemux_push_event (qtdemux, event);
6600       }
6601     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6602       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6603       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6604     }
6605     goto done;
6606   }
6607 }
6608
6609 /*
6610  * has_next_entry
6611  *
6612  * Returns if there are samples to be played.
6613  */
6614 static gboolean
6615 has_next_entry (GstQTDemux * demux)
6616 {
6617   QtDemuxStream *stream;
6618   int i;
6619
6620   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6621
6622   for (i = 0; i < demux->n_streams; i++) {
6623     stream = demux->streams[i];
6624
6625     if (stream->sample_index == -1) {
6626       stream->sample_index = 0;
6627       stream->offset_in_sample = 0;
6628     }
6629
6630     if (stream->sample_index >= stream->n_samples) {
6631       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6632       continue;
6633     }
6634     GST_DEBUG_OBJECT (demux, "Found a sample");
6635     return TRUE;
6636   }
6637
6638   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6639   return FALSE;
6640 }
6641
6642 /*
6643  * next_entry_size
6644  *
6645  * Returns the size of the first entry at the current offset.
6646  * If -1, there are none (which means EOS or empty file).
6647  */
6648 static guint64
6649 next_entry_size (GstQTDemux * demux)
6650 {
6651   QtDemuxStream *stream;
6652   int i;
6653   int smallidx = -1;
6654   guint64 smalloffs = (guint64) - 1;
6655   QtDemuxSample *sample;
6656
6657   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6658       demux->offset);
6659
6660   for (i = 0; i < demux->n_streams; i++) {
6661     stream = demux->streams[i];
6662
6663     if (stream->sample_index == -1) {
6664       stream->sample_index = 0;
6665       stream->offset_in_sample = 0;
6666     }
6667
6668     if (stream->sample_index >= stream->n_samples) {
6669       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6670       continue;
6671     }
6672
6673     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6674       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6675           stream->sample_index);
6676       return -1;
6677     }
6678
6679     sample = &stream->samples[stream->sample_index];
6680
6681     GST_LOG_OBJECT (demux,
6682         "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6683         " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6684         sample->offset, sample->size);
6685
6686     if (((smalloffs == -1)
6687             || (sample->offset < smalloffs)) && (sample->size)) {
6688       smallidx = i;
6689       smalloffs = sample->offset;
6690     }
6691   }
6692
6693   GST_LOG_OBJECT (demux,
6694       "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6695       G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6696
6697   if (smallidx == -1)
6698     return -1;
6699
6700   stream = demux->streams[smallidx];
6701   sample = &stream->samples[stream->sample_index];
6702
6703   if (sample->offset >= demux->offset) {
6704     demux->todrop = sample->offset - demux->offset;
6705     return sample->size + demux->todrop;
6706   }
6707
6708   GST_DEBUG_OBJECT (demux,
6709       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6710   return -1;
6711 }
6712
6713 static void
6714 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6715 {
6716   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6717
6718   gst_element_post_message (GST_ELEMENT_CAST (demux),
6719       gst_message_new_element (GST_OBJECT_CAST (demux),
6720           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6721 }
6722
6723 static gboolean
6724 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6725 {
6726   GstEvent *event;
6727   gboolean res = 0;
6728
6729   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6730
6731   event =
6732       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6733       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6734       GST_SEEK_TYPE_NONE, -1);
6735
6736   /* store seqnum to drop flush events, they don't need to reach downstream */
6737   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6738   res = gst_pad_push_event (demux->sinkpad, event);
6739   demux->offset_seek_seqnum = 0;
6740
6741   return res;
6742 }
6743
6744 /* check for seekable upstream, above and beyond a mere query */
6745 static void
6746 gst_qtdemux_check_seekability (GstQTDemux * demux)
6747 {
6748   GstQuery *query;
6749   gboolean seekable = FALSE;
6750   gint64 start = -1, stop = -1;
6751
6752   if (demux->upstream_size)
6753     return;
6754
6755   if (demux->upstream_format_is_time)
6756     return;
6757
6758   query = gst_query_new_seeking (GST_FORMAT_BYTES);
6759   if (!gst_pad_peer_query (demux->sinkpad, query)) {
6760     GST_DEBUG_OBJECT (demux, "seeking query failed");
6761     goto done;
6762   }
6763
6764   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6765
6766   /* try harder to query upstream size if we didn't get it the first time */
6767   if (seekable && stop == -1) {
6768     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6769     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6770   }
6771
6772   /* if upstream doesn't know the size, it's likely that it's not seekable in
6773    * practice even if it technically may be seekable */
6774   if (seekable && (start != 0 || stop <= start)) {
6775     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6776     seekable = FALSE;
6777   }
6778
6779 done:
6780   gst_query_unref (query);
6781
6782   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6783       G_GUINT64_FORMAT ")", seekable, start, stop);
6784   demux->upstream_seekable = seekable;
6785   demux->upstream_size = seekable ? stop : -1;
6786 }
6787
6788 static void
6789 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6790 {
6791   g_return_if_fail (bytes <= demux->todrop);
6792
6793   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6794   gst_adapter_flush (demux->adapter, bytes);
6795   demux->neededbytes -= bytes;
6796   demux->offset += bytes;
6797   demux->todrop -= bytes;
6798 }
6799
6800 static void
6801 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6802 {
6803   if (G_UNLIKELY (demux->pending_newsegment)) {
6804     gint i;
6805
6806     gst_qtdemux_push_pending_newsegment (demux);
6807     /* clear to send tags on all streams */
6808     for (i = 0; i < demux->n_streams; i++) {
6809       QtDemuxStream *stream;
6810       stream = demux->streams[i];
6811       gst_qtdemux_push_tags (demux, stream);
6812       if (CUR_STREAM (stream)->sparse) {
6813         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6814         gst_pad_push_event (stream->pad,
6815             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6816       }
6817     }
6818   }
6819 }
6820
6821 static void
6822 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6823     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6824 {
6825   GstClockTime ts, dur;
6826   GstEvent *gap;
6827
6828   ts = pos;
6829   dur =
6830       stream->segments[segment_index].duration - (pos -
6831       stream->segments[segment_index].time);
6832   gap = gst_event_new_gap (ts, dur);
6833   stream->time_position += dur;
6834
6835   GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6836       "segment: %" GST_PTR_FORMAT, gap);
6837   gst_pad_push_event (stream->pad, gap);
6838 }
6839
6840 static void
6841 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6842     QtDemuxStream * stream)
6843 {
6844   gint i;
6845
6846   /* Push any initial gap segments before proceeding to the
6847    * 'real' data */
6848   for (i = 0; i < stream->n_segments; i++) {
6849     gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6850
6851     if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6852       gst_qtdemux_send_gap_for_segment (demux, stream, i,
6853           stream->time_position);
6854     } else {
6855       /* Only support empty segment at the beginning followed by
6856        * one non-empty segment, this was checked when parsing the
6857        * edts atom, arriving here is unexpected */
6858       g_assert (i + 1 == stream->n_segments);
6859       break;
6860     }
6861   }
6862 }
6863
6864 static GstFlowReturn
6865 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6866 {
6867   GstQTDemux *demux;
6868
6869   demux = GST_QTDEMUX (parent);
6870
6871   GST_DEBUG_OBJECT (demux,
6872       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6873       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6874       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6875       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6876       gst_buffer_get_size (inbuf), demux->offset);
6877
6878   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6879     gboolean is_gap_input = FALSE;
6880     gint i;
6881
6882     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6883
6884     for (i = 0; i < demux->n_streams; i++) {
6885       demux->streams[i]->discont = TRUE;
6886     }
6887
6888     /* Check if we can land back on our feet in the case where upstream is
6889      * handling the seeking/pushing of samples with gaps in between (like
6890      * in the case of trick-mode DASH for example) */
6891     if (demux->upstream_format_is_time
6892         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6893       gint i;
6894       for (i = 0; i < demux->n_streams; i++) {
6895         guint32 res;
6896         GST_LOG_OBJECT (demux,
6897             "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6898             " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6899         res =
6900             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6901             demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6902         if (res != -1) {
6903           QtDemuxSample *sample = &demux->streams[i]->samples[res];
6904           GST_LOG_OBJECT (demux,
6905               "Checking if sample %d from stream %d is valid (offset:%"
6906               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6907               sample->offset, sample->size);
6908           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6909             GST_LOG_OBJECT (demux,
6910                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6911                 res);
6912             is_gap_input = TRUE;
6913             /* We can go back to standard playback mode */
6914             demux->state = QTDEMUX_STATE_MOVIE;
6915             /* Remember which sample this stream is at */
6916             demux->streams[i]->sample_index = res;
6917             /* Finally update all push-based values to the expected values */
6918             demux->neededbytes = demux->streams[i]->samples[res].size;
6919             demux->offset = GST_BUFFER_OFFSET (inbuf);
6920             demux->mdatleft =
6921                 demux->mdatsize - demux->offset + demux->mdatoffset;
6922             demux->todrop = 0;
6923           }
6924         }
6925       }
6926       if (!is_gap_input) {
6927         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6928         /* Reset state if it's a real discont */
6929         demux->neededbytes = 16;
6930         demux->state = QTDEMUX_STATE_INITIAL;
6931         demux->offset = GST_BUFFER_OFFSET (inbuf);
6932         gst_adapter_clear (demux->adapter);
6933       }
6934     }
6935     /* Reverse fragmented playback, need to flush all we have before
6936      * consuming a new fragment.
6937      * The samples array have the timestamps calculated by accumulating the
6938      * durations but this won't work for reverse playback of fragments as
6939      * the timestamps of a subsequent fragment should be smaller than the
6940      * previously received one. */
6941     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6942       gst_qtdemux_process_adapter (demux, TRUE);
6943       for (i = 0; i < demux->n_streams; i++)
6944         gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6945     }
6946   }
6947
6948   gst_adapter_push (demux->adapter, inbuf);
6949
6950   GST_DEBUG_OBJECT (demux,
6951       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6952       demux->neededbytes, gst_adapter_available (demux->adapter));
6953
6954   return gst_qtdemux_process_adapter (demux, FALSE);
6955 }
6956
6957 static GstFlowReturn
6958 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6959 {
6960   GstFlowReturn ret = GST_FLOW_OK;
6961
6962   /* we never really mean to buffer that much */
6963   if (demux->neededbytes == -1) {
6964     goto eos;
6965   }
6966
6967   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6968       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6969
6970 #ifndef GST_DISABLE_GST_DEBUG
6971     {
6972       guint64 discont_offset, distance_from_discont;
6973
6974       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6975       distance_from_discont =
6976           gst_adapter_distance_from_discont (demux->adapter);
6977
6978       GST_DEBUG_OBJECT (demux,
6979           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6980           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6981           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6982           demux->offset, discont_offset, distance_from_discont);
6983     }
6984 #endif
6985
6986     switch (demux->state) {
6987       case QTDEMUX_STATE_INITIAL:{
6988         const guint8 *data;
6989         guint32 fourcc;
6990         guint64 size;
6991
6992         gst_qtdemux_check_seekability (demux);
6993
6994         data = gst_adapter_map (demux->adapter, demux->neededbytes);
6995
6996         /* get fourcc/length, set neededbytes */
6997         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6998             &size, &fourcc);
6999         gst_adapter_unmap (demux->adapter);
7000         data = NULL;
7001         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7002             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7003         if (size == 0) {
7004           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7005               (_("This file is invalid and cannot be played.")),
7006               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7007                   GST_FOURCC_ARGS (fourcc)));
7008           ret = GST_FLOW_ERROR;
7009           break;
7010         }
7011         if (fourcc == FOURCC_mdat) {
7012           gint next_entry = next_entry_size (demux);
7013           if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
7014             /* we have the headers, start playback */
7015             demux->state = QTDEMUX_STATE_MOVIE;
7016             demux->neededbytes = next_entry;
7017             demux->mdatleft = size;
7018             demux->mdatsize = demux->mdatleft;
7019           } else {
7020             /* no headers yet, try to get them */
7021             guint bs;
7022             gboolean res;
7023             guint64 old, target;
7024
7025           buffer_data:
7026             old = demux->offset;
7027             target = old + size;
7028
7029             /* try to jump over the atom with a seek */
7030             /* only bother if it seems worth doing so,
7031              * and avoids possible upstream/server problems */
7032             if (demux->upstream_seekable &&
7033                 demux->upstream_size > 4 * (1 << 20)) {
7034               res = qtdemux_seek_offset (demux, target);
7035             } else {
7036               GST_DEBUG_OBJECT (demux, "skipping seek");
7037               res = FALSE;
7038             }
7039
7040             if (res) {
7041               GST_DEBUG_OBJECT (demux, "seek success");
7042               /* remember the offset fo the first mdat so we can seek back to it
7043                * after we have the headers */
7044               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7045                 demux->first_mdat = old;
7046                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7047                     demux->first_mdat);
7048               }
7049               /* seek worked, continue reading */
7050               demux->offset = target;
7051               demux->neededbytes = 16;
7052               demux->state = QTDEMUX_STATE_INITIAL;
7053             } else {
7054               /* seek failed, need to buffer */
7055               demux->offset = old;
7056               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7057               /* there may be multiple mdat (or alike) buffers */
7058               /* sanity check */
7059               if (demux->mdatbuffer)
7060                 bs = gst_buffer_get_size (demux->mdatbuffer);
7061               else
7062                 bs = 0;
7063               if (size + bs > 10 * (1 << 20))
7064                 goto no_moov;
7065               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7066               demux->neededbytes = size;
7067               if (!demux->mdatbuffer)
7068                 demux->mdatoffset = demux->offset;
7069             }
7070           }
7071         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7072           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7073               (_("This file is invalid and cannot be played.")),
7074               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7075                   GST_FOURCC_ARGS (fourcc), size));
7076           ret = GST_FLOW_ERROR;
7077           break;
7078         } else {
7079           /* this means we already started buffering and still no moov header,
7080            * let's continue buffering everything till we get moov */
7081           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7082                   || fourcc == FOURCC_moof))
7083             goto buffer_data;
7084           demux->neededbytes = size;
7085           demux->state = QTDEMUX_STATE_HEADER;
7086         }
7087         break;
7088       }
7089       case QTDEMUX_STATE_HEADER:{
7090         const guint8 *data;
7091         guint32 fourcc;
7092
7093         GST_DEBUG_OBJECT (demux, "In header");
7094
7095         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7096
7097         /* parse the header */
7098         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7099             &fourcc);
7100         if (fourcc == FOURCC_moov) {
7101           gint n;
7102
7103           /* in usual fragmented setup we could try to scan for more
7104            * and end up at the the moov (after mdat) again */
7105           if (demux->got_moov && demux->n_streams > 0 &&
7106               (!demux->fragmented
7107                   || demux->last_moov_offset == demux->offset)) {
7108             GST_DEBUG_OBJECT (demux,
7109                 "Skipping moov atom as we have (this) one already");
7110           } else {
7111             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7112
7113             if (demux->got_moov && demux->fragmented) {
7114               GST_DEBUG_OBJECT (demux,
7115                   "Got a second moov, clean up data from old one");
7116               if (demux->moov_node_compressed) {
7117                 g_node_destroy (demux->moov_node_compressed);
7118                 if (demux->moov_node)
7119                   g_free (demux->moov_node->data);
7120               }
7121               demux->moov_node_compressed = NULL;
7122               if (demux->moov_node)
7123                 g_node_destroy (demux->moov_node);
7124               demux->moov_node = NULL;
7125             } else {
7126               /* prepare newsegment to send when streaming actually starts */
7127               if (!demux->pending_newsegment) {
7128                 demux->pending_newsegment =
7129                     gst_event_new_segment (&demux->segment);
7130                 if (demux->segment_seqnum)
7131                   gst_event_set_seqnum (demux->pending_newsegment,
7132                       demux->segment_seqnum);
7133               }
7134             }
7135
7136             demux->last_moov_offset = demux->offset;
7137
7138             qtdemux_parse_moov (demux, data, demux->neededbytes);
7139             qtdemux_node_dump (demux, demux->moov_node);
7140             qtdemux_parse_tree (demux);
7141             qtdemux_prepare_streams (demux);
7142             if (!demux->got_moov)
7143               qtdemux_expose_streams (demux);
7144             else {
7145
7146               for (n = 0; n < demux->n_streams; n++) {
7147                 QtDemuxStream *stream = demux->streams[n];
7148
7149                 gst_qtdemux_configure_stream (demux, stream);
7150               }
7151             }
7152
7153             demux->got_moov = TRUE;
7154             gst_qtdemux_check_send_pending_segment (demux);
7155
7156             /* fragmented streams headers shouldn't contain edts atoms */
7157             if (!demux->fragmented) {
7158               for (n = 0; n < demux->n_streams; n++) {
7159                 gst_qtdemux_stream_send_initial_gap_segments (demux,
7160                     demux->streams[n]);
7161               }
7162             }
7163
7164             if (demux->moov_node_compressed) {
7165               g_node_destroy (demux->moov_node_compressed);
7166               g_free (demux->moov_node->data);
7167             }
7168             demux->moov_node_compressed = NULL;
7169             g_node_destroy (demux->moov_node);
7170             demux->moov_node = NULL;
7171             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7172           }
7173         } else if (fourcc == FOURCC_moof) {
7174           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7175             guint64 dist = 0;
7176             GstClockTime prev_pts;
7177             guint64 prev_offset;
7178             guint64 adapter_discont_offset, adapter_discont_dist;
7179
7180             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7181
7182             /*
7183              * The timestamp of the moof buffer is relevant as some scenarios
7184              * won't have the initial timestamp in the atoms. Whenever a new
7185              * buffer has started, we get that buffer's PTS and use it as a base
7186              * timestamp for the trun entries.
7187              *
7188              * To keep track of the current buffer timestamp and starting point
7189              * we use gst_adapter_prev_pts that gives us the PTS and the distance
7190              * from the beggining of the buffer, with the distance and demux->offset
7191              * we know if it is still the same buffer or not.
7192              */
7193             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7194             prev_offset = demux->offset - dist;
7195             if (demux->fragment_start_offset == -1
7196                 || prev_offset > demux->fragment_start_offset) {
7197               demux->fragment_start_offset = prev_offset;
7198               demux->fragment_start = prev_pts;
7199               GST_DEBUG_OBJECT (demux,
7200                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7201                   GST_TIME_FORMAT, demux->fragment_start_offset,
7202                   GST_TIME_ARGS (demux->fragment_start));
7203             }
7204
7205             /* We can't use prev_offset() here because this would require
7206              * upstream to set consistent and correct offsets on all buffers
7207              * since the discont. Nothing ever did that in the past and we
7208              * would break backwards compatibility here then.
7209              * Instead take the offset we had at the last discont and count
7210              * the bytes from there. This works with old code as there would
7211              * be no discont between moov and moof, and also works with
7212              * adaptivedemux which correctly sets offset and will set the
7213              * DISCONT flag accordingly when needed.
7214              *
7215              * We also only do this for upstream TIME segments as otherwise
7216              * there are potential backwards compatibility problems with
7217              * seeking in PUSH mode and upstream providing inconsistent
7218              * timestamps. */
7219             adapter_discont_offset =
7220                 gst_adapter_offset_at_discont (demux->adapter);
7221             adapter_discont_dist =
7222                 gst_adapter_distance_from_discont (demux->adapter);
7223
7224             GST_DEBUG_OBJECT (demux,
7225                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7226                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7227                 demux->offset, adapter_discont_offset, adapter_discont_dist);
7228
7229             if (demux->upstream_format_is_time) {
7230               demux->moof_offset = adapter_discont_offset;
7231               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7232                 demux->moof_offset += adapter_discont_dist;
7233               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7234                 demux->moof_offset = demux->offset;
7235             } else {
7236               demux->moof_offset = demux->offset;
7237             }
7238
7239             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7240                     demux->moof_offset, NULL)) {
7241               gst_adapter_unmap (demux->adapter);
7242               ret = GST_FLOW_ERROR;
7243               goto done;
7244             }
7245             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7246             if (demux->mss_mode && !demux->exposed) {
7247               if (!demux->pending_newsegment) {
7248                 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
7249                 demux->pending_newsegment =
7250                     gst_event_new_segment (&demux->segment);
7251                 if (demux->segment_seqnum)
7252                   gst_event_set_seqnum (demux->pending_newsegment,
7253                       demux->segment_seqnum);
7254               }
7255               qtdemux_expose_streams (demux);
7256             }
7257           } else {
7258             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7259           }
7260         } else if (fourcc == FOURCC_ftyp) {
7261           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7262           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7263         } else if (fourcc == FOURCC_uuid) {
7264           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7265           qtdemux_parse_uuid (demux, data, demux->neededbytes);
7266         } else if (fourcc == FOURCC_sidx) {
7267           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7268           qtdemux_parse_sidx (demux, data, demux->neededbytes);
7269         } else {
7270           switch (fourcc) {
7271             case FOURCC_styp:
7272               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7273                * FALLTHROUGH */
7274             case FOURCC_free:
7275               /* [free] is a padding atom */
7276               GST_DEBUG_OBJECT (demux,
7277                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7278                   GST_FOURCC_ARGS (fourcc));
7279               break;
7280             default:
7281               GST_WARNING_OBJECT (demux,
7282                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7283                   GST_FOURCC_ARGS (fourcc));
7284               /* Let's jump that one and go back to initial state */
7285               break;
7286           }
7287         }
7288         gst_adapter_unmap (demux->adapter);
7289         data = NULL;
7290
7291         if (demux->mdatbuffer && demux->n_streams) {
7292           gsize remaining_data_size = 0;
7293
7294           /* the mdat was before the header */
7295           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7296               demux->n_streams, demux->mdatbuffer);
7297           /* restore our adapter/offset view of things with upstream;
7298            * put preceding buffered data ahead of current moov data.
7299            * This should also handle evil mdat, moov, mdat cases and alike */
7300           gst_adapter_flush (demux->adapter, demux->neededbytes);
7301
7302           /* Store any remaining data after the mdat for later usage */
7303           remaining_data_size = gst_adapter_available (demux->adapter);
7304           if (remaining_data_size > 0) {
7305             g_assert (demux->restoredata_buffer == NULL);
7306             demux->restoredata_buffer =
7307                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7308             demux->restoredata_offset = demux->offset + demux->neededbytes;
7309             GST_DEBUG_OBJECT (demux,
7310                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7311                 G_GUINT64_FORMAT, remaining_data_size,
7312                 demux->restoredata_offset);
7313           }
7314
7315           gst_adapter_push (demux->adapter, demux->mdatbuffer);
7316           demux->mdatbuffer = NULL;
7317           demux->offset = demux->mdatoffset;
7318           demux->neededbytes = next_entry_size (demux);
7319           demux->state = QTDEMUX_STATE_MOVIE;
7320           demux->mdatleft = gst_adapter_available (demux->adapter);
7321           demux->mdatsize = demux->mdatleft;
7322         } else {
7323           GST_DEBUG_OBJECT (demux, "Carrying on normally");
7324           gst_adapter_flush (demux->adapter, demux->neededbytes);
7325
7326           /* only go back to the mdat if there are samples to play */
7327           if (demux->got_moov && demux->first_mdat != -1
7328               && has_next_entry (demux)) {
7329             gboolean res;
7330
7331             /* we need to seek back */
7332             res = qtdemux_seek_offset (demux, demux->first_mdat);
7333             if (res) {
7334               demux->offset = demux->first_mdat;
7335             } else {
7336               GST_DEBUG_OBJECT (demux, "Seek back failed");
7337             }
7338           } else {
7339             demux->offset += demux->neededbytes;
7340           }
7341           demux->neededbytes = 16;
7342           demux->state = QTDEMUX_STATE_INITIAL;
7343         }
7344
7345         break;
7346       }
7347       case QTDEMUX_STATE_BUFFER_MDAT:{
7348         GstBuffer *buf;
7349         guint8 fourcc[4];
7350
7351         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7352             demux->offset);
7353         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7354         gst_buffer_extract (buf, 0, fourcc, 4);
7355         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7356             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7357         if (demux->mdatbuffer)
7358           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7359         else
7360           demux->mdatbuffer = buf;
7361         demux->offset += demux->neededbytes;
7362         demux->neededbytes = 16;
7363         demux->state = QTDEMUX_STATE_INITIAL;
7364         gst_qtdemux_post_progress (demux, 1, 1);
7365
7366         break;
7367       }
7368       case QTDEMUX_STATE_MOVIE:{
7369         QtDemuxStream *stream = NULL;
7370         QtDemuxSample *sample;
7371         int i = -1;
7372         GstClockTime dts, pts, duration;
7373         gboolean keyframe;
7374
7375         GST_DEBUG_OBJECT (demux,
7376             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7377
7378         if (demux->fragmented) {
7379           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7380               demux->mdatleft);
7381           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7382             /* if needed data starts within this atom,
7383              * then it should not exceed this atom */
7384             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7385               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7386                   (_("This file is invalid and cannot be played.")),
7387                   ("sample data crosses atom boundary"));
7388               ret = GST_FLOW_ERROR;
7389               break;
7390             }
7391             demux->mdatleft -= demux->neededbytes;
7392           } else {
7393             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7394             /* so we are dropping more than left in this atom */
7395             gst_qtdemux_drop_data (demux, demux->mdatleft);
7396             demux->mdatleft = 0;
7397
7398             /* need to resume atom parsing so we do not miss any other pieces */
7399             demux->state = QTDEMUX_STATE_INITIAL;
7400             demux->neededbytes = 16;
7401
7402             /* check if there was any stored post mdat data from previous buffers */
7403             if (demux->restoredata_buffer) {
7404               g_assert (gst_adapter_available (demux->adapter) == 0);
7405
7406               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7407               demux->restoredata_buffer = NULL;
7408               demux->offset = demux->restoredata_offset;
7409             }
7410
7411             break;
7412           }
7413         }
7414
7415         if (demux->todrop) {
7416           if (demux->cenc_aux_info_offset > 0) {
7417             GstByteReader br;
7418             const guint8 *data;
7419
7420             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7421             data = gst_adapter_map (demux->adapter, demux->todrop);
7422             gst_byte_reader_init (&br, data + 8, demux->todrop);
7423             if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
7424                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7425               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7426               ret = GST_FLOW_ERROR;
7427               gst_adapter_unmap (demux->adapter);
7428               g_free (demux->cenc_aux_info_sizes);
7429               demux->cenc_aux_info_sizes = NULL;
7430               goto done;
7431             }
7432             demux->cenc_aux_info_offset = 0;
7433             g_free (demux->cenc_aux_info_sizes);
7434             demux->cenc_aux_info_sizes = NULL;
7435             gst_adapter_unmap (demux->adapter);
7436           }
7437           gst_qtdemux_drop_data (demux, demux->todrop);
7438         }
7439
7440         /* first buffer? */
7441         /* initial newsegment sent here after having added pads,
7442          * possible others in sink_event */
7443         gst_qtdemux_check_send_pending_segment (demux);
7444
7445         /* Figure out which stream this packet belongs to */
7446         for (i = 0; i < demux->n_streams; i++) {
7447           stream = demux->streams[i];
7448           if (stream->sample_index >= stream->n_samples)
7449             continue;
7450           GST_LOG_OBJECT (demux,
7451               "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
7452               " / size:%d)", i, stream->sample_index,
7453               stream->samples[stream->sample_index].offset,
7454               stream->samples[stream->sample_index].size);
7455
7456           if (stream->samples[stream->sample_index].offset == demux->offset)
7457             break;
7458         }
7459
7460         if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
7461           goto unknown_stream;
7462
7463         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7464
7465         if (stream->new_caps) {
7466           gst_qtdemux_configure_stream (demux, stream);
7467         }
7468
7469         /* Put data in a buffer, set timestamps, caps, ... */
7470         sample = &stream->samples[stream->sample_index];
7471
7472         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7473           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7474               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7475
7476           dts = QTSAMPLE_DTS (stream, sample);
7477           pts = QTSAMPLE_PTS (stream, sample);
7478           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7479           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7480
7481           /* check for segment end */
7482           if (G_UNLIKELY (demux->segment.stop != -1
7483                   && demux->segment.stop <= pts && stream->on_keyframe)) {
7484             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7485             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
7486
7487             /* skip this data, stream is EOS */
7488             gst_adapter_flush (demux->adapter, demux->neededbytes);
7489             demux->offset += demux->neededbytes;
7490
7491             /* check if all streams are eos */
7492             ret = GST_FLOW_EOS;
7493             for (i = 0; i < demux->n_streams; i++) {
7494               if (!STREAM_IS_EOS (demux->streams[i])) {
7495                 ret = GST_FLOW_OK;
7496                 break;
7497               }
7498             }
7499           } else {
7500             GstBuffer *outbuf;
7501
7502             outbuf =
7503                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7504
7505             /* FIXME: should either be an assert or a plain check */
7506             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7507
7508             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7509                 dts, pts, duration, keyframe, dts, demux->offset);
7510           }
7511
7512           /* combine flows */
7513           ret = gst_qtdemux_combine_flows (demux, stream, ret);
7514         } else {
7515           /* skip this data, stream is EOS */
7516           gst_adapter_flush (demux->adapter, demux->neededbytes);
7517         }
7518
7519         stream->sample_index++;
7520         stream->offset_in_sample = 0;
7521
7522         /* update current offset and figure out size of next buffer */
7523         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7524             demux->offset, demux->neededbytes);
7525         demux->offset += demux->neededbytes;
7526         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7527             demux->offset);
7528
7529
7530         if (ret == GST_FLOW_EOS) {
7531           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7532           demux->neededbytes = -1;
7533           goto eos;
7534         }
7535
7536         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7537           if (demux->fragmented) {
7538             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7539             /* there may be more to follow, only finish this atom */
7540             demux->todrop = demux->mdatleft;
7541             demux->neededbytes = demux->todrop;
7542             break;
7543           }
7544           goto eos;
7545         }
7546         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7547           goto non_ok_unlinked_flow;
7548         }
7549         break;
7550       }
7551       default:
7552         goto invalid_state;
7553     }
7554   }
7555
7556   /* when buffering movie data, at least show user something is happening */
7557   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7558       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7559     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7560         demux->neededbytes);
7561   }
7562 done:
7563
7564   return ret;
7565
7566   /* ERRORS */
7567 non_ok_unlinked_flow:
7568   {
7569     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7570         gst_flow_get_name (ret));
7571     return ret;
7572   }
7573 unknown_stream:
7574   {
7575     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7576     ret = GST_FLOW_ERROR;
7577     goto done;
7578   }
7579 eos:
7580   {
7581     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7582     ret = GST_FLOW_EOS;
7583     goto done;
7584   }
7585 invalid_state:
7586   {
7587     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7588         (NULL), ("qtdemuxer invalid state %d", demux->state));
7589     ret = GST_FLOW_ERROR;
7590     goto done;
7591   }
7592 no_moov:
7593   {
7594     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7595         (NULL), ("no 'moov' atom within the first 10 MB"));
7596     ret = GST_FLOW_ERROR;
7597     goto done;
7598   }
7599 }
7600
7601 static gboolean
7602 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7603 {
7604   GstQuery *query;
7605   gboolean pull_mode;
7606
7607   query = gst_query_new_scheduling ();
7608
7609   if (!gst_pad_peer_query (sinkpad, query)) {
7610     gst_query_unref (query);
7611     goto activate_push;
7612   }
7613
7614   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7615       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7616   gst_query_unref (query);
7617
7618   if (!pull_mode)
7619     goto activate_push;
7620
7621   GST_DEBUG_OBJECT (sinkpad, "activating pull");
7622   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7623
7624 activate_push:
7625   {
7626     GST_DEBUG_OBJECT (sinkpad, "activating push");
7627     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7628   }
7629 }
7630
7631 static gboolean
7632 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7633     GstPadMode mode, gboolean active)
7634 {
7635   gboolean res;
7636   GstQTDemux *demux = GST_QTDEMUX (parent);
7637
7638   switch (mode) {
7639     case GST_PAD_MODE_PUSH:
7640       demux->pullbased = FALSE;
7641       res = TRUE;
7642       break;
7643     case GST_PAD_MODE_PULL:
7644       if (active) {
7645         demux->pullbased = TRUE;
7646         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7647             sinkpad, NULL);
7648       } else {
7649         res = gst_pad_stop_task (sinkpad);
7650       }
7651       break;
7652     default:
7653       res = FALSE;
7654       break;
7655   }
7656   return res;
7657 }
7658
7659 #ifdef HAVE_ZLIB
7660 static void *
7661 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7662 {
7663   guint8 *buffer;
7664   z_stream z;
7665   int ret;
7666
7667   memset (&z, 0, sizeof (z));
7668   z.zalloc = NULL;
7669   z.zfree = NULL;
7670   z.opaque = NULL;
7671
7672   if ((ret = inflateInit (&z)) != Z_OK) {
7673     GST_ERROR ("inflateInit() returned %d", ret);
7674     return NULL;
7675   }
7676
7677   z.next_in = z_buffer;
7678   z.avail_in = z_length;
7679
7680   buffer = (guint8 *) g_malloc (*length);
7681   z.avail_out = *length;
7682   z.next_out = (Bytef *) buffer;
7683   do {
7684     ret = inflate (&z, Z_NO_FLUSH);
7685     if (ret == Z_STREAM_END) {
7686       break;
7687     } else if (ret != Z_OK) {
7688       GST_WARNING ("inflate() returned %d", ret);
7689       break;
7690     }
7691
7692     *length += 4096;
7693     buffer = (guint8 *) g_realloc (buffer, *length);
7694     z.next_out = (Bytef *) (buffer + z.total_out);
7695     z.avail_out += 4096;
7696   } while (z.avail_in > 0);
7697
7698   if (ret != Z_STREAM_END) {
7699     g_free (buffer);
7700     buffer = NULL;
7701     *length = 0;
7702   } else {
7703     *length = z.total_out;
7704   }
7705
7706   inflateEnd (&z);
7707
7708   return buffer;
7709 }
7710 #endif /* HAVE_ZLIB */
7711
7712 static gboolean
7713 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7714 {
7715   GNode *cmov;
7716
7717   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7718
7719   /* counts as header data */
7720   qtdemux->header_size += length;
7721
7722   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7723   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7724
7725   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7726   if (cmov) {
7727     guint32 method;
7728     GNode *dcom;
7729     GNode *cmvd;
7730     guint32 dcom_len;
7731
7732     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7733     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7734     if (dcom == NULL || cmvd == NULL)
7735       goto invalid_compression;
7736
7737     dcom_len = QT_UINT32 (dcom->data);
7738     if (dcom_len < 12)
7739       goto invalid_compression;
7740
7741     method = QT_FOURCC ((guint8 *) dcom->data + 8);
7742     switch (method) {
7743 #ifdef HAVE_ZLIB
7744       case FOURCC_zlib:{
7745         guint uncompressed_length;
7746         guint compressed_length;
7747         guint8 *buf;
7748         guint32 cmvd_len;
7749
7750         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7751         if (cmvd_len < 12)
7752           goto invalid_compression;
7753
7754         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7755         compressed_length = cmvd_len - 12;
7756         GST_LOG ("length = %u", uncompressed_length);
7757
7758         buf =
7759             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7760             compressed_length, &uncompressed_length);
7761
7762         if (buf) {
7763           qtdemux->moov_node_compressed = qtdemux->moov_node;
7764           qtdemux->moov_node = g_node_new (buf);
7765
7766           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7767               uncompressed_length);
7768         }
7769         break;
7770       }
7771 #endif /* HAVE_ZLIB */
7772       default:
7773         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7774             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7775         break;
7776     }
7777   }
7778   return TRUE;
7779
7780   /* ERRORS */
7781 invalid_compression:
7782   {
7783     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7784     return FALSE;
7785   }
7786 }
7787
7788 static gboolean
7789 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7790     const guint8 * end)
7791 {
7792   while (G_UNLIKELY (buf < end)) {
7793     GNode *child;
7794     guint32 len;
7795
7796     if (G_UNLIKELY (buf + 4 > end)) {
7797       GST_LOG_OBJECT (qtdemux, "buffer overrun");
7798       break;
7799     }
7800     len = QT_UINT32 (buf);
7801     if (G_UNLIKELY (len == 0)) {
7802       GST_LOG_OBJECT (qtdemux, "empty container");
7803       break;
7804     }
7805     if (G_UNLIKELY (len < 8)) {
7806       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7807       break;
7808     }
7809     if (G_UNLIKELY (len > (end - buf))) {
7810       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7811           (gint) (end - buf));
7812       break;
7813     }
7814
7815     child = g_node_new ((guint8 *) buf);
7816     g_node_append (node, child);
7817     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7818     qtdemux_parse_node (qtdemux, child, buf, len);
7819
7820     buf += len;
7821   }
7822   return TRUE;
7823 }
7824
7825 static gboolean
7826 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7827     GNode * xdxt)
7828 {
7829   int len = QT_UINT32 (xdxt->data);
7830   guint8 *buf = xdxt->data;
7831   guint8 *end = buf + len;
7832   GstBuffer *buffer;
7833
7834   /* skip size and type */
7835   buf += 8;
7836   end -= 8;
7837
7838   while (buf < end) {
7839     gint size;
7840     guint32 type;
7841
7842     size = QT_UINT32 (buf);
7843     type = QT_FOURCC (buf + 4);
7844
7845     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7846
7847     if (buf + size > end || size <= 0)
7848       break;
7849
7850     buf += 8;
7851     size -= 8;
7852
7853     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7854         GST_FOURCC_ARGS (type));
7855
7856     switch (type) {
7857       case FOURCC_tCtH:
7858         buffer = gst_buffer_new_and_alloc (size);
7859         gst_buffer_fill (buffer, 0, buf, size);
7860         stream->buffers = g_slist_append (stream->buffers, buffer);
7861         GST_LOG_OBJECT (qtdemux, "parsing theora header");
7862         break;
7863       case FOURCC_tCt_:
7864         buffer = gst_buffer_new_and_alloc (size);
7865         gst_buffer_fill (buffer, 0, buf, size);
7866         stream->buffers = g_slist_append (stream->buffers, buffer);
7867         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7868         break;
7869       case FOURCC_tCtC:
7870         buffer = gst_buffer_new_and_alloc (size);
7871         gst_buffer_fill (buffer, 0, buf, size);
7872         stream->buffers = g_slist_append (stream->buffers, buffer);
7873         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7874         break;
7875       default:
7876         GST_WARNING_OBJECT (qtdemux,
7877             "unknown theora cookie %" GST_FOURCC_FORMAT,
7878             GST_FOURCC_ARGS (type));
7879         break;
7880     }
7881     buf += size;
7882   }
7883   return TRUE;
7884 }
7885
7886 static gboolean
7887 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7888     guint length)
7889 {
7890   guint32 fourcc = 0;
7891   guint32 node_length = 0;
7892   const QtNodeType *type;
7893   const guint8 *end;
7894
7895   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7896
7897   if (G_UNLIKELY (length < 8))
7898     goto not_enough_data;
7899
7900   node_length = QT_UINT32 (buffer);
7901   fourcc = QT_FOURCC (buffer + 4);
7902
7903   /* ignore empty nodes */
7904   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7905     return TRUE;
7906
7907   type = qtdemux_type_get (fourcc);
7908
7909   end = buffer + length;
7910
7911   GST_LOG_OBJECT (qtdemux,
7912       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7913       GST_FOURCC_ARGS (fourcc), node_length, type->name);
7914
7915   if (node_length > length)
7916     goto broken_atom_size;
7917
7918   if (type->flags & QT_FLAG_CONTAINER) {
7919     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7920   } else {
7921     switch (fourcc) {
7922       case FOURCC_stsd:
7923       {
7924         if (node_length < 20) {
7925           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7926           break;
7927         }
7928         GST_DEBUG_OBJECT (qtdemux,
7929             "parsing stsd (sample table, sample description) atom");
7930         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7931         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7932         break;
7933       }
7934       case FOURCC_mp4a:
7935       case FOURCC_alac:
7936       case FOURCC_fLaC:
7937       {
7938         guint32 version;
7939         guint32 offset;
7940         guint min_size;
7941
7942         /* also read alac (or whatever) in stead of mp4a in the following,
7943          * since a similar layout is used in other cases as well */
7944         if (fourcc == FOURCC_mp4a)
7945           min_size = 20;
7946         else if (fourcc == FOURCC_fLaC)
7947           min_size = 86;
7948         else
7949           min_size = 40;
7950
7951         /* There are two things we might encounter here: a true mp4a atom, and
7952            an mp4a entry in an stsd atom. The latter is what we're interested
7953            in, and it looks like an atom, but isn't really one. The true mp4a
7954            atom is short, so we detect it based on length here. */
7955         if (length < min_size) {
7956           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7957               GST_FOURCC_ARGS (fourcc));
7958           break;
7959         }
7960
7961         /* 'version' here is the sound sample description version. Types 0 and
7962            1 are documented in the QTFF reference, but type 2 is not: it's
7963            described in Apple header files instead (struct SoundDescriptionV2
7964            in Movies.h) */
7965         version = QT_UINT16 (buffer + 16);
7966
7967         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7968             GST_FOURCC_ARGS (fourcc), version);
7969
7970         /* parse any esds descriptors */
7971         switch (version) {
7972           case 0:
7973             offset = 0x24;
7974             break;
7975           case 1:
7976             offset = 0x34;
7977             break;
7978           case 2:
7979             offset = 0x48;
7980             break;
7981           default:
7982             GST_WARNING_OBJECT (qtdemux,
7983                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7984                 GST_FOURCC_ARGS (fourcc), version);
7985             offset = 0;
7986             break;
7987         }
7988         if (offset)
7989           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7990         break;
7991       }
7992       case FOURCC_mp4v:
7993       case FOURCC_MP4V:
7994       case FOURCC_fmp4:
7995       case FOURCC_FMP4:
7996       case FOURCC_apcs:
7997       case FOURCC_apch:
7998       case FOURCC_apcn:
7999       case FOURCC_apco:
8000       case FOURCC_ap4h:
8001       case FOURCC_xvid:
8002       case FOURCC_XVID:
8003       case FOURCC_H264:
8004       case FOURCC_avc1:
8005       case FOURCC_avc3:
8006       case FOURCC_H265:
8007       case FOURCC_hvc1:
8008       case FOURCC_hev1:
8009       case FOURCC_mjp2:
8010       case FOURCC_encv:
8011       {
8012         guint32 version;
8013         guint32 str_len;
8014
8015         /* codec_data is contained inside these atoms, which all have
8016          * the same format. */
8017         /* video sample description size is 86 bytes without extension.
8018          * node_length have to be bigger than 86 bytes because video sample
8019          * description can include extenstions such as esds, fiel, glbl, etc. */
8020         if (node_length < 86) {
8021           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8022               " sample description length too short (%u < 86)",
8023               GST_FOURCC_ARGS (fourcc), node_length);
8024           break;
8025         }
8026
8027         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8028             GST_FOURCC_ARGS (fourcc));
8029
8030         /* version (2 bytes) : this is set to 0, unless a compressor has changed
8031          *              its data format.
8032          * revision level (2 bytes) : must be set to 0. */
8033         version = QT_UINT32 (buffer + 16);
8034         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8035
8036         /* compressor name : PASCAL string and informative purposes
8037          * first byte : the number of bytes to be displayed.
8038          *              it has to be less than 32 because it is reserved
8039          *              space of 32 bytes total including itself. */
8040         str_len = QT_UINT8 (buffer + 50);
8041         if (str_len < 32)
8042           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8043               (char *) buffer + 51);
8044         else
8045           GST_WARNING_OBJECT (qtdemux,
8046               "compressorname length too big (%u > 31)", str_len);
8047
8048         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8049             end - buffer);
8050         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8051         break;
8052       }
8053       case FOURCC_meta:
8054       {
8055         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8056         qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8057         break;
8058       }
8059       case FOURCC_mp4s:
8060       {
8061         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8062         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8063         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8064         break;
8065       }
8066       case FOURCC_XiTh:
8067       {
8068         guint32 version;
8069         guint32 offset;
8070
8071         if (length < 16) {
8072           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8073               GST_FOURCC_ARGS (fourcc));
8074           break;
8075         }
8076
8077         version = QT_UINT32 (buffer + 12);
8078         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8079
8080         switch (version) {
8081           case 0x00000001:
8082             offset = 0x62;
8083             break;
8084           default:
8085             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8086             offset = 0;
8087             break;
8088         }
8089         if (offset) {
8090           if (length < offset) {
8091             GST_WARNING_OBJECT (qtdemux,
8092                 "skipping too small %" GST_FOURCC_FORMAT " box",
8093                 GST_FOURCC_ARGS (fourcc));
8094             break;
8095           }
8096           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8097         }
8098         break;
8099       }
8100       case FOURCC_in24:
8101       {
8102         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8103         break;
8104       }
8105       case FOURCC_uuid:
8106       {
8107         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8108         break;
8109       }
8110       case FOURCC_enca:
8111       {
8112         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8113         break;
8114       }
8115 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
8116       case FOURCC_SA3D:
8117       {
8118         qtdemux_parse_SA3D (qtdemux, buffer, end - buffer);
8119         break;
8120       }
8121 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
8122       default:
8123         if (!strcmp (type->name, "unknown"))
8124           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8125         break;
8126     }
8127   }
8128   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8129       GST_FOURCC_ARGS (fourcc));
8130   return TRUE;
8131
8132 /* ERRORS */
8133 not_enough_data:
8134   {
8135     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8136         (_("This file is corrupt and cannot be played.")),
8137         ("Not enough data for an atom header, got only %u bytes", length));
8138     return FALSE;
8139   }
8140 broken_atom_size:
8141   {
8142     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8143         (_("This file is corrupt and cannot be played.")),
8144         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8145             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8146             length));
8147     return FALSE;
8148   }
8149 }
8150
8151 static GNode *
8152 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
8153 {
8154   GNode *child;
8155   guint8 *buffer;
8156   guint32 child_fourcc;
8157
8158   for (child = g_node_first_child (node); child;
8159       child = g_node_next_sibling (child)) {
8160     buffer = (guint8 *) child->data;
8161
8162     child_fourcc = QT_FOURCC (buffer + 4);
8163
8164     if (G_UNLIKELY (child_fourcc == fourcc)) {
8165       return child;
8166     }
8167   }
8168   return NULL;
8169 }
8170
8171 static GNode *
8172 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
8173     GstByteReader * parser)
8174 {
8175   GNode *child;
8176   guint8 *buffer;
8177   guint32 child_fourcc, child_len;
8178
8179   for (child = g_node_first_child (node); child;
8180       child = g_node_next_sibling (child)) {
8181     buffer = (guint8 *) child->data;
8182
8183     child_len = QT_UINT32 (buffer);
8184     child_fourcc = QT_FOURCC (buffer + 4);
8185
8186     if (G_UNLIKELY (child_fourcc == fourcc)) {
8187       if (G_UNLIKELY (child_len < (4 + 4)))
8188         return NULL;
8189       /* FIXME: must verify if atom length < parent atom length */
8190       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8191       return child;
8192     }
8193   }
8194   return NULL;
8195 }
8196
8197 static GNode *
8198 qtdemux_tree_get_child_by_index (GNode * node, guint index)
8199 {
8200   return g_node_nth_child (node, index);
8201 }
8202
8203 static GNode *
8204 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
8205     GstByteReader * parser)
8206 {
8207   GNode *child;
8208   guint8 *buffer;
8209   guint32 child_fourcc, child_len;
8210
8211   for (child = g_node_next_sibling (node); child;
8212       child = g_node_next_sibling (child)) {
8213     buffer = (guint8 *) child->data;
8214
8215     child_fourcc = QT_FOURCC (buffer + 4);
8216
8217     if (child_fourcc == fourcc) {
8218       if (parser) {
8219         child_len = QT_UINT32 (buffer);
8220         if (G_UNLIKELY (child_len < (4 + 4)))
8221           return NULL;
8222         /* FIXME: must verify if atom length < parent atom length */
8223         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8224       }
8225       return child;
8226     }
8227   }
8228   return NULL;
8229 }
8230
8231 static GNode *
8232 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8233 {
8234   return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8235 }
8236
8237 static void
8238 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
8239 {
8240 /* FIXME: This can only reliably work if demuxers have a
8241  * separate streaming thread per srcpad. This should be
8242  * done in a demuxer base class, which integrates parts
8243  * of multiqueue
8244  *
8245  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8246  */
8247 #if 0
8248   GstQuery *query;
8249
8250   query = gst_query_new_allocation (stream->caps, FALSE);
8251
8252   if (!gst_pad_peer_query (stream->pad, query)) {
8253     /* not a problem, just debug a little */
8254     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8255   }
8256
8257   if (stream->allocator)
8258     gst_object_unref (stream->allocator);
8259
8260   if (gst_query_get_n_allocation_params (query) > 0) {
8261     /* try the allocator */
8262     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8263         &stream->params);
8264     stream->use_allocator = TRUE;
8265   } else {
8266     stream->allocator = NULL;
8267     gst_allocation_params_init (&stream->params);
8268     stream->use_allocator = FALSE;
8269   }
8270   gst_query_unref (query);
8271 #endif
8272 }
8273
8274 static gboolean
8275 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8276     QtDemuxStream * stream)
8277 {
8278   GstStructure *s;
8279   const gchar *selected_system;
8280
8281   g_return_val_if_fail (qtdemux != NULL, FALSE);
8282   g_return_val_if_fail (stream != NULL, FALSE);
8283   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8284       FALSE);
8285
8286   if (stream->protection_scheme_type != FOURCC_cenc) {
8287     GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
8288     return FALSE;
8289   }
8290   if (qtdemux->protection_system_ids == NULL) {
8291     GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8292         "cenc protection system information has been found");
8293     return FALSE;
8294   }
8295   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8296   selected_system = gst_protection_select_system ((const gchar **)
8297       qtdemux->protection_system_ids->pdata);
8298   g_ptr_array_remove_index (qtdemux->protection_system_ids,
8299       qtdemux->protection_system_ids->len - 1);
8300   if (!selected_system) {
8301     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8302         "suitable decryptor element has been found");
8303     return FALSE;
8304   }
8305
8306   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8307   if (!gst_structure_has_name (s, "application/x-cenc")) {
8308     gst_structure_set (s,
8309         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8310         GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8311         NULL);
8312     gst_structure_set_name (s, "application/x-cenc");
8313   }
8314   return TRUE;
8315 }
8316
8317 static gboolean
8318 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8319 {
8320   if (stream->subtype == FOURCC_vide) {
8321     /* fps is calculated base on the duration of the average framerate since
8322      * qt does not have a fixed framerate. */
8323     gboolean fps_available = TRUE;
8324
8325     if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
8326       /* still frame */
8327       CUR_STREAM (stream)->fps_n = 0;
8328       CUR_STREAM (stream)->fps_d = 1;
8329     } else {
8330       if (stream->duration == 0 || stream->n_samples < 2) {
8331         CUR_STREAM (stream)->fps_n = stream->timescale;
8332         CUR_STREAM (stream)->fps_d = 1;
8333         fps_available = FALSE;
8334       } else {
8335         GstClockTime avg_duration;
8336         guint64 duration;
8337         guint32 n_samples;
8338
8339         /* duration and n_samples can be updated for fragmented format
8340          * so, framerate of fragmented format is calculated using data in a moof */
8341         if (qtdemux->fragmented && stream->n_samples_moof > 0
8342             && stream->duration_moof > 0) {
8343           n_samples = stream->n_samples_moof;
8344           duration = stream->duration_moof;
8345         } else {
8346           n_samples = stream->n_samples;
8347           duration = stream->duration;
8348         }
8349
8350         /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8351         /* stream->duration is guint64, timescale, n_samples are guint32 */
8352         avg_duration =
8353             gst_util_uint64_scale_round (duration -
8354             stream->first_duration, GST_SECOND,
8355             (guint64) (stream->timescale) * (n_samples - 1));
8356
8357         GST_LOG_OBJECT (qtdemux,
8358             "Calculating avg sample duration based on stream (or moof) duration %"
8359             G_GUINT64_FORMAT
8360             " minus first sample %u, leaving %d samples gives %"
8361             GST_TIME_FORMAT, duration, stream->first_duration,
8362             n_samples - 1, GST_TIME_ARGS (avg_duration));
8363
8364         gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8365             &CUR_STREAM (stream)->fps_d);
8366
8367         GST_DEBUG_OBJECT (qtdemux,
8368             "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8369             stream->timescale, CUR_STREAM (stream)->fps_n,
8370             CUR_STREAM (stream)->fps_d);
8371       }
8372     }
8373
8374     if (CUR_STREAM (stream)->caps) {
8375       CUR_STREAM (stream)->caps =
8376           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8377
8378       gst_caps_set_simple (CUR_STREAM (stream)->caps,
8379           "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8380           "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8381
8382       /* set framerate if calculated framerate is reliable */
8383       if (fps_available) {
8384         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8385             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8386             CUR_STREAM (stream)->fps_d, NULL);
8387       }
8388
8389       /* calculate pixel-aspect-ratio using display width and height */
8390       GST_DEBUG_OBJECT (qtdemux,
8391           "video size %dx%d, target display size %dx%d",
8392           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8393           stream->display_width, stream->display_height);
8394       /* qt file might have pasp atom */
8395       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8396         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8397             CUR_STREAM (stream)->par_h);
8398         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8399             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8400             CUR_STREAM (stream)->par_h, NULL);
8401       } else if (stream->display_width > 0 && stream->display_height > 0
8402           && CUR_STREAM (stream)->width > 0
8403           && CUR_STREAM (stream)->height > 0) {
8404         gint n, d;
8405
8406         /* calculate the pixel aspect ratio using the display and pixel w/h */
8407         n = stream->display_width * CUR_STREAM (stream)->height;
8408         d = stream->display_height * CUR_STREAM (stream)->width;
8409         if (n == d)
8410           n = d = 1;
8411         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8412         CUR_STREAM (stream)->par_w = n;
8413         CUR_STREAM (stream)->par_h = d;
8414         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8415             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8416             CUR_STREAM (stream)->par_h, NULL);
8417       }
8418
8419       if (CUR_STREAM (stream)->interlace_mode > 0) {
8420         if (CUR_STREAM (stream)->interlace_mode == 1) {
8421           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8422               G_TYPE_STRING, "progressive", NULL);
8423         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8424           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8425               G_TYPE_STRING, "interleaved", NULL);
8426           if (CUR_STREAM (stream)->field_order == 9) {
8427             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8428                 G_TYPE_STRING, "top-field-first", NULL);
8429           } else if (CUR_STREAM (stream)->field_order == 14) {
8430             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8431                 G_TYPE_STRING, "bottom-field-first", NULL);
8432           }
8433         }
8434       }
8435
8436       /* Create incomplete colorimetry here if needed */
8437       if (CUR_STREAM (stream)->colorimetry.range ||
8438           CUR_STREAM (stream)->colorimetry.matrix ||
8439           CUR_STREAM (stream)->colorimetry.transfer
8440           || CUR_STREAM (stream)->colorimetry.primaries) {
8441         gchar *colorimetry =
8442             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8443         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8444             G_TYPE_STRING, colorimetry, NULL);
8445         g_free (colorimetry);
8446       }
8447
8448       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8449         guint par_w = 1, par_h = 1;
8450
8451         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8452           par_w = CUR_STREAM (stream)->par_w;
8453           par_h = CUR_STREAM (stream)->par_h;
8454         }
8455
8456         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8457                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8458                 par_h)) {
8459           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8460         }
8461
8462         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8463             "multiview-mode", G_TYPE_STRING,
8464             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8465             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8466             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8467       }
8468     }
8469   }
8470
8471   else if (stream->subtype == FOURCC_soun) {
8472     if (CUR_STREAM (stream)->caps) {
8473       CUR_STREAM (stream)->caps =
8474           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8475       if (CUR_STREAM (stream)->rate > 0)
8476         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8477             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8478       if (CUR_STREAM (stream)->n_channels > 0)
8479         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8480             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8481       if (CUR_STREAM (stream)->n_channels > 2) {
8482         /* FIXME: Need to parse the 'chan' atom to get channel layouts
8483          * correctly; this is just the minimum we can do - assume
8484          * we don't actually have any channel positions. */
8485         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8486             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8487       }
8488     }
8489   }
8490
8491   if (stream->pad) {
8492     GstCaps *prev_caps = NULL;
8493
8494     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8495     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8496     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8497     gst_pad_set_active (stream->pad, TRUE);
8498
8499     gst_pad_use_fixed_caps (stream->pad);
8500
8501     if (stream->protected) {
8502       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8503         GST_ERROR_OBJECT (qtdemux,
8504             "Failed to configure protected stream caps.");
8505         return FALSE;
8506       }
8507     }
8508
8509     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8510         CUR_STREAM (stream)->caps);
8511     if (stream->new_stream) {
8512       gchar *stream_id;
8513       GstEvent *event;
8514       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8515
8516       event =
8517           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8518           0);
8519       if (event) {
8520         gst_event_parse_stream_flags (event, &stream_flags);
8521         if (gst_event_parse_group_id (event, &qtdemux->group_id))
8522           qtdemux->have_group_id = TRUE;
8523         else
8524           qtdemux->have_group_id = FALSE;
8525         gst_event_unref (event);
8526       } else if (!qtdemux->have_group_id) {
8527         qtdemux->have_group_id = TRUE;
8528         qtdemux->group_id = gst_util_group_id_next ();
8529       }
8530
8531       stream->new_stream = FALSE;
8532       stream_id =
8533           gst_pad_create_stream_id_printf (stream->pad,
8534           GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
8535       event = gst_event_new_stream_start (stream_id);
8536       if (qtdemux->have_group_id)
8537         gst_event_set_group_id (event, qtdemux->group_id);
8538       if (stream->disabled)
8539         stream_flags |= GST_STREAM_FLAG_UNSELECT;
8540       if (CUR_STREAM (stream)->sparse) {
8541         stream_flags |= GST_STREAM_FLAG_SPARSE;
8542       } else {
8543         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8544       }
8545       gst_event_set_stream_flags (event, stream_flags);
8546       gst_pad_push_event (stream->pad, event);
8547       g_free (stream_id);
8548     }
8549
8550     prev_caps = gst_pad_get_current_caps (stream->pad);
8551
8552     if (CUR_STREAM (stream)->caps) {
8553       if (!prev_caps
8554           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8555         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8556             CUR_STREAM (stream)->caps);
8557         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8558       } else {
8559         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8560       }
8561     } else {
8562       GST_WARNING_OBJECT (qtdemux, "stream without caps");
8563     }
8564
8565     if (prev_caps)
8566       gst_caps_unref (prev_caps);
8567     stream->new_caps = FALSE;
8568   }
8569   return TRUE;
8570 }
8571
8572 static void
8573 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8574     QtDemuxStream * stream)
8575 {
8576   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8577     return;
8578
8579   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8580       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8581   if (G_UNLIKELY (stream->stsd_sample_description_id >=
8582           stream->stsd_entries_length)) {
8583     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8584         (_("This file is invalid and cannot be played.")),
8585         ("New sample description id is out of bounds (%d >= %d)",
8586             stream->stsd_sample_description_id, stream->stsd_entries_length));
8587   } else {
8588     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8589     stream->new_caps = TRUE;
8590   }
8591 }
8592
8593 static gboolean
8594 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8595     QtDemuxStream * stream, GstTagList * list)
8596 {
8597   gboolean ret = TRUE;
8598   /* consistent default for push based mode */
8599   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8600
8601   if (stream->subtype == FOURCC_vide) {
8602     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8603
8604     stream->pad =
8605         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8606     g_free (name);
8607
8608     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8609       gst_object_unref (stream->pad);
8610       stream->pad = NULL;
8611       ret = FALSE;
8612       goto done;
8613     }
8614
8615     qtdemux->n_video_streams++;
8616   } else if (stream->subtype == FOURCC_soun) {
8617     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8618
8619     stream->pad =
8620         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8621     g_free (name);
8622     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8623       gst_object_unref (stream->pad);
8624       stream->pad = NULL;
8625       ret = FALSE;
8626       goto done;
8627     }
8628     qtdemux->n_audio_streams++;
8629   } else if (stream->subtype == FOURCC_strm) {
8630     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8631   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8632       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8633     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8634
8635     stream->pad =
8636         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8637     g_free (name);
8638     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8639       gst_object_unref (stream->pad);
8640       stream->pad = NULL;
8641       ret = FALSE;
8642       goto done;
8643     }
8644     qtdemux->n_sub_streams++;
8645   } else if (CUR_STREAM (stream)->caps) {
8646     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8647
8648     stream->pad =
8649         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8650     g_free (name);
8651     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8652       gst_object_unref (stream->pad);
8653       stream->pad = NULL;
8654       ret = FALSE;
8655       goto done;
8656     }
8657     qtdemux->n_video_streams++;
8658   } else {
8659     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8660     goto done;
8661   }
8662
8663   if (stream->pad) {
8664     GList *l;
8665
8666     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8667         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8668     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8669     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8670
8671     if (stream->stream_tags)
8672       gst_tag_list_unref (stream->stream_tags);
8673     stream->stream_tags = list;
8674     list = NULL;
8675     /* global tags go on each pad anyway */
8676     stream->send_global_tags = TRUE;
8677     /* send upstream GST_EVENT_PROTECTION events that were received before
8678        this source pad was created */
8679     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8680       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8681   }
8682 done:
8683   if (list)
8684     gst_tag_list_unref (list);
8685   return ret;
8686 }
8687
8688 /* find next atom with @fourcc starting at @offset */
8689 static GstFlowReturn
8690 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8691     guint64 * length, guint32 fourcc)
8692 {
8693   GstFlowReturn ret;
8694   guint32 lfourcc;
8695   GstBuffer *buf;
8696
8697   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8698       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8699
8700   while (TRUE) {
8701     GstMapInfo map;
8702
8703     buf = NULL;
8704     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8705     if (G_UNLIKELY (ret != GST_FLOW_OK))
8706       goto locate_failed;
8707     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8708       /* likely EOF */
8709       ret = GST_FLOW_EOS;
8710       gst_buffer_unref (buf);
8711       goto locate_failed;
8712     }
8713     gst_buffer_map (buf, &map, GST_MAP_READ);
8714     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8715     gst_buffer_unmap (buf, &map);
8716     gst_buffer_unref (buf);
8717
8718     if (G_UNLIKELY (*length == 0)) {
8719       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8720       ret = GST_FLOW_ERROR;
8721       goto locate_failed;
8722     }
8723
8724     if (lfourcc == fourcc) {
8725       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8726           *offset);
8727       break;
8728     } else {
8729       GST_LOG_OBJECT (qtdemux,
8730           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8731           GST_FOURCC_ARGS (fourcc), *offset);
8732       *offset += *length;
8733     }
8734   }
8735
8736   return GST_FLOW_OK;
8737
8738 locate_failed:
8739   {
8740     /* might simply have had last one */
8741     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8742     return ret;
8743   }
8744 }
8745
8746 /* should only do something in pull mode */
8747 /* call with OBJECT lock */
8748 static GstFlowReturn
8749 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8750 {
8751   guint64 length, offset;
8752   GstBuffer *buf = NULL;
8753   GstFlowReturn ret = GST_FLOW_OK;
8754   GstFlowReturn res = GST_FLOW_OK;
8755   GstMapInfo map;
8756
8757   offset = qtdemux->moof_offset;
8758   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8759
8760   if (!offset) {
8761     GST_DEBUG_OBJECT (qtdemux, "no next moof");
8762     return GST_FLOW_EOS;
8763   }
8764
8765   /* best not do pull etc with lock held */
8766   GST_OBJECT_UNLOCK (qtdemux);
8767
8768   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8769   if (ret != GST_FLOW_OK)
8770     goto flow_failed;
8771
8772   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8773   if (G_UNLIKELY (ret != GST_FLOW_OK))
8774     goto flow_failed;
8775   gst_buffer_map (buf, &map, GST_MAP_READ);
8776   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8777     gst_buffer_unmap (buf, &map);
8778     gst_buffer_unref (buf);
8779     buf = NULL;
8780     goto parse_failed;
8781   }
8782
8783   gst_buffer_unmap (buf, &map);
8784   gst_buffer_unref (buf);
8785   buf = NULL;
8786
8787   offset += length;
8788   /* look for next moof */
8789   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8790   if (G_UNLIKELY (ret != GST_FLOW_OK))
8791     goto flow_failed;
8792
8793 exit:
8794   GST_OBJECT_LOCK (qtdemux);
8795
8796   qtdemux->moof_offset = offset;
8797
8798   return res;
8799
8800 parse_failed:
8801   {
8802     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8803     offset = 0;
8804     res = GST_FLOW_ERROR;
8805     goto exit;
8806   }
8807 flow_failed:
8808   {
8809     /* maybe upstream temporarily flushing */
8810     if (ret != GST_FLOW_FLUSHING) {
8811       GST_DEBUG_OBJECT (qtdemux, "no next moof");
8812       offset = 0;
8813     } else {
8814       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8815       /* resume at current position next time */
8816     }
8817     res = ret;
8818     goto exit;
8819   }
8820 }
8821
8822 /* initialise bytereaders for stbl sub-atoms */
8823 static gboolean
8824 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8825 {
8826   stream->stbl_index = -1;      /* no samples have yet been parsed */
8827   stream->sample_index = -1;
8828
8829   /* time-to-sample atom */
8830   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8831     goto corrupt_file;
8832
8833   /* copy atom data into a new buffer for later use */
8834   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8835
8836   /* skip version + flags */
8837   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8838       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8839     goto corrupt_file;
8840   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8841
8842   /* make sure there's enough data */
8843   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8844     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8845     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8846         stream->n_sample_times);
8847     if (!stream->n_sample_times)
8848       goto corrupt_file;
8849   }
8850
8851   /* sync sample atom */
8852   stream->stps_present = FALSE;
8853   if ((stream->stss_present =
8854           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8855               &stream->stss) ? TRUE : FALSE) == TRUE) {
8856     /* copy atom data into a new buffer for later use */
8857     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8858
8859     /* skip version + flags */
8860     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8861         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8862       goto corrupt_file;
8863
8864     if (stream->n_sample_syncs) {
8865       /* make sure there's enough data */
8866       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8867         goto corrupt_file;
8868     }
8869
8870     /* partial sync sample atom */
8871     if ((stream->stps_present =
8872             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8873                 &stream->stps) ? TRUE : FALSE) == TRUE) {
8874       /* copy atom data into a new buffer for later use */
8875       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8876
8877       /* skip version + flags */
8878       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8879           !gst_byte_reader_get_uint32_be (&stream->stps,
8880               &stream->n_sample_partial_syncs))
8881         goto corrupt_file;
8882
8883       /* if there are no entries, the stss table contains the real
8884        * sync samples */
8885       if (stream->n_sample_partial_syncs) {
8886         /* make sure there's enough data */
8887         if (!qt_atom_parser_has_chunks (&stream->stps,
8888                 stream->n_sample_partial_syncs, 4))
8889           goto corrupt_file;
8890       }
8891     }
8892   }
8893
8894   /* sample size */
8895   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8896     goto no_samples;
8897
8898   /* copy atom data into a new buffer for later use */
8899   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8900
8901   /* skip version + flags */
8902   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8903       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8904     goto corrupt_file;
8905
8906   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8907     goto corrupt_file;
8908
8909   if (!stream->n_samples)
8910     goto no_samples;
8911
8912   /* sample-to-chunk atom */
8913   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8914     goto corrupt_file;
8915
8916   /* copy atom data into a new buffer for later use */
8917   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8918
8919   /* skip version + flags */
8920   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8921       !gst_byte_reader_get_uint32_be (&stream->stsc,
8922           &stream->n_samples_per_chunk))
8923     goto corrupt_file;
8924
8925   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8926       stream->n_samples_per_chunk);
8927
8928   /* make sure there's enough data */
8929   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8930           12))
8931     goto corrupt_file;
8932
8933
8934   /* chunk offset */
8935   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8936     stream->co_size = sizeof (guint32);
8937   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8938           &stream->stco))
8939     stream->co_size = sizeof (guint64);
8940   else
8941     goto corrupt_file;
8942
8943   /* copy atom data into a new buffer for later use */
8944   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8945
8946   /* skip version + flags */
8947   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8948     goto corrupt_file;
8949
8950   /* chunks_are_samples == TRUE means treat chunks as samples */
8951   stream->chunks_are_samples = stream->sample_size
8952       && !CUR_STREAM (stream)->sampled;
8953   if (stream->chunks_are_samples) {
8954     /* treat chunks as samples */
8955     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8956       goto corrupt_file;
8957   } else {
8958     /* skip number of entries */
8959     if (!gst_byte_reader_skip (&stream->stco, 4))
8960       goto corrupt_file;
8961
8962     /* make sure there are enough data in the stsz atom */
8963     if (!stream->sample_size) {
8964       /* different sizes for each sample */
8965       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8966         goto corrupt_file;
8967     }
8968   }
8969
8970   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8971       stream->n_samples, (guint) sizeof (QtDemuxSample),
8972       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8973
8974   if (stream->n_samples >=
8975       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8976     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8977         "be larger than %uMB (broken file?)", stream->n_samples,
8978         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8979     return FALSE;
8980   }
8981
8982   g_assert (stream->samples == NULL);
8983   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8984   if (!stream->samples) {
8985     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8986         stream->n_samples);
8987     return FALSE;
8988   }
8989
8990   /* composition time-to-sample */
8991   if ((stream->ctts_present =
8992           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
8993               &stream->ctts) ? TRUE : FALSE) == TRUE) {
8994     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
8995
8996     /* copy atom data into a new buffer for later use */
8997     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
8998
8999     /* skip version + flags */
9000     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9001         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9002             &stream->n_composition_times))
9003       goto corrupt_file;
9004
9005     /* make sure there's enough data */
9006     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9007             4 + 4))
9008       goto corrupt_file;
9009
9010     /* This is optional, if missing we iterate the ctts */
9011     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9012       if (!gst_byte_reader_skip (&cslg, 1 + 3)
9013           || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9014         g_free ((gpointer) cslg.data);
9015         goto corrupt_file;
9016       }
9017     } else {
9018       gint32 cslg_least = 0;
9019       guint num_entries, pos;
9020       gint i;
9021
9022       pos = gst_byte_reader_get_pos (&stream->ctts);
9023       num_entries = stream->n_composition_times;
9024
9025       stream->cslg_shift = 0;
9026
9027       for (i = 0; i < num_entries; i++) {
9028         gint32 offset;
9029
9030         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9031         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9032
9033         if (offset < cslg_least)
9034           cslg_least = offset;
9035       }
9036
9037       if (cslg_least < 0)
9038         stream->cslg_shift = ABS (cslg_least);
9039       else
9040         stream->cslg_shift = 0;
9041
9042       /* reset the reader so we can generate sample table */
9043       gst_byte_reader_set_pos (&stream->ctts, pos);
9044     }
9045   } else {
9046     /* Ensure the cslg_shift value is consistent so we can use it
9047      * unconditionnally to produce TS and Segment */
9048     stream->cslg_shift = 0;
9049   }
9050
9051   return TRUE;
9052
9053 corrupt_file:
9054   {
9055     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9056         (_("This file is corrupt and cannot be played.")), (NULL));
9057     return FALSE;
9058   }
9059 no_samples:
9060   {
9061     gst_qtdemux_stbl_free (stream);
9062     if (!qtdemux->fragmented) {
9063       /* not quite good */
9064       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9065       return FALSE;
9066     } else {
9067       /* may pick up samples elsewhere */
9068       return TRUE;
9069     }
9070   }
9071 }
9072
9073 /* collect samples from the next sample to be parsed up to sample @n for @stream
9074  * by reading the info from @stbl
9075  *
9076  * This code can be executed from both the streaming thread and the seeking
9077  * thread so it takes the object lock to protect itself
9078  */
9079 static gboolean
9080 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9081 {
9082   gint i, j, k;
9083   QtDemuxSample *samples, *first, *cur, *last;
9084   guint32 n_samples_per_chunk;
9085   guint32 n_samples;
9086
9087   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9088       GST_FOURCC_FORMAT ", pad %s",
9089       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9090       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9091
9092   n_samples = stream->n_samples;
9093
9094   if (n >= n_samples)
9095     goto out_of_samples;
9096
9097   GST_OBJECT_LOCK (qtdemux);
9098   if (n <= stream->stbl_index)
9099     goto already_parsed;
9100
9101   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9102
9103   if (!stream->stsz.data) {
9104     /* so we already parsed and passed all the moov samples;
9105      * onto fragmented ones */
9106     g_assert (qtdemux->fragmented);
9107     goto done;
9108   }
9109
9110   /* pointer to the sample table */
9111   samples = stream->samples;
9112
9113   /* starts from -1, moves to the next sample index to parse */
9114   stream->stbl_index++;
9115
9116   /* keep track of the first and last sample to fill */
9117   first = &samples[stream->stbl_index];
9118   last = &samples[n];
9119
9120   if (!stream->chunks_are_samples) {
9121     /* set the sample sizes */
9122     if (stream->sample_size == 0) {
9123       /* different sizes for each sample */
9124       for (cur = first; cur <= last; cur++) {
9125         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9126         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9127             (guint) (cur - samples), cur->size);
9128       }
9129     } else {
9130       /* samples have the same size */
9131       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9132       for (cur = first; cur <= last; cur++)
9133         cur->size = stream->sample_size;
9134     }
9135   }
9136
9137   n_samples_per_chunk = stream->n_samples_per_chunk;
9138   cur = first;
9139
9140   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9141     guint32 last_chunk;
9142
9143     if (stream->stsc_chunk_index >= stream->last_chunk
9144         || stream->stsc_chunk_index < stream->first_chunk) {
9145       stream->first_chunk =
9146           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9147       stream->samples_per_chunk =
9148           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9149       /* starts from 1 */
9150       stream->stsd_sample_description_id =
9151           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9152
9153       /* chunk numbers are counted from 1 it seems */
9154       if (G_UNLIKELY (stream->first_chunk == 0))
9155         goto corrupt_file;
9156
9157       --stream->first_chunk;
9158
9159       /* the last chunk of each entry is calculated by taking the first chunk
9160        * of the next entry; except if there is no next, where we fake it with
9161        * INT_MAX */
9162       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9163         stream->last_chunk = G_MAXUINT32;
9164       } else {
9165         stream->last_chunk =
9166             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9167         if (G_UNLIKELY (stream->last_chunk == 0))
9168           goto corrupt_file;
9169
9170         --stream->last_chunk;
9171       }
9172
9173       GST_LOG_OBJECT (qtdemux,
9174           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9175           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9176           stream->samples_per_chunk, stream->stsd_sample_description_id);
9177
9178       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9179         goto corrupt_file;
9180
9181       if (stream->last_chunk != G_MAXUINT32) {
9182         if (!qt_atom_parser_peek_sub (&stream->stco,
9183                 stream->first_chunk * stream->co_size,
9184                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9185                 &stream->co_chunk))
9186           goto corrupt_file;
9187
9188       } else {
9189         stream->co_chunk = stream->stco;
9190         if (!gst_byte_reader_skip (&stream->co_chunk,
9191                 stream->first_chunk * stream->co_size))
9192           goto corrupt_file;
9193       }
9194
9195       stream->stsc_chunk_index = stream->first_chunk;
9196     }
9197
9198     last_chunk = stream->last_chunk;
9199
9200     if (stream->chunks_are_samples) {
9201       cur = &samples[stream->stsc_chunk_index];
9202
9203       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9204         if (j > n) {
9205           /* save state */
9206           stream->stsc_chunk_index = j;
9207           goto done;
9208         }
9209
9210         cur->offset =
9211             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9212             stream->co_size);
9213
9214         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9215             "%" G_GUINT64_FORMAT, j, cur->offset);
9216
9217         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9218             CUR_STREAM (stream)->bytes_per_frame > 0) {
9219           cur->size =
9220               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9221               CUR_STREAM (stream)->samples_per_frame *
9222               CUR_STREAM (stream)->bytes_per_frame;
9223         } else {
9224           cur->size = stream->samples_per_chunk;
9225         }
9226
9227         GST_DEBUG_OBJECT (qtdemux,
9228             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9229             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9230                     stream->stco_sample_index)), cur->size);
9231
9232         cur->timestamp = stream->stco_sample_index;
9233         cur->duration = stream->samples_per_chunk;
9234         cur->keyframe = TRUE;
9235         cur++;
9236
9237         stream->stco_sample_index += stream->samples_per_chunk;
9238       }
9239       stream->stsc_chunk_index = j;
9240     } else {
9241       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9242         guint32 samples_per_chunk;
9243         guint64 chunk_offset;
9244
9245         if (!stream->stsc_sample_index
9246             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9247                 &stream->chunk_offset))
9248           goto corrupt_file;
9249
9250         samples_per_chunk = stream->samples_per_chunk;
9251         chunk_offset = stream->chunk_offset;
9252
9253         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9254           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9255               G_GUINT64_FORMAT " and size %d",
9256               (guint) (cur - samples), chunk_offset, cur->size);
9257
9258           cur->offset = chunk_offset;
9259           chunk_offset += cur->size;
9260           cur++;
9261
9262           if (G_UNLIKELY (cur > last)) {
9263             /* save state */
9264             stream->stsc_sample_index = k + 1;
9265             stream->chunk_offset = chunk_offset;
9266             stream->stsc_chunk_index = j;
9267             goto done2;
9268           }
9269         }
9270         stream->stsc_sample_index = 0;
9271       }
9272       stream->stsc_chunk_index = j;
9273     }
9274     stream->stsc_index++;
9275   }
9276
9277   if (stream->chunks_are_samples)
9278     goto ctts;
9279 done2:
9280   {
9281     guint32 n_sample_times;
9282
9283     n_sample_times = stream->n_sample_times;
9284     cur = first;
9285
9286     for (i = stream->stts_index; i < n_sample_times; i++) {
9287       guint32 stts_samples;
9288       gint32 stts_duration;
9289       gint64 stts_time;
9290
9291       if (stream->stts_sample_index >= stream->stts_samples
9292           || !stream->stts_sample_index) {
9293
9294         stream->stts_samples =
9295             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9296         stream->stts_duration =
9297             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9298
9299         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9300             i, stream->stts_samples, stream->stts_duration);
9301
9302         stream->stts_sample_index = 0;
9303       }
9304
9305       stts_samples = stream->stts_samples;
9306       stts_duration = stream->stts_duration;
9307       stts_time = stream->stts_time;
9308
9309       for (j = stream->stts_sample_index; j < stts_samples; j++) {
9310         GST_DEBUG_OBJECT (qtdemux,
9311             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9312             (guint) (cur - samples), j,
9313             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9314
9315         cur->timestamp = stts_time;
9316         cur->duration = stts_duration;
9317
9318         /* avoid 32-bit wrap-around,
9319          * but still mind possible 'negative' duration */
9320         stts_time += (gint64) stts_duration;
9321         cur++;
9322
9323         if (G_UNLIKELY (cur > last)) {
9324           /* save values */
9325           stream->stts_time = stts_time;
9326           stream->stts_sample_index = j + 1;
9327           if (stream->stts_sample_index >= stream->stts_samples)
9328             stream->stts_index++;
9329           goto done3;
9330         }
9331       }
9332       stream->stts_sample_index = 0;
9333       stream->stts_time = stts_time;
9334       stream->stts_index++;
9335     }
9336     /* fill up empty timestamps with the last timestamp, this can happen when
9337      * the last samples do not decode and so we don't have timestamps for them.
9338      * We however look at the last timestamp to estimate the track length so we
9339      * need something in here. */
9340     for (; cur < last; cur++) {
9341       GST_DEBUG_OBJECT (qtdemux,
9342           "fill sample %d: timestamp %" GST_TIME_FORMAT,
9343           (guint) (cur - samples),
9344           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9345       cur->timestamp = stream->stts_time;
9346       cur->duration = -1;
9347     }
9348   }
9349 done3:
9350   {
9351     /* sample sync, can be NULL */
9352     if (stream->stss_present == TRUE) {
9353       guint32 n_sample_syncs;
9354
9355       n_sample_syncs = stream->n_sample_syncs;
9356
9357       if (!n_sample_syncs) {
9358         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9359         stream->all_keyframe = TRUE;
9360       } else {
9361         for (i = stream->stss_index; i < n_sample_syncs; i++) {
9362           /* note that the first sample is index 1, not 0 */
9363           guint32 index;
9364
9365           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9366
9367           if (G_LIKELY (index > 0 && index <= n_samples)) {
9368             index -= 1;
9369             samples[index].keyframe = TRUE;
9370             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9371             /* and exit if we have enough samples */
9372             if (G_UNLIKELY (index >= n)) {
9373               i++;
9374               break;
9375             }
9376           }
9377         }
9378         /* save state */
9379         stream->stss_index = i;
9380       }
9381
9382       /* stps marks partial sync frames like open GOP I-Frames */
9383       if (stream->stps_present == TRUE) {
9384         guint32 n_sample_partial_syncs;
9385
9386         n_sample_partial_syncs = stream->n_sample_partial_syncs;
9387
9388         /* if there are no entries, the stss table contains the real
9389          * sync samples */
9390         if (n_sample_partial_syncs) {
9391           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9392             /* note that the first sample is index 1, not 0 */
9393             guint32 index;
9394
9395             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9396
9397             if (G_LIKELY (index > 0 && index <= n_samples)) {
9398               index -= 1;
9399               samples[index].keyframe = TRUE;
9400               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9401               /* and exit if we have enough samples */
9402               if (G_UNLIKELY (index >= n)) {
9403                 i++;
9404                 break;
9405               }
9406             }
9407           }
9408           /* save state */
9409           stream->stps_index = i;
9410         }
9411       }
9412     } else {
9413       /* no stss, all samples are keyframes */
9414       stream->all_keyframe = TRUE;
9415       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9416     }
9417   }
9418
9419 ctts:
9420   /* composition time to sample */
9421   if (stream->ctts_present == TRUE) {
9422     guint32 n_composition_times;
9423     guint32 ctts_count;
9424     gint32 ctts_soffset;
9425
9426     /* Fill in the pts_offsets */
9427     cur = first;
9428     n_composition_times = stream->n_composition_times;
9429
9430     for (i = stream->ctts_index; i < n_composition_times; i++) {
9431       if (stream->ctts_sample_index >= stream->ctts_count
9432           || !stream->ctts_sample_index) {
9433         stream->ctts_count =
9434             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9435         stream->ctts_soffset =
9436             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9437         stream->ctts_sample_index = 0;
9438       }
9439
9440       ctts_count = stream->ctts_count;
9441       ctts_soffset = stream->ctts_soffset;
9442
9443       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9444         cur->pts_offset = ctts_soffset;
9445         cur++;
9446
9447         if (G_UNLIKELY (cur > last)) {
9448           /* save state */
9449           stream->ctts_sample_index = j + 1;
9450           goto done;
9451         }
9452       }
9453       stream->ctts_sample_index = 0;
9454       stream->ctts_index++;
9455     }
9456   }
9457 done:
9458   stream->stbl_index = n;
9459   /* if index has been completely parsed, free data that is no-longer needed */
9460   if (n + 1 == stream->n_samples) {
9461     gst_qtdemux_stbl_free (stream);
9462     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9463     if (qtdemux->pullbased) {
9464       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9465       while (n + 1 == stream->n_samples)
9466         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9467           break;
9468     }
9469   }
9470   GST_OBJECT_UNLOCK (qtdemux);
9471
9472   return TRUE;
9473
9474   /* SUCCESS */
9475 already_parsed:
9476   {
9477     GST_LOG_OBJECT (qtdemux,
9478         "Tried to parse up to sample %u but this sample has already been parsed",
9479         n);
9480     /* if fragmented, there may be more */
9481     if (qtdemux->fragmented && n == stream->stbl_index)
9482       goto done;
9483     GST_OBJECT_UNLOCK (qtdemux);
9484     return TRUE;
9485   }
9486   /* ERRORS */
9487 out_of_samples:
9488   {
9489     GST_LOG_OBJECT (qtdemux,
9490         "Tried to parse up to sample %u but there are only %u samples", n + 1,
9491         stream->n_samples);
9492     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9493         (_("This file is corrupt and cannot be played.")), (NULL));
9494     return FALSE;
9495   }
9496 corrupt_file:
9497   {
9498     GST_OBJECT_UNLOCK (qtdemux);
9499     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9500         (_("This file is corrupt and cannot be played.")), (NULL));
9501     return FALSE;
9502   }
9503 }
9504
9505 /* collect all segment info for @stream.
9506  */
9507 static gboolean
9508 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9509     GNode * trak)
9510 {
9511   GNode *edts;
9512   /* accept edts if they contain gaps at start and there is only
9513    * one media segment */
9514   gboolean allow_pushbased_edts = TRUE;
9515   gint media_segments_count = 0;
9516
9517   /* parse and prepare segment info from the edit list */
9518   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9519   stream->n_segments = 0;
9520   stream->segments = NULL;
9521   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9522     GNode *elst;
9523     gint n_segments;
9524     gint i, count, entry_size;
9525     guint64 time;
9526     GstClockTime stime;
9527     const guint8 *buffer;
9528     guint8 version;
9529     guint32 size;
9530
9531     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9532     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9533       goto done;
9534
9535     buffer = elst->data;
9536
9537     size = QT_UINT32 (buffer);
9538     /* version, flags, n_segments */
9539     if (size < 16) {
9540       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9541       goto done;
9542     }
9543     version = QT_UINT8 (buffer + 8);
9544     entry_size = (version == 1) ? 20 : 12;
9545
9546     n_segments = QT_UINT32 (buffer + 12);
9547
9548     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9549       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9550       goto done;
9551     }
9552
9553     /* we might allocate a bit too much, at least allocate 1 segment */
9554     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9555
9556     /* segments always start from 0 */
9557     time = 0;
9558     stime = 0;
9559     count = 0;
9560     buffer += 16;
9561     for (i = 0; i < n_segments; i++) {
9562       guint64 duration;
9563       guint64 media_time;
9564       gboolean time_valid = TRUE;
9565       QtDemuxSegment *segment;
9566       guint32 rate_int;
9567       GstClockTime media_start = GST_CLOCK_TIME_NONE;
9568
9569       if (version == 1) {
9570         media_time = QT_UINT64 (buffer + 8);
9571         duration = QT_UINT64 (buffer);
9572         if (media_time == G_MAXUINT64)
9573           time_valid = FALSE;
9574       } else {
9575         media_time = QT_UINT32 (buffer + 4);
9576         duration = QT_UINT32 (buffer);
9577         if (media_time == G_MAXUINT32)
9578           time_valid = FALSE;
9579       }
9580
9581       if (time_valid)
9582         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9583
9584       segment = &stream->segments[count++];
9585
9586       /* time and duration expressed in global timescale */
9587       segment->time = stime;
9588       /* add non scaled values so we don't cause roundoff errors */
9589       if (duration || media_start == GST_CLOCK_TIME_NONE) {
9590         time += duration;
9591         stime = QTTIME_TO_GSTTIME (qtdemux, time);
9592         segment->duration = stime - segment->time;
9593       } else {
9594         /* zero duration does not imply media_start == media_stop
9595          * but, only specify media_start.*/
9596         stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9597         if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9598             && stime >= media_start) {
9599           segment->duration = stime - media_start;
9600         } else {
9601           segment->duration = GST_CLOCK_TIME_NONE;
9602         }
9603       }
9604       segment->stop_time = stime;
9605
9606       segment->trak_media_start = media_time;
9607       /* media_time expressed in stream timescale */
9608       if (time_valid) {
9609         segment->media_start = media_start;
9610         segment->media_stop = segment->media_start + segment->duration;
9611         media_segments_count++;
9612       } else {
9613         segment->media_start = GST_CLOCK_TIME_NONE;
9614         segment->media_stop = GST_CLOCK_TIME_NONE;
9615       }
9616       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9617
9618       if (rate_int <= 1) {
9619         /* 0 is not allowed, some programs write 1 instead of the floating point
9620          * value */
9621         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9622             rate_int);
9623         segment->rate = 1;
9624       } else {
9625         segment->rate = rate_int / 65536.0;
9626       }
9627
9628       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9629           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9630           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9631           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9632           i, GST_TIME_ARGS (segment->time),
9633           GST_TIME_ARGS (segment->duration),
9634           GST_TIME_ARGS (segment->media_start), media_time,
9635           GST_TIME_ARGS (segment->media_stop),
9636           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9637           stream->timescale);
9638       if (segment->stop_time > qtdemux->segment.stop) {
9639         GST_WARNING_OBJECT (qtdemux, "Segment %d "
9640             " extends to %" GST_TIME_FORMAT
9641             " past the end of the file duration %" GST_TIME_FORMAT
9642             " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9643             GST_TIME_ARGS (qtdemux->segment.stop));
9644         qtdemux->segment.stop = segment->stop_time;
9645       }
9646
9647       buffer += entry_size;
9648     }
9649     GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9650     stream->n_segments = count;
9651     if (media_segments_count != 1)
9652       allow_pushbased_edts = FALSE;
9653   }
9654 done:
9655
9656   /* push based does not handle segments, so act accordingly here,
9657    * and warn if applicable */
9658   if (!qtdemux->pullbased && !allow_pushbased_edts) {
9659     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9660     /* remove and use default one below, we stream like it anyway */
9661     g_free (stream->segments);
9662     stream->segments = NULL;
9663     stream->n_segments = 0;
9664   }
9665
9666   /* no segments, create one to play the complete trak */
9667   if (stream->n_segments == 0) {
9668     GstClockTime stream_duration =
9669         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9670
9671     if (stream->segments == NULL)
9672       stream->segments = g_new (QtDemuxSegment, 1);
9673
9674     /* represent unknown our way */
9675     if (stream_duration == 0)
9676       stream_duration = GST_CLOCK_TIME_NONE;
9677
9678     stream->segments[0].time = 0;
9679     stream->segments[0].stop_time = stream_duration;
9680     stream->segments[0].duration = stream_duration;
9681     stream->segments[0].media_start = 0;
9682     stream->segments[0].media_stop = stream_duration;
9683     stream->segments[0].rate = 1.0;
9684     stream->segments[0].trak_media_start = 0;
9685
9686     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9687         GST_TIME_ARGS (stream_duration));
9688     stream->n_segments = 1;
9689     stream->dummy_segment = TRUE;
9690   }
9691   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9692
9693   return TRUE;
9694 }
9695
9696 /*
9697  * Parses the stsd atom of a svq3 trak looking for
9698  * the SMI and gama atoms.
9699  */
9700 static void
9701 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9702     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9703 {
9704   const guint8 *_gamma = NULL;
9705   GstBuffer *_seqh = NULL;
9706   const guint8 *stsd_data = stsd_entry_data;
9707   guint32 length = QT_UINT32 (stsd_data);
9708   guint16 version;
9709
9710   if (length < 32) {
9711     GST_WARNING_OBJECT (qtdemux, "stsd too short");
9712     goto end;
9713   }
9714
9715   stsd_data += 16;
9716   length -= 16;
9717   version = QT_UINT16 (stsd_data);
9718   if (version == 3) {
9719     if (length >= 70) {
9720       length -= 70;
9721       stsd_data += 70;
9722       while (length > 8) {
9723         guint32 fourcc, size;
9724         const guint8 *data;
9725         size = QT_UINT32 (stsd_data);
9726         fourcc = QT_FOURCC (stsd_data + 4);
9727         data = stsd_data + 8;
9728
9729         if (size == 0) {
9730           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9731               "svq3 atom parsing");
9732           goto end;
9733         }
9734
9735         switch (fourcc) {
9736           case FOURCC_gama:{
9737             if (size == 12) {
9738               _gamma = data;
9739             } else {
9740               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9741                   " for gama atom, expected 12", size);
9742             }
9743             break;
9744           }
9745           case FOURCC_SMI_:{
9746             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9747               guint32 seqh_size;
9748               if (_seqh != NULL) {
9749                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9750                     " found, ignoring");
9751               } else {
9752                 seqh_size = QT_UINT32 (data + 4);
9753                 if (seqh_size > 0) {
9754                   _seqh = gst_buffer_new_and_alloc (seqh_size);
9755                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9756                 }
9757               }
9758             }
9759             break;
9760           }
9761           default:{
9762             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9763                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9764           }
9765         }
9766
9767         if (size <= length) {
9768           length -= size;
9769           stsd_data += size;
9770         }
9771       }
9772     } else {
9773       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9774     }
9775   } else {
9776     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9777         G_GUINT16_FORMAT, version);
9778     goto end;
9779   }
9780
9781 end:
9782   if (gamma) {
9783     *gamma = _gamma;
9784   }
9785   if (seqh) {
9786     *seqh = _seqh;
9787   } else if (_seqh) {
9788     gst_buffer_unref (_seqh);
9789   }
9790 }
9791
9792 static gchar *
9793 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9794 {
9795   GNode *dinf;
9796   GstByteReader dref;
9797   gchar *uri = NULL;
9798
9799   /*
9800    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9801    * atom that might contain a 'data' atom with the rtsp uri.
9802    * This case was reported in bug #597497, some info about
9803    * the hndl atom can be found in TN1195
9804    */
9805   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9806   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9807
9808   if (dinf) {
9809     guint32 dref_num_entries = 0;
9810     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9811         gst_byte_reader_skip (&dref, 4) &&
9812         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9813       gint i;
9814
9815       /* search dref entries for hndl atom */
9816       for (i = 0; i < dref_num_entries; i++) {
9817         guint32 size = 0, type;
9818         guint8 string_len = 0;
9819         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9820             qt_atom_parser_get_fourcc (&dref, &type)) {
9821           if (type == FOURCC_hndl) {
9822             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9823
9824             /* skip data reference handle bytes and the
9825              * following pascal string and some extra 4
9826              * bytes I have no idea what are */
9827             if (!gst_byte_reader_skip (&dref, 4) ||
9828                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9829                 !gst_byte_reader_skip (&dref, string_len + 4)) {
9830               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9831               break;
9832             }
9833
9834             /* iterate over the atoms to find the data atom */
9835             while (gst_byte_reader_get_remaining (&dref) >= 8) {
9836               guint32 atom_size;
9837               guint32 atom_type;
9838
9839               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9840                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9841                 if (atom_type == FOURCC_data) {
9842                   const guint8 *uri_aux = NULL;
9843
9844                   /* found the data atom that might contain the rtsp uri */
9845                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9846                       "hndl atom, interpreting it as an URI");
9847                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9848                           &uri_aux)) {
9849                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9850                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9851                     else
9852                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9853                           "didn't contain a rtsp address");
9854                   } else {
9855                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9856                         "atom contents");
9857                   }
9858                   break;
9859                 }
9860                 /* skipping to the next entry */
9861                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9862                   break;
9863               } else {
9864                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9865                     "atom header");
9866                 break;
9867               }
9868             }
9869             break;
9870           }
9871           /* skip to the next entry */
9872           if (!gst_byte_reader_skip (&dref, size - 8))
9873             break;
9874         } else {
9875           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9876         }
9877       }
9878       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9879     }
9880   }
9881   return uri;
9882 }
9883
9884 #define AMR_NB_ALL_MODES        0x81ff
9885 #define AMR_WB_ALL_MODES        0x83ff
9886 static guint
9887 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9888 {
9889   /* The 'damr' atom is of the form:
9890    *
9891    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9892    *    32 b       8 b          16 b           8 b                 8 b
9893    *
9894    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9895    * represents the highest mode used in the stream (and thus the maximum
9896    * bitrate), with a couple of special cases as seen below.
9897    */
9898
9899   /* Map of frame type ID -> bitrate */
9900   static const guint nb_bitrates[] = {
9901     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9902   };
9903   static const guint wb_bitrates[] = {
9904     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9905   };
9906   GstMapInfo map;
9907   gsize max_mode;
9908   guint16 mode_set;
9909
9910   gst_buffer_map (buf, &map, GST_MAP_READ);
9911
9912   if (map.size != 0x11) {
9913     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9914     goto bad_data;
9915   }
9916
9917   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9918     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9919         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9920     goto bad_data;
9921   }
9922
9923   mode_set = QT_UINT16 (map.data + 13);
9924
9925   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9926     max_mode = 7 + (wb ? 1 : 0);
9927   else
9928     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9929     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9930
9931   if (max_mode == -1) {
9932     GST_DEBUG ("No mode indication was found (mode set) = %x",
9933         (guint) mode_set);
9934     goto bad_data;
9935   }
9936
9937   gst_buffer_unmap (buf, &map);
9938   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9939
9940 bad_data:
9941   gst_buffer_unmap (buf, &map);
9942   return 0;
9943 }
9944
9945 static gboolean
9946 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9947     GstByteReader * reader, guint32 * matrix, const gchar * atom)
9948 {
9949   /*
9950    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9951    * [0 1 2]
9952    * [3 4 5]
9953    * [6 7 8]
9954    */
9955
9956   if (gst_byte_reader_get_remaining (reader) < 36)
9957     return FALSE;
9958
9959   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9960   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9961   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9962   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9963   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9964   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9965   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9966   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9967   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9968
9969   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9970   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9971       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9972       matrix[2] & 0xFF);
9973   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9974       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9975       matrix[5] & 0xFF);
9976   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9977       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9978       matrix[8] & 0xFF);
9979
9980   return TRUE;
9981 }
9982
9983 static void
9984 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9985     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9986 {
9987
9988 /* [a b c]
9989  * [d e f]
9990  * [g h i]
9991  *
9992  * This macro will only compare value abdegh, it expects cfi to have already
9993  * been checked
9994  */
9995 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
9996                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
9997
9998   /* only handle the cases where the last column has standard values */
9999   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10000     const gchar *rotation_tag = NULL;
10001
10002     /* no rotation needed */
10003     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10004       /* NOP */
10005     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10006       rotation_tag = "rotate-90";
10007     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10008       rotation_tag = "rotate-180";
10009     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10010       rotation_tag = "rotate-270";
10011     } else {
10012       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10013     }
10014
10015     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10016         rotation_tag);
10017     if (rotation_tag != NULL) {
10018       if (*taglist == NULL)
10019         *taglist = gst_tag_list_new_empty ();
10020       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10021           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10022     }
10023   } else {
10024     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10025   }
10026 }
10027
10028 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10029  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10030  * Common Encryption (cenc), the function will also parse the tenc box (defined
10031  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10032  * (typically an enc[v|a|t|s] sample entry); the function will set
10033  * @original_fmt to the fourcc of the original unencrypted stream format.
10034  * Returns TRUE if successful; FALSE otherwise. */
10035 static gboolean
10036 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10037     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10038 {
10039   GNode *sinf;
10040   GNode *frma;
10041   GNode *schm;
10042   GNode *schi;
10043
10044   g_return_val_if_fail (qtdemux != NULL, FALSE);
10045   g_return_val_if_fail (stream != NULL, FALSE);
10046   g_return_val_if_fail (container != NULL, FALSE);
10047   g_return_val_if_fail (original_fmt != NULL, FALSE);
10048
10049   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10050   if (G_UNLIKELY (!sinf)) {
10051     if (stream->protection_scheme_type == FOURCC_cenc) {
10052       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10053           "mandatory for Common Encryption");
10054       return FALSE;
10055     }
10056     return TRUE;
10057   }
10058
10059   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10060   if (G_UNLIKELY (!frma)) {
10061     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10062     return FALSE;
10063   }
10064
10065   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10066   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10067       GST_FOURCC_ARGS (*original_fmt));
10068
10069   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10070   if (!schm) {
10071     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10072     return FALSE;
10073   }
10074   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10075   stream->protection_scheme_version =
10076       QT_UINT32 ((const guint8 *) schm->data + 16);
10077
10078   GST_DEBUG_OBJECT (qtdemux,
10079       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10080       "protection_scheme_version: %#010x",
10081       GST_FOURCC_ARGS (stream->protection_scheme_type),
10082       stream->protection_scheme_version);
10083
10084   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10085   if (!schi) {
10086     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10087     return FALSE;
10088   }
10089   if (stream->protection_scheme_type == FOURCC_cenc) {
10090     QtDemuxCencSampleSetInfo *info;
10091     GNode *tenc;
10092     const guint8 *tenc_data;
10093     guint32 isEncrypted;
10094     guint8 iv_size;
10095     const guint8 *default_kid;
10096     GstBuffer *kid_buf;
10097
10098     if (G_UNLIKELY (!stream->protection_scheme_info))
10099       stream->protection_scheme_info =
10100           g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10101
10102     info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10103
10104     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10105     if (!tenc) {
10106       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10107           "which is mandatory for Common Encryption");
10108       return FALSE;
10109     }
10110     tenc_data = (const guint8 *) tenc->data + 12;
10111     isEncrypted = QT_UINT24 (tenc_data);
10112     iv_size = QT_UINT8 (tenc_data + 3);
10113     default_kid = (tenc_data + 4);
10114     kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
10115     gst_buffer_fill (kid_buf, 0, default_kid, 16);
10116     if (info->default_properties)
10117       gst_structure_free (info->default_properties);
10118     info->default_properties =
10119         gst_structure_new ("application/x-cenc",
10120         "iv_size", G_TYPE_UINT, iv_size,
10121         "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
10122         "kid", GST_TYPE_BUFFER, kid_buf, NULL);
10123     GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
10124         "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
10125     gst_buffer_unref (kid_buf);
10126   }
10127   return TRUE;
10128 }
10129
10130 /* parse the traks.
10131  * With each track we associate a new QtDemuxStream that contains all the info
10132  * about the trak.
10133  * traks that do not decode to something (like strm traks) will not have a pad.
10134  */
10135 static gboolean
10136 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10137 {
10138   GstByteReader tkhd;
10139   int offset;
10140   GNode *mdia;
10141   GNode *mdhd;
10142   GNode *hdlr;
10143   GNode *minf;
10144   GNode *stbl;
10145   GNode *stsd;
10146   GNode *mp4a;
10147   GNode *mp4v;
10148   GNode *wave;
10149   GNode *esds;
10150   GNode *pasp;
10151   GNode *colr;
10152   GNode *tref;
10153   GNode *udta;
10154   GNode *svmi;
10155   GNode *fiel;
10156
10157   QtDemuxStream *stream = NULL;
10158   gboolean new_stream = FALSE;
10159   gchar *codec = NULL;
10160   const guint8 *stsd_data;
10161   const guint8 *stsd_entry_data;
10162   guint remaining_stsd_len;
10163   guint stsd_entry_count;
10164   guint stsd_index;
10165   guint16 lang_code;            /* quicktime lang code or packed iso code */
10166   guint32 version;
10167   guint32 tkhd_flags = 0;
10168   guint8 tkhd_version = 0;
10169   guint32 w = 0, h = 0;
10170   guint32 fourcc;
10171   guint value_size, stsd_len, len;
10172   guint32 track_id;
10173   guint32 dummy;
10174
10175   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10176
10177   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10178       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10179       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10180     goto corrupt_file;
10181
10182   /* pick between 64 or 32 bits */
10183   value_size = tkhd_version == 1 ? 8 : 4;
10184   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10185       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10186     goto corrupt_file;
10187
10188   if (!qtdemux->got_moov) {
10189     if (qtdemux_find_stream (qtdemux, track_id))
10190       goto existing_stream;
10191     stream = _create_stream ();
10192     stream->track_id = track_id;
10193     new_stream = TRUE;
10194   } else {
10195     stream = qtdemux_find_stream (qtdemux, track_id);
10196     if (!stream) {
10197       GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
10198       goto skip_track;
10199     }
10200
10201     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10202
10203     /* flush samples data from this track from previous moov */
10204     gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
10205     gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
10206   }
10207   /* need defaults for fragments */
10208   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10209
10210   if ((tkhd_flags & 1) == 0)
10211     stream->disabled = TRUE;
10212
10213   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10214       tkhd_version, tkhd_flags, stream->track_id);
10215
10216   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10217     goto corrupt_file;
10218
10219   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10220     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10221     if (qtdemux->major_brand != FOURCC_mjp2 ||
10222         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10223       goto corrupt_file;
10224   }
10225
10226   len = QT_UINT32 ((guint8 *) mdhd->data);
10227   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10228   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10229   if (version == 0x01000000) {
10230     if (len < 38)
10231       goto corrupt_file;
10232     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10233     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10234     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10235   } else {
10236     if (len < 30)
10237       goto corrupt_file;
10238     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10239     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10240     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10241   }
10242
10243   if (lang_code < 0x400) {
10244     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10245   } else if (lang_code == 0x7fff) {
10246     stream->lang_id[0] = 0;     /* unspecified */
10247   } else {
10248     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10249     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10250     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10251     stream->lang_id[3] = 0;
10252   }
10253
10254   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10255       stream->timescale);
10256   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10257       stream->duration);
10258   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10259       lang_code, stream->lang_id);
10260
10261   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10262     goto corrupt_file;
10263
10264   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10265     /* chapters track reference */
10266     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10267     if (chap) {
10268       gsize length = GST_READ_UINT32_BE (chap->data);
10269       if (qtdemux->chapters_track_id)
10270         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10271
10272       if (length >= 12) {
10273         qtdemux->chapters_track_id =
10274             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10275       }
10276     }
10277   }
10278
10279   /* fragmented files may have bogus duration in moov */
10280   if (!qtdemux->fragmented &&
10281       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10282     guint64 tdur1, tdur2;
10283
10284     /* don't overflow */
10285     tdur1 = stream->timescale * (guint64) qtdemux->duration;
10286     tdur2 = qtdemux->timescale * (guint64) stream->duration;
10287
10288     /* HACK:
10289      * some of those trailers, nowadays, have prologue images that are
10290      * themselves video tracks as well. I haven't really found a way to
10291      * identify those yet, except for just looking at their duration. */
10292     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10293       GST_WARNING_OBJECT (qtdemux,
10294           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10295           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10296           "found, assuming preview image or something; skipping track",
10297           stream->duration, stream->timescale, qtdemux->duration,
10298           qtdemux->timescale);
10299       if (new_stream)
10300         gst_qtdemux_stream_free (qtdemux, stream);
10301       return TRUE;
10302     }
10303   }
10304
10305   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10306     goto corrupt_file;
10307
10308   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10309       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10310
10311   len = QT_UINT32 ((guint8 *) hdlr->data);
10312   if (len >= 20)
10313     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10314   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10315       GST_FOURCC_ARGS (stream->subtype));
10316
10317   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10318     goto corrupt_file;
10319
10320   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10321     goto corrupt_file;
10322
10323   /*parse svmi header if existing */
10324   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10325   if (svmi) {
10326     len = QT_UINT32 ((guint8 *) svmi->data);
10327     version = QT_UINT32 ((guint8 *) svmi->data + 8);
10328     if (!version) {
10329       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10330       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10331       guint8 frame_type, frame_layout;
10332
10333       /* MPEG-A stereo video */
10334       if (qtdemux->major_brand == FOURCC_ss02)
10335         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10336
10337       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10338       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10339       switch (frame_type) {
10340         case 0:
10341           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10342           break;
10343         case 1:
10344           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10345           break;
10346         case 2:
10347           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10348           break;
10349         case 3:
10350           /* mode 3 is primary/secondary view sequence, ie
10351            * left/right views in separate tracks. See section 7.2
10352            * of ISO/IEC 23000-11:2009 */
10353           GST_FIXME_OBJECT (qtdemux,
10354               "Implement stereo video in separate streams");
10355       }
10356
10357       if ((frame_layout & 0x1) == 0)
10358         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10359
10360       GST_LOG_OBJECT (qtdemux,
10361           "StereoVideo: composition type: %u, is_left_first: %u",
10362           frame_type, frame_layout);
10363       stream->multiview_mode = mode;
10364       stream->multiview_flags = flags;
10365     }
10366   }
10367
10368   /* parse rest of tkhd */
10369   if (stream->subtype == FOURCC_vide) {
10370     guint32 matrix[9];
10371
10372     /* version 1 uses some 64-bit ints */
10373     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10374       goto corrupt_file;
10375
10376     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10377       goto corrupt_file;
10378
10379     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10380         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10381       goto corrupt_file;
10382
10383     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10384         &stream->stream_tags);
10385   }
10386
10387   /* parse stsd */
10388   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10389     goto corrupt_file;
10390   stsd_data = (const guint8 *) stsd->data;
10391
10392   /* stsd should at least have one entry */
10393   stsd_len = QT_UINT32 (stsd_data);
10394   if (stsd_len < 24) {
10395     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10396     if (stream->subtype == FOURCC_vivo) {
10397       if (new_stream)
10398         gst_qtdemux_stream_free (qtdemux, stream);
10399       return TRUE;
10400     } else {
10401       goto corrupt_file;
10402     }
10403   }
10404
10405   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10406   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10407   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
10408   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
10409
10410   stsd_entry_data = stsd_data + 16;
10411   remaining_stsd_len = stsd_len - 16;
10412   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10413     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10414
10415     /* and that entry should fit within stsd */
10416     len = QT_UINT32 (stsd_entry_data);
10417     if (len > remaining_stsd_len)
10418       goto corrupt_file;
10419
10420     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10421     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
10422         GST_FOURCC_ARGS (entry->fourcc));
10423     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
10424
10425     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10426       goto error_encrypted;
10427
10428     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10429       /* FIXME this looks wrong, there might be multiple children
10430        * with the same type */
10431       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10432       stream->protected = TRUE;
10433       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10434         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10435     }
10436
10437     if (stream->subtype == FOURCC_vide) {
10438       gboolean gray;
10439       gint depth, palette_size, palette_count;
10440       guint32 *palette_data = NULL;
10441
10442       entry->sampled = TRUE;
10443
10444       stream->display_width = w >> 16;
10445       stream->display_height = h >> 16;
10446
10447       offset = 16;
10448       if (len < 86)             /* TODO verify */
10449         goto corrupt_file;
10450
10451       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10452       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10453       entry->fps_n = 0;         /* this is filled in later */
10454       entry->fps_d = 0;         /* this is filled in later */
10455       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10456       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10457
10458       /* if color_table_id is 0, ctab atom must follow; however some files
10459        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10460        * if color table is not present we'll correct the value */
10461       if (entry->color_table_id == 0 &&
10462           (len < 90
10463               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10464         entry->color_table_id = -1;
10465       }
10466
10467       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10468           entry->width, entry->height, entry->bits_per_sample,
10469           entry->color_table_id);
10470
10471       depth = entry->bits_per_sample;
10472
10473       /* more than 32 bits means grayscale */
10474       gray = (depth > 32);
10475       /* low 32 bits specify the depth  */
10476       depth &= 0x1F;
10477
10478       /* different number of palette entries is determined by depth. */
10479       palette_count = 0;
10480       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10481         palette_count = (1 << depth);
10482       palette_size = palette_count * 4;
10483
10484       if (entry->color_table_id) {
10485         switch (palette_count) {
10486           case 0:
10487             break;
10488           case 2:
10489             palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10490             break;
10491           case 4:
10492             palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10493             break;
10494           case 16:
10495             if (gray)
10496               palette_data =
10497                   g_memdup (ff_qt_grayscale_palette_16, palette_size);
10498             else
10499               palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10500             break;
10501           case 256:
10502             if (gray)
10503               palette_data =
10504                   g_memdup (ff_qt_grayscale_palette_256, palette_size);
10505             else
10506               palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10507             break;
10508           default:
10509             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10510                 (_("The video in this file might not play correctly.")),
10511                 ("unsupported palette depth %d", depth));
10512             break;
10513         }
10514       } else {
10515         gint i, j, start, end;
10516
10517         if (len < 94)
10518           goto corrupt_file;
10519
10520         /* read table */
10521         start = QT_UINT32 (stsd_entry_data + offset + 70);
10522         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10523         end = QT_UINT16 (stsd_entry_data + offset + 76);
10524
10525         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10526             start, end, palette_count);
10527
10528         if (end > 255)
10529           end = 255;
10530         if (start > end)
10531           start = end;
10532
10533         if (len < 94 + (end - start) * 8)
10534           goto corrupt_file;
10535
10536         /* palette is always the same size */
10537         palette_data = g_malloc0 (256 * 4);
10538         palette_size = 256 * 4;
10539
10540         for (j = 0, i = start; i <= end; j++, i++) {
10541           guint32 a, r, g, b;
10542
10543           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10544           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10545           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10546           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10547
10548           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10549               (g & 0xff00) | (b >> 8);
10550         }
10551       }
10552
10553       if (entry->caps)
10554         gst_caps_unref (entry->caps);
10555
10556       entry->caps =
10557           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10558           &codec);
10559       if (G_UNLIKELY (!entry->caps)) {
10560         g_free (palette_data);
10561         goto unknown_stream;
10562       }
10563
10564       if (codec) {
10565         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10566             GST_TAG_VIDEO_CODEC, codec, NULL);
10567         g_free (codec);
10568         codec = NULL;
10569       }
10570
10571       if (palette_data) {
10572         GstStructure *s;
10573
10574         if (entry->rgb8_palette)
10575           gst_memory_unref (entry->rgb8_palette);
10576         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10577             palette_data, palette_size, 0, palette_size, palette_data, g_free);
10578
10579         s = gst_caps_get_structure (entry->caps, 0);
10580
10581         /* non-raw video has a palette_data property. raw video has the palette as
10582          * an extra plane that we append to the output buffers before we push
10583          * them*/
10584         if (!gst_structure_has_name (s, "video/x-raw")) {
10585           GstBuffer *palette;
10586
10587           palette = gst_buffer_new ();
10588           gst_buffer_append_memory (palette, entry->rgb8_palette);
10589           entry->rgb8_palette = NULL;
10590
10591           gst_caps_set_simple (entry->caps, "palette_data",
10592               GST_TYPE_BUFFER, palette, NULL);
10593           gst_buffer_unref (palette);
10594         }
10595       } else if (palette_count != 0) {
10596         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10597             (NULL), ("Unsupported palette depth %d", depth));
10598       }
10599
10600       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
10601           QT_UINT16 (stsd_entry_data + offset + 32));
10602
10603       esds = NULL;
10604       pasp = NULL;
10605       colr = NULL;
10606       fiel = NULL;
10607       /* pick 'the' stsd child */
10608       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10609       if (!stream->protected) {
10610         if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10611           mp4v = NULL;
10612         }
10613       } else {
10614         if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10615           mp4v = NULL;
10616         }
10617       }
10618
10619       if (mp4v) {
10620         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10621         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10622         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10623         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10624       }
10625
10626       if (pasp) {
10627         const guint8 *pasp_data = (const guint8 *) pasp->data;
10628         gint len = QT_UINT32 (pasp_data);
10629
10630         if (len == 16) {
10631           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10632           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10633         } else {
10634           CUR_STREAM (stream)->par_w = 0;
10635           CUR_STREAM (stream)->par_h = 0;
10636         }
10637       } else {
10638         CUR_STREAM (stream)->par_w = 0;
10639         CUR_STREAM (stream)->par_h = 0;
10640       }
10641
10642       if (fiel) {
10643         const guint8 *fiel_data = (const guint8 *) fiel->data;
10644         gint len = QT_UINT32 (fiel_data);
10645
10646         if (len == 10) {
10647           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10648           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10649         }
10650       }
10651
10652       if (colr) {
10653         const guint8 *colr_data = (const guint8 *) colr->data;
10654         gint len = QT_UINT32 (colr_data);
10655
10656         if (len == 19 || len == 18) {
10657           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10658
10659           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10660             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10661             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10662             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10663             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10664
10665             switch (primaries) {
10666               case 1:
10667                 CUR_STREAM (stream)->colorimetry.primaries =
10668                     GST_VIDEO_COLOR_PRIMARIES_BT709;
10669                 break;
10670               case 5:
10671                 CUR_STREAM (stream)->colorimetry.primaries =
10672                     GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10673                 break;
10674               case 6:
10675                 CUR_STREAM (stream)->colorimetry.primaries =
10676                     GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10677                 break;
10678               case 9:
10679                 CUR_STREAM (stream)->colorimetry.primaries =
10680                     GST_VIDEO_COLOR_PRIMARIES_BT2020;
10681                 break;
10682               default:
10683                 break;
10684             }
10685
10686             switch (transfer_function) {
10687               case 1:
10688                 CUR_STREAM (stream)->colorimetry.transfer =
10689                     GST_VIDEO_TRANSFER_BT709;
10690                 break;
10691               case 7:
10692                 CUR_STREAM (stream)->colorimetry.transfer =
10693                     GST_VIDEO_TRANSFER_SMPTE240M;
10694                 break;
10695               default:
10696                 break;
10697             }
10698
10699             switch (matrix) {
10700               case 1:
10701                 CUR_STREAM (stream)->colorimetry.matrix =
10702                     GST_VIDEO_COLOR_MATRIX_BT709;
10703                 break;
10704               case 6:
10705                 CUR_STREAM (stream)->colorimetry.matrix =
10706                     GST_VIDEO_COLOR_MATRIX_BT601;
10707                 break;
10708               case 7:
10709                 CUR_STREAM (stream)->colorimetry.matrix =
10710                     GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10711                 break;
10712               case 9:
10713                 CUR_STREAM (stream)->colorimetry.matrix =
10714                     GST_VIDEO_COLOR_MATRIX_BT2020;
10715                 break;
10716               default:
10717                 break;
10718             }
10719
10720             CUR_STREAM (stream)->colorimetry.range =
10721                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10722                 GST_VIDEO_COLOR_RANGE_16_235;
10723           } else {
10724             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10725           }
10726         } else {
10727           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10728         }
10729       }
10730
10731       if (esds) {
10732         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10733             stream->stream_tags);
10734       } else {
10735         switch (fourcc) {
10736           case FOURCC_H264:
10737           case FOURCC_avc1:
10738           case FOURCC_avc3:
10739           {
10740             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10741             const guint8 *avc_data = stsd_entry_data + 0x56;
10742
10743             /* find avcC */
10744             while (len >= 0x8) {
10745               gint size;
10746
10747               if (QT_UINT32 (avc_data) <= len)
10748                 size = QT_UINT32 (avc_data) - 0x8;
10749               else
10750                 size = len - 0x8;
10751
10752               if (size < 1)
10753                 /* No real data, so break out */
10754                 break;
10755
10756               switch (QT_FOURCC (avc_data + 0x4)) {
10757                 case FOURCC_avcC:
10758                 {
10759                   /* parse, if found */
10760                   GstBuffer *buf;
10761
10762                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10763
10764                   /* First 4 bytes are the length of the atom, the next 4 bytes
10765                    * are the fourcc, the next 1 byte is the version, and the
10766                    * subsequent bytes are profile_tier_level structure like data. */
10767                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10768                       avc_data + 8 + 1, size - 1);
10769                   buf = gst_buffer_new_and_alloc (size);
10770                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10771                   gst_caps_set_simple (entry->caps,
10772                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
10773                   gst_buffer_unref (buf);
10774
10775                   break;
10776                 }
10777                 case FOURCC_strf:
10778                 {
10779                   GstBuffer *buf;
10780
10781                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10782
10783                   /* First 4 bytes are the length of the atom, the next 4 bytes
10784                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10785                    * next 1 byte is the version, and the
10786                    * subsequent bytes are sequence parameter set like data. */
10787
10788                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
10789                   if (size > 1) {
10790                     gst_codec_utils_h264_caps_set_level_and_profile
10791                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10792
10793                     buf = gst_buffer_new_and_alloc (size);
10794                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10795                     gst_caps_set_simple (entry->caps,
10796                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
10797                     gst_buffer_unref (buf);
10798                   }
10799                   break;
10800                 }
10801                 case FOURCC_btrt:
10802                 {
10803                   guint avg_bitrate, max_bitrate;
10804
10805                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10806                   if (size < 12)
10807                     break;
10808
10809                   max_bitrate = QT_UINT32 (avc_data + 0xc);
10810                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
10811
10812                   if (!max_bitrate && !avg_bitrate)
10813                     break;
10814
10815                   /* Some muxers seem to swap the average and maximum bitrates
10816                    * (I'm looking at you, YouTube), so we swap for sanity. */
10817                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10818                     guint temp = avg_bitrate;
10819
10820                     avg_bitrate = max_bitrate;
10821                     max_bitrate = temp;
10822                   }
10823
10824                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10825                     gst_tag_list_add (stream->stream_tags,
10826                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10827                         max_bitrate, NULL);
10828                   }
10829                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10830                     gst_tag_list_add (stream->stream_tags,
10831                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10832                         NULL);
10833                   }
10834
10835                   break;
10836                 }
10837
10838                 default:
10839                   break;
10840               }
10841
10842               len -= size + 8;
10843               avc_data += size + 8;
10844             }
10845
10846             break;
10847           }
10848           case FOURCC_H265:
10849           case FOURCC_hvc1:
10850           case FOURCC_hev1:
10851           {
10852             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10853             const guint8 *hevc_data = stsd_entry_data + 0x56;
10854
10855             /* find hevc */
10856             while (len >= 0x8) {
10857               gint size;
10858
10859               if (QT_UINT32 (hevc_data) <= len)
10860                 size = QT_UINT32 (hevc_data) - 0x8;
10861               else
10862                 size = len - 0x8;
10863
10864               if (size < 1)
10865                 /* No real data, so break out */
10866                 break;
10867
10868               switch (QT_FOURCC (hevc_data + 0x4)) {
10869                 case FOURCC_hvcC:
10870                 {
10871                   /* parse, if found */
10872                   GstBuffer *buf;
10873
10874                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10875
10876                   /* First 4 bytes are the length of the atom, the next 4 bytes
10877                    * are the fourcc, the next 1 byte is the version, and the
10878                    * subsequent bytes are sequence parameter set like data. */
10879                   gst_codec_utils_h265_caps_set_level_tier_and_profile
10880                       (entry->caps, hevc_data + 8 + 1, size - 1);
10881
10882                   buf = gst_buffer_new_and_alloc (size);
10883                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10884                   gst_caps_set_simple (entry->caps,
10885                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
10886                   gst_buffer_unref (buf);
10887                   break;
10888                 }
10889                 default:
10890                   break;
10891               }
10892               len -= size + 8;
10893               hevc_data += size + 8;
10894             }
10895             break;
10896           }
10897           case FOURCC_mp4v:
10898           case FOURCC_MP4V:
10899           case FOURCC_fmp4:
10900           case FOURCC_FMP4:
10901           case FOURCC_xvid:
10902           case FOURCC_XVID:
10903           {
10904             GNode *glbl;
10905
10906             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10907                 GST_FOURCC_ARGS (fourcc));
10908
10909             /* codec data might be in glbl extension atom */
10910             glbl = mp4v ?
10911                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10912             if (glbl) {
10913               guint8 *data;
10914               GstBuffer *buf;
10915               gint len;
10916
10917               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10918               data = glbl->data;
10919               len = QT_UINT32 (data);
10920               if (len > 0x8) {
10921                 len -= 0x8;
10922                 buf = gst_buffer_new_and_alloc (len);
10923                 gst_buffer_fill (buf, 0, data + 8, len);
10924                 gst_caps_set_simple (entry->caps,
10925                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
10926                 gst_buffer_unref (buf);
10927               }
10928             }
10929             break;
10930           }
10931           case FOURCC_mjp2:
10932           {
10933             /* see annex I of the jpeg2000 spec */
10934             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10935             const guint8 *data;
10936             const gchar *colorspace = NULL;
10937             gint ncomp = 0;
10938             guint32 ncomp_map = 0;
10939             gint32 *comp_map = NULL;
10940             guint32 nchan_def = 0;
10941             gint32 *chan_def = NULL;
10942
10943             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10944             /* some required atoms */
10945             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10946             if (!mjp2)
10947               break;
10948             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10949             if (!jp2h)
10950               break;
10951
10952             /* number of components; redundant with info in codestream, but useful
10953                to a muxer */
10954             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10955             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10956               break;
10957             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10958
10959             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10960             if (!colr)
10961               break;
10962             GST_DEBUG_OBJECT (qtdemux, "found colr");
10963             /* extract colour space info */
10964             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10965               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10966                 case 16:
10967                   colorspace = "sRGB";
10968                   break;
10969                 case 17:
10970                   colorspace = "GRAY";
10971                   break;
10972                 case 18:
10973                   colorspace = "sYUV";
10974                   break;
10975                 default:
10976                   colorspace = NULL;
10977                   break;
10978               }
10979             }
10980             if (!colorspace)
10981               /* colr is required, and only values 16, 17, and 18 are specified,
10982                  so error if we have no colorspace */
10983               break;
10984
10985             /* extract component mapping */
10986             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10987             if (cmap) {
10988               guint32 cmap_len = 0;
10989               int i;
10990               cmap_len = QT_UINT32 (cmap->data);
10991               if (cmap_len >= 8) {
10992                 /* normal box, subtract off header */
10993                 cmap_len -= 8;
10994                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
10995                 if (cmap_len % 4 == 0) {
10996                   ncomp_map = (cmap_len / 4);
10997                   comp_map = g_new0 (gint32, ncomp_map);
10998                   for (i = 0; i < ncomp_map; i++) {
10999                     guint16 cmp;
11000                     guint8 mtyp, pcol;
11001                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11002                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11003                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11004                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11005                   }
11006                 }
11007               }
11008             }
11009             /* extract channel definitions */
11010             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11011             if (cdef) {
11012               guint32 cdef_len = 0;
11013               int i;
11014               cdef_len = QT_UINT32 (cdef->data);
11015               if (cdef_len >= 10) {
11016                 /* normal box, subtract off header and len */
11017                 cdef_len -= 10;
11018                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11019                 if (cdef_len % 6 == 0) {
11020                   nchan_def = (cdef_len / 6);
11021                   chan_def = g_new0 (gint32, nchan_def);
11022                   for (i = 0; i < nchan_def; i++)
11023                     chan_def[i] = -1;
11024                   for (i = 0; i < nchan_def; i++) {
11025                     guint16 cn, typ, asoc;
11026                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11027                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11028                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11029                     if (cn < nchan_def) {
11030                       switch (typ) {
11031                         case 0:
11032                           chan_def[cn] = asoc;
11033                           break;
11034                         case 1:
11035                           chan_def[cn] = 0;     /* alpha */
11036                           break;
11037                         default:
11038                           chan_def[cn] = -typ;
11039                       }
11040                     }
11041                   }
11042                 }
11043               }
11044             }
11045
11046             gst_caps_set_simple (entry->caps,
11047                 "num-components", G_TYPE_INT, ncomp, NULL);
11048             gst_caps_set_simple (entry->caps,
11049                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11050
11051             if (comp_map) {
11052               GValue arr = { 0, };
11053               GValue elt = { 0, };
11054               int i;
11055               g_value_init (&arr, GST_TYPE_ARRAY);
11056               g_value_init (&elt, G_TYPE_INT);
11057               for (i = 0; i < ncomp_map; i++) {
11058                 g_value_set_int (&elt, comp_map[i]);
11059                 gst_value_array_append_value (&arr, &elt);
11060               }
11061               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11062                   "component-map", &arr);
11063               g_value_unset (&elt);
11064               g_value_unset (&arr);
11065               g_free (comp_map);
11066             }
11067
11068             if (chan_def) {
11069               GValue arr = { 0, };
11070               GValue elt = { 0, };
11071               int i;
11072               g_value_init (&arr, GST_TYPE_ARRAY);
11073               g_value_init (&elt, G_TYPE_INT);
11074               for (i = 0; i < nchan_def; i++) {
11075                 g_value_set_int (&elt, chan_def[i]);
11076                 gst_value_array_append_value (&arr, &elt);
11077               }
11078               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11079                   "channel-definitions", &arr);
11080               g_value_unset (&elt);
11081               g_value_unset (&arr);
11082               g_free (chan_def);
11083             }
11084
11085             /* some optional atoms */
11086             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11087             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11088
11089             /* indicate possible fields in caps */
11090             if (field) {
11091               data = (guint8 *) field->data + 8;
11092               if (*data != 1)
11093                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11094                     (gint) * data, NULL);
11095             }
11096             /* add codec_data if provided */
11097             if (prefix) {
11098               GstBuffer *buf;
11099               gint len;
11100
11101               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11102               data = prefix->data;
11103               len = QT_UINT32 (data);
11104               if (len > 0x8) {
11105                 len -= 0x8;
11106                 buf = gst_buffer_new_and_alloc (len);
11107                 gst_buffer_fill (buf, 0, data + 8, len);
11108                 gst_caps_set_simple (entry->caps,
11109                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11110                 gst_buffer_unref (buf);
11111               }
11112             }
11113             break;
11114           }
11115           case FOURCC_SVQ3:
11116           case FOURCC_VP31:
11117           {
11118             GstBuffer *buf;
11119             GstBuffer *seqh = NULL;
11120             const guint8 *gamma_data = NULL;
11121             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11122
11123             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11124                 &seqh);
11125             if (gamma_data) {
11126               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11127                   QT_FP32 (gamma_data), NULL);
11128             }
11129             if (seqh) {
11130               /* sorry for the bad name, but we don't know what this is, other
11131                * than its own fourcc */
11132               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11133                   NULL);
11134               gst_buffer_unref (seqh);
11135             }
11136
11137             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11138             buf = gst_buffer_new_and_alloc (len);
11139             gst_buffer_fill (buf, 0, stsd_data, len);
11140             gst_caps_set_simple (entry->caps,
11141                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11142             gst_buffer_unref (buf);
11143             break;
11144           }
11145           case FOURCC_jpeg:
11146           {
11147             /* https://developer.apple.com/standards/qtff-2001.pdf,
11148              * page 92, "Video Sample Description", under table 3.1 */
11149             GstByteReader br;
11150
11151             const gint compressor_offset =
11152                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11153             const gint min_size = compressor_offset + 32 + 2 + 2;
11154             GNode *jpeg;
11155             guint32 len;
11156             guint16 color_table_id = 0;
11157             gboolean ok;
11158
11159             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11160
11161             /* recover information on interlaced/progressive */
11162             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11163             if (!jpeg)
11164               break;
11165
11166             len = QT_UINT32 (jpeg->data);
11167             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11168                 min_size);
11169             if (len >= min_size) {
11170               gst_byte_reader_init (&br, jpeg->data, len);
11171
11172               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11173               gst_byte_reader_get_uint16_le (&br, &color_table_id);
11174               if (color_table_id != 0) {
11175                 /* the spec says there can be concatenated chunks in the data, and we want
11176                  * to find one called field. Walk through them. */
11177                 gint offset = min_size;
11178                 while (offset + 8 < len) {
11179                   guint32 size = 0, tag;
11180                   ok = gst_byte_reader_get_uint32_le (&br, &size);
11181                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11182                   if (!ok || size < 8) {
11183                     GST_WARNING_OBJECT (qtdemux,
11184                         "Failed to walk optional chunk list");
11185                     break;
11186                   }
11187                   GST_DEBUG_OBJECT (qtdemux,
11188                       "Found optional %4.4s chunk, size %u",
11189                       (const char *) &tag, size);
11190                   if (tag == FOURCC_fiel) {
11191                     guint8 n_fields = 0, ordering = 0;
11192                     gst_byte_reader_get_uint8 (&br, &n_fields);
11193                     gst_byte_reader_get_uint8 (&br, &ordering);
11194                     if (n_fields == 1 || n_fields == 2) {
11195                       GST_DEBUG_OBJECT (qtdemux,
11196                           "Found fiel tag with %u fields, ordering %u",
11197                           n_fields, ordering);
11198                       if (n_fields == 2)
11199                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
11200                             "interlace-mode", G_TYPE_STRING, "interleaved",
11201                             NULL);
11202                     } else {
11203                       GST_WARNING_OBJECT (qtdemux,
11204                           "Found fiel tag with invalid fields (%u)", n_fields);
11205                     }
11206                   }
11207                   offset += size;
11208                 }
11209               } else {
11210                 GST_DEBUG_OBJECT (qtdemux,
11211                     "Color table ID is 0, not trying to get interlacedness");
11212               }
11213             } else {
11214               GST_WARNING_OBJECT (qtdemux,
11215                   "Length of jpeg chunk is too small, not trying to get interlacedness");
11216             }
11217
11218             break;
11219           }
11220           case FOURCC_rle_:
11221           case FOURCC_WRLE:
11222           {
11223             gst_caps_set_simple (entry->caps,
11224                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11225                 NULL);
11226             break;
11227           }
11228           case FOURCC_XiTh:
11229           {
11230             GNode *xith, *xdxt;
11231
11232             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11233             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11234             if (!xith)
11235               break;
11236
11237             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11238             if (!xdxt)
11239               break;
11240
11241             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11242             /* collect the headers and store them in a stream list so that we can
11243              * send them out first */
11244             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11245             break;
11246           }
11247           case FOURCC_ovc1:
11248           {
11249             GNode *ovc1;
11250             guint8 *ovc1_data;
11251             guint ovc1_len;
11252             GstBuffer *buf;
11253
11254             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11255             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11256             if (!ovc1)
11257               break;
11258             ovc1_data = ovc1->data;
11259             ovc1_len = QT_UINT32 (ovc1_data);
11260             if (ovc1_len <= 198) {
11261               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11262               break;
11263             }
11264             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11265             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11266             gst_caps_set_simple (entry->caps,
11267                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11268             gst_buffer_unref (buf);
11269             break;
11270           }
11271           case FOURCC_vc_1:
11272           {
11273             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11274             const guint8 *vc1_data = stsd_entry_data + 0x56;
11275
11276             /* find dvc1 */
11277             while (len >= 8) {
11278               gint size;
11279
11280               if (QT_UINT32 (vc1_data) <= len)
11281                 size = QT_UINT32 (vc1_data) - 8;
11282               else
11283                 size = len - 8;
11284
11285               if (size < 1)
11286                 /* No real data, so break out */
11287                 break;
11288
11289               switch (QT_FOURCC (vc1_data + 0x4)) {
11290                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11291                 {
11292                   GstBuffer *buf;
11293
11294                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11295                   buf = gst_buffer_new_and_alloc (size);
11296                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
11297                   gst_caps_set_simple (entry->caps,
11298                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11299                   gst_buffer_unref (buf);
11300                   break;
11301                 }
11302                 default:
11303                   break;
11304               }
11305               len -= size + 8;
11306               vc1_data += size + 8;
11307             }
11308             break;
11309           }
11310           default:
11311             break;
11312         }
11313       }
11314
11315       GST_INFO_OBJECT (qtdemux,
11316           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11317           GST_FOURCC_ARGS (fourcc), entry->caps);
11318
11319     } else if (stream->subtype == FOURCC_soun) {
11320       int version, samplesize;
11321       guint16 compression_id;
11322       gboolean amrwb = FALSE;
11323
11324       offset = 16;
11325       /* sample description entry (16) + sound sample description v0 (20) */
11326       if (len < 36)
11327         goto corrupt_file;
11328
11329       version = QT_UINT32 (stsd_entry_data + offset);
11330       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11331       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11332       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11333       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11334
11335       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
11336       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
11337           QT_UINT32 (stsd_entry_data + offset + 4));
11338       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
11339       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
11340       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
11341       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
11342           QT_UINT16 (stsd_entry_data + offset + 14));
11343       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
11344
11345       if (compression_id == 0xfffe)
11346         entry->sampled = TRUE;
11347
11348       /* first assume uncompressed audio */
11349       entry->bytes_per_sample = samplesize / 8;
11350       entry->samples_per_frame = entry->n_channels;
11351       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11352       entry->samples_per_packet = entry->samples_per_frame;
11353       entry->bytes_per_packet = entry->bytes_per_sample;
11354
11355       offset = 36;
11356       switch (fourcc) {
11357           /* Yes, these have to be hard-coded */
11358         case FOURCC_MAC6:
11359         {
11360           entry->samples_per_packet = 6;
11361           entry->bytes_per_packet = 1;
11362           entry->bytes_per_frame = 1 * entry->n_channels;
11363           entry->bytes_per_sample = 1;
11364           entry->samples_per_frame = 6 * entry->n_channels;
11365           break;
11366         }
11367         case FOURCC_MAC3:
11368         {
11369           entry->samples_per_packet = 3;
11370           entry->bytes_per_packet = 1;
11371           entry->bytes_per_frame = 1 * entry->n_channels;
11372           entry->bytes_per_sample = 1;
11373           entry->samples_per_frame = 3 * entry->n_channels;
11374           break;
11375         }
11376         case FOURCC_ima4:
11377         {
11378           entry->samples_per_packet = 64;
11379           entry->bytes_per_packet = 34;
11380           entry->bytes_per_frame = 34 * entry->n_channels;
11381           entry->bytes_per_sample = 2;
11382           entry->samples_per_frame = 64 * entry->n_channels;
11383           break;
11384         }
11385         case FOURCC_ulaw:
11386         case FOURCC_alaw:
11387         {
11388           entry->samples_per_packet = 1;
11389           entry->bytes_per_packet = 1;
11390           entry->bytes_per_frame = 1 * entry->n_channels;
11391           entry->bytes_per_sample = 1;
11392           entry->samples_per_frame = 1 * entry->n_channels;
11393           break;
11394         }
11395         case FOURCC_agsm:
11396         {
11397           entry->samples_per_packet = 160;
11398           entry->bytes_per_packet = 33;
11399           entry->bytes_per_frame = 33 * entry->n_channels;
11400           entry->bytes_per_sample = 2;
11401           entry->samples_per_frame = 160 * entry->n_channels;
11402           break;
11403         }
11404         default:
11405           break;
11406       }
11407
11408       if (version == 0x00010000) {
11409         /* sample description entry (16) + sound sample description v1 (20+16) */
11410         if (len < 52)
11411           goto corrupt_file;
11412
11413         switch (fourcc) {
11414           case FOURCC_twos:
11415           case FOURCC_sowt:
11416           case FOURCC_raw_:
11417             break;
11418           default:
11419           {
11420             /* only parse extra decoding config for non-pcm audio */
11421             entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11422             entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11423             entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11424             entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11425
11426             GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
11427                 entry->samples_per_packet);
11428             GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
11429                 entry->bytes_per_packet);
11430             GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
11431                 entry->bytes_per_frame);
11432             GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
11433                 entry->bytes_per_sample);
11434
11435             if (!entry->sampled && entry->bytes_per_packet) {
11436               entry->samples_per_frame = (entry->bytes_per_frame /
11437                   entry->bytes_per_packet) * entry->samples_per_packet;
11438               GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
11439                   entry->samples_per_frame);
11440             }
11441             break;
11442           }
11443         }
11444       } else if (version == 0x00020000) {
11445         union
11446         {
11447           gdouble fp;
11448           guint64 val;
11449         } qtfp;
11450
11451         /* sample description entry (16) + sound sample description v2 (56) */
11452         if (len < 72)
11453           goto corrupt_file;
11454
11455         qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11456         entry->rate = qtfp.fp;
11457         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11458
11459         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11460         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
11461         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
11462         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
11463             QT_UINT32 (stsd_entry_data + offset + 20));
11464         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
11465             QT_UINT32 (stsd_entry_data + offset + 24));
11466         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
11467             QT_UINT32 (stsd_entry_data + offset + 28));
11468         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11469             QT_UINT32 (stsd_entry_data + offset + 32));
11470       } else if (version != 0x00000) {
11471         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11472             version);
11473       }
11474
11475       if (entry->caps)
11476         gst_caps_unref (entry->caps);
11477
11478       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11479           stsd_entry_data + 32, len - 16, &codec);
11480
11481       switch (fourcc) {
11482         case FOURCC_in24:
11483         {
11484           GNode *enda;
11485           GNode *in24;
11486
11487           in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11488
11489           enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11490           if (!enda) {
11491             wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11492             if (wave)
11493               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11494           }
11495           if (enda) {
11496             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11497             gst_caps_set_simple (entry->caps,
11498                 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11499                 NULL);
11500           }
11501           break;
11502         }
11503         case FOURCC_owma:
11504         {
11505           const guint8 *owma_data;
11506           const gchar *codec_name = NULL;
11507           guint owma_len;
11508           GstBuffer *buf;
11509           gint version = 1;
11510           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11511           /* FIXME this should also be gst_riff_strf_auds,
11512            * but the latter one is actually missing bits-per-sample :( */
11513           typedef struct
11514           {
11515             gint16 wFormatTag;
11516             gint16 nChannels;
11517             gint32 nSamplesPerSec;
11518             gint32 nAvgBytesPerSec;
11519             gint16 nBlockAlign;
11520             gint16 wBitsPerSample;
11521             gint16 cbSize;
11522           } WAVEFORMATEX;
11523           WAVEFORMATEX *wfex;
11524
11525           GST_DEBUG_OBJECT (qtdemux, "parse owma");
11526           owma_data = stsd_entry_data;
11527           owma_len = QT_UINT32 (owma_data);
11528           if (owma_len <= 54) {
11529             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11530             break;
11531           }
11532           wfex = (WAVEFORMATEX *) (owma_data + 36);
11533           buf = gst_buffer_new_and_alloc (owma_len - 54);
11534           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11535           if (wfex->wFormatTag == 0x0161) {
11536             codec_name = "Windows Media Audio";
11537             version = 2;
11538           } else if (wfex->wFormatTag == 0x0162) {
11539             codec_name = "Windows Media Audio 9 Pro";
11540             version = 3;
11541           } else if (wfex->wFormatTag == 0x0163) {
11542             codec_name = "Windows Media Audio 9 Lossless";
11543             /* is that correct? gstffmpegcodecmap.c is missing it, but
11544              * fluendo codec seems to support it */
11545             version = 4;
11546           }
11547
11548           gst_caps_set_simple (entry->caps,
11549               "codec_data", GST_TYPE_BUFFER, buf,
11550               "wmaversion", G_TYPE_INT, version,
11551               "block_align", G_TYPE_INT,
11552               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11553               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11554               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11555               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11556           gst_buffer_unref (buf);
11557
11558           if (codec_name) {
11559             g_free (codec);
11560             codec = g_strdup (codec_name);
11561           }
11562           break;
11563         }
11564         case FOURCC_wma_:
11565         {
11566           gint len = QT_UINT32 (stsd_entry_data) - offset;
11567           const guint8 *wfex_data = stsd_entry_data + offset;
11568           const gchar *codec_name = NULL;
11569           gint version = 1;
11570           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11571           /* FIXME this should also be gst_riff_strf_auds,
11572            * but the latter one is actually missing bits-per-sample :( */
11573           typedef struct
11574           {
11575             gint16 wFormatTag;
11576             gint16 nChannels;
11577             gint32 nSamplesPerSec;
11578             gint32 nAvgBytesPerSec;
11579             gint16 nBlockAlign;
11580             gint16 wBitsPerSample;
11581             gint16 cbSize;
11582           } WAVEFORMATEX;
11583           WAVEFORMATEX wfex;
11584
11585           /* FIXME: unify with similar wavformatex parsing code above */
11586           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11587
11588           /* find wfex */
11589           while (len >= 8) {
11590             gint size;
11591
11592             if (QT_UINT32 (wfex_data) <= len)
11593               size = QT_UINT32 (wfex_data) - 8;
11594             else
11595               size = len - 8;
11596
11597             if (size < 1)
11598               /* No real data, so break out */
11599               break;
11600
11601             switch (QT_FOURCC (wfex_data + 4)) {
11602               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11603               {
11604                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11605
11606                 if (size < 8 + 18)
11607                   break;
11608
11609                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11610                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11611                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11612                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11613                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11614                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11615                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11616
11617                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11618                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11619                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11620                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11621                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11622                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11623
11624                 if (wfex.wFormatTag == 0x0161) {
11625                   codec_name = "Windows Media Audio";
11626                   version = 2;
11627                 } else if (wfex.wFormatTag == 0x0162) {
11628                   codec_name = "Windows Media Audio 9 Pro";
11629                   version = 3;
11630                 } else if (wfex.wFormatTag == 0x0163) {
11631                   codec_name = "Windows Media Audio 9 Lossless";
11632                   /* is that correct? gstffmpegcodecmap.c is missing it, but
11633                    * fluendo codec seems to support it */
11634                   version = 4;
11635                 }
11636
11637                 gst_caps_set_simple (entry->caps,
11638                     "wmaversion", G_TYPE_INT, version,
11639                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
11640                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11641                     "width", G_TYPE_INT, wfex.wBitsPerSample,
11642                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11643
11644                 if (size > wfex.cbSize) {
11645                   GstBuffer *buf;
11646
11647                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11648                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11649                       size - wfex.cbSize);
11650                   gst_caps_set_simple (entry->caps,
11651                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11652                   gst_buffer_unref (buf);
11653                 } else {
11654                   GST_WARNING_OBJECT (qtdemux, "no codec data");
11655                 }
11656
11657                 if (codec_name) {
11658                   g_free (codec);
11659                   codec = g_strdup (codec_name);
11660                 }
11661                 break;
11662               }
11663               default:
11664                 break;
11665             }
11666             len -= size + 8;
11667             wfex_data += size + 8;
11668           }
11669           break;
11670         }
11671         case FOURCC_opus:
11672         {
11673           const guint8 *opus_data;
11674           guint8 *channel_mapping = NULL;
11675           guint32 rate;
11676           guint8 channels;
11677           guint8 channel_mapping_family;
11678           guint8 stream_count;
11679           guint8 coupled_count;
11680           guint8 i;
11681
11682           opus_data = stsd_entry_data;
11683
11684           channels = GST_READ_UINT8 (opus_data + 45);
11685           rate = GST_READ_UINT32_LE (opus_data + 48);
11686           channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11687           stream_count = GST_READ_UINT8 (opus_data + 55);
11688           coupled_count = GST_READ_UINT8 (opus_data + 56);
11689
11690           if (channels > 0) {
11691             channel_mapping = g_malloc (channels * sizeof (guint8));
11692             for (i = 0; i < channels; i++)
11693               channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11694           }
11695
11696           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11697               channel_mapping_family, stream_count, coupled_count,
11698               channel_mapping);
11699           break;
11700         }
11701         default:
11702           break;
11703       }
11704
11705       if (codec) {
11706         GstStructure *s;
11707         gint bitrate = 0;
11708
11709         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11710             GST_TAG_AUDIO_CODEC, codec, NULL);
11711         g_free (codec);
11712         codec = NULL;
11713
11714         /* some bitrate info may have ended up in caps */
11715         s = gst_caps_get_structure (entry->caps, 0);
11716         gst_structure_get_int (s, "bitrate", &bitrate);
11717         if (bitrate > 0)
11718           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11719               GST_TAG_BITRATE, bitrate, NULL);
11720       }
11721
11722       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11723       if (!stream->protected) {
11724       } else {
11725         if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11726           mp4v = NULL;
11727         }
11728       }
11729       if (stream->protected && fourcc == FOURCC_mp4a) {
11730         if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11731           mp4a = NULL;
11732         }
11733       } else {
11734         if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11735           mp4a = NULL;
11736         }
11737       }
11738
11739       wave = NULL;
11740       esds = NULL;
11741       if (mp4a) {
11742         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11743         if (wave)
11744           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11745         if (!esds)
11746           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11747       }
11748
11749
11750       /* If the fourcc's bottom 16 bits gives 'sm', then the top
11751          16 bits is a byte-swapped wave-style codec identifier,
11752          and we can find a WAVE header internally to a 'wave' atom here.
11753          This can more clearly be thought of as 'ms' as the top 16 bits, and a
11754          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11755          is big-endian).
11756        */
11757       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11758         if (len < offset + 20) {
11759           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11760         } else {
11761           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11762           const guint8 *data = stsd_entry_data + offset + 16;
11763           GNode *wavenode;
11764           GNode *waveheadernode;
11765
11766           wavenode = g_node_new ((guint8 *) data);
11767           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11768             const guint8 *waveheader;
11769             guint32 headerlen;
11770
11771             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11772             if (waveheadernode) {
11773               waveheader = (const guint8 *) waveheadernode->data;
11774               headerlen = QT_UINT32 (waveheader);
11775
11776               if (headerlen > 8) {
11777                 gst_riff_strf_auds *header = NULL;
11778                 GstBuffer *headerbuf;
11779                 GstBuffer *extra;
11780
11781                 waveheader += 8;
11782                 headerlen -= 8;
11783
11784                 headerbuf = gst_buffer_new_and_alloc (headerlen);
11785                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11786
11787                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11788                         headerbuf, &header, &extra)) {
11789                   gst_caps_unref (entry->caps);
11790                   /* FIXME: Need to do something with the channel reorder map */
11791                   entry->caps =
11792                       gst_riff_create_audio_caps (header->format, NULL, header,
11793                       extra, NULL, NULL, NULL);
11794
11795                   if (extra)
11796                     gst_buffer_unref (extra);
11797                   g_free (header);
11798                 }
11799               }
11800             } else
11801               GST_DEBUG ("Didn't find waveheadernode for this codec");
11802           }
11803           g_node_destroy (wavenode);
11804         }
11805       } else if (esds) {
11806         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11807             stream->stream_tags);
11808       } else {
11809         switch (fourcc) {
11810 #if 0
11811             /* FIXME: what is in the chunk? */
11812           case FOURCC_QDMC:
11813           {
11814             gint len = QT_UINT32 (stsd_data);
11815
11816             /* seems to be always = 116 = 0x74 */
11817             break;
11818           }
11819 #endif
11820           case FOURCC_QDM2:
11821           {
11822             gint len = QT_UINT32 (stsd_entry_data);
11823
11824             if (len > 0x3C) {
11825               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11826
11827               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11828               gst_caps_set_simple (entry->caps,
11829                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
11830               gst_buffer_unref (buf);
11831             }
11832             gst_caps_set_simple (entry->caps,
11833                 "samplesize", G_TYPE_INT, samplesize, NULL);
11834             break;
11835           }
11836           case FOURCC_alac:
11837           {
11838             GNode *alac, *wave = NULL;
11839
11840             /* apparently, m4a has this atom appended directly in the stsd entry,
11841              * while mov has it in a wave atom */
11842             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11843             if (alac) {
11844               /* alac now refers to stsd entry atom */
11845               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11846               if (wave)
11847                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11848               else
11849                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11850             }
11851             if (alac) {
11852               const guint8 *alac_data = alac->data;
11853               gint len = QT_UINT32 (alac->data);
11854               GstBuffer *buf;
11855
11856               if (len < 36) {
11857                 GST_DEBUG_OBJECT (qtdemux,
11858                     "discarding alac atom with unexpected len %d", len);
11859               } else {
11860                 /* codec-data contains alac atom size and prefix,
11861                  * ffmpeg likes it that way, not quite gst-ish though ...*/
11862                 buf = gst_buffer_new_and_alloc (len);
11863                 gst_buffer_fill (buf, 0, alac->data, len);
11864                 gst_caps_set_simple (entry->caps,
11865                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11866                 gst_buffer_unref (buf);
11867
11868                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11869                 entry->n_channels = QT_UINT8 (alac_data + 21);
11870                 entry->rate = QT_UINT32 (alac_data + 32);
11871               }
11872             }
11873             gst_caps_set_simple (entry->caps,
11874                 "samplesize", G_TYPE_INT, samplesize, NULL);
11875             break;
11876           }
11877           case FOURCC_fLaC:
11878           {
11879             /* The codingname of the sample entry is 'fLaC' */
11880             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11881
11882             if (flac) {
11883               /* The 'dfLa' box is added to the sample entry to convey
11884                  initializing information for the decoder. */
11885               const GNode *dfla =
11886                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11887
11888               if (dfla) {
11889                 const guint32 len = QT_UINT32 (dfla->data);
11890
11891                 /* Must contain at least dfLa box header (12),
11892                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11893                 if (len < 50) {
11894                   GST_DEBUG_OBJECT (qtdemux,
11895                       "discarding dfla atom with unexpected len %d", len);
11896                 } else {
11897                   /* skip dfLa header to get the METADATA_BLOCKs */
11898                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11899                   const guint32 metadata_blocks_len = len - 12;
11900
11901                   gchar *stream_marker = g_strdup ("fLaC");
11902                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11903                       strlen (stream_marker));
11904
11905                   guint32 index = 0;
11906                   guint32 remainder = 0;
11907                   guint32 block_size = 0;
11908                   gboolean is_last = FALSE;
11909
11910                   GValue array = G_VALUE_INIT;
11911                   GValue value = G_VALUE_INIT;
11912
11913                   g_value_init (&array, GST_TYPE_ARRAY);
11914                   g_value_init (&value, GST_TYPE_BUFFER);
11915
11916                   gst_value_set_buffer (&value, block);
11917                   gst_value_array_append_value (&array, &value);
11918                   g_value_reset (&value);
11919
11920                   gst_buffer_unref (block);
11921
11922                   /* check there's at least one METADATA_BLOCK_HEADER's worth
11923                    * of data, and we haven't already finished parsing */
11924                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
11925                     remainder = metadata_blocks_len - index;
11926
11927                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
11928                     block_size = 4 +
11929                         (metadata_blocks[index + 1] << 16) +
11930                         (metadata_blocks[index + 2] << 8) +
11931                         metadata_blocks[index + 3];
11932
11933                     /* be careful not to read off end of box */
11934                     if (block_size > remainder) {
11935                       break;
11936                     }
11937
11938                     is_last = metadata_blocks[index] >> 7;
11939
11940                     block = gst_buffer_new_and_alloc (block_size);
11941
11942                     gst_buffer_fill (block, 0, &metadata_blocks[index],
11943                         block_size);
11944
11945                     gst_value_set_buffer (&value, block);
11946                     gst_value_array_append_value (&array, &value);
11947                     g_value_reset (&value);
11948
11949                     gst_buffer_unref (block);
11950
11951                     index += block_size;
11952                   }
11953
11954                   /* only append the metadata if we successfully read all of it */
11955                   if (is_last) {
11956                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11957                             (stream)->caps, 0), "streamheader", &array);
11958                   } else {
11959                     GST_WARNING_OBJECT (qtdemux,
11960                         "discarding all METADATA_BLOCKs due to invalid "
11961                         "block_size %d at idx %d, rem %d", block_size, index,
11962                         remainder);
11963                   }
11964
11965                   g_value_unset (&value);
11966                   g_value_unset (&array);
11967
11968                   /* The sample rate obtained from the stsd may not be accurate
11969                    * since it cannot represent rates greater than 65535Hz, so
11970                    * override that value with the sample rate from the
11971                    * METADATA_BLOCK_STREAMINFO block */
11972                   CUR_STREAM (stream)->rate =
11973                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11974                 }
11975               }
11976             }
11977             break;
11978           }
11979           case FOURCC_sawb:
11980             /* Fallthrough! */
11981             amrwb = TRUE;
11982           case FOURCC_samr:
11983           {
11984             gint len = QT_UINT32 (stsd_entry_data);
11985
11986             if (len > 0x24) {
11987               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11988               guint bitrate;
11989
11990               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11991
11992               /* If we have enough data, let's try to get the 'damr' atom. See
11993                * the 3GPP container spec (26.244) for more details. */
11994               if ((len - 0x34) > 8 &&
11995                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
11996                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11997                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
11998               }
11999
12000               gst_caps_set_simple (entry->caps,
12001                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12002               gst_buffer_unref (buf);
12003             }
12004             break;
12005           }
12006           case FOURCC_mp4a:
12007           {
12008             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12009             gint len = QT_UINT32 (stsd_entry_data);
12010
12011             if (len >= 34) {
12012               guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12013
12014               if (sound_version == 1) {
12015                 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12016                 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12017                 guint8 codec_data[2];
12018                 GstBuffer *buf;
12019                 gint profile = 2;       /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12020
12021                 gint sample_rate_index =
12022                     gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12023
12024                 /* build AAC codec data */
12025                 codec_data[0] = profile << 3;
12026                 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12027                 codec_data[1] = (sample_rate_index & 0x01) << 7;
12028                 codec_data[1] |= (channels & 0xF) << 3;
12029
12030                 buf = gst_buffer_new_and_alloc (2);
12031                 gst_buffer_fill (buf, 0, codec_data, 2);
12032                 gst_caps_set_simple (entry->caps,
12033                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12034                 gst_buffer_unref (buf);
12035               }
12036             }
12037             break;
12038           }
12039           default:
12040             GST_INFO_OBJECT (qtdemux,
12041                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12042             break;
12043         }
12044       }
12045       GST_INFO_OBJECT (qtdemux,
12046           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12047           GST_FOURCC_ARGS (fourcc), entry->caps);
12048
12049     } else if (stream->subtype == FOURCC_strm) {
12050       if (fourcc == FOURCC_rtsp) {
12051         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12052       } else {
12053         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12054             GST_FOURCC_ARGS (fourcc));
12055         goto unknown_stream;
12056       }
12057       entry->sampled = TRUE;
12058     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12059         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
12060
12061       entry->sampled = TRUE;
12062       entry->sparse = TRUE;
12063
12064       entry->caps =
12065           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12066           &codec);
12067       if (codec) {
12068         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12069             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12070         g_free (codec);
12071         codec = NULL;
12072       }
12073
12074       /* hunt for sort-of codec data */
12075       switch (fourcc) {
12076         case FOURCC_mp4s:
12077         {
12078           GNode *mp4s = NULL;
12079           GNode *esds = NULL;
12080
12081           /* look for palette in a stsd->mp4s->esds sub-atom */
12082           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12083           if (mp4s)
12084             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12085           if (esds == NULL) {
12086             /* Invalid STSD */
12087             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12088             break;
12089           }
12090
12091           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12092               stream->stream_tags);
12093           break;
12094         }
12095         default:
12096           GST_INFO_OBJECT (qtdemux,
12097               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12098           break;
12099       }
12100       GST_INFO_OBJECT (qtdemux,
12101           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12102           GST_FOURCC_ARGS (fourcc), entry->caps);
12103     } else {
12104       /* everything in 1 sample */
12105       entry->sampled = TRUE;
12106
12107       entry->caps =
12108           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12109           &codec);
12110
12111       if (entry->caps == NULL)
12112         goto unknown_stream;
12113
12114       if (codec) {
12115         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12116             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12117         g_free (codec);
12118         codec = NULL;
12119       }
12120     }
12121
12122     /* promote to sampled format */
12123     if (entry->fourcc == FOURCC_samr) {
12124       /* force mono 8000 Hz for AMR */
12125       entry->sampled = TRUE;
12126       entry->n_channels = 1;
12127       entry->rate = 8000;
12128     } else if (entry->fourcc == FOURCC_sawb) {
12129       /* force mono 16000 Hz for AMR-WB */
12130       entry->sampled = TRUE;
12131       entry->n_channels = 1;
12132       entry->rate = 16000;
12133     } else if (entry->fourcc == FOURCC_mp4a) {
12134       entry->sampled = TRUE;
12135     }
12136
12137
12138     stsd_entry_data += len;
12139     remaining_stsd_len -= len;
12140
12141   }
12142
12143   /* collect sample information */
12144   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12145     goto samples_failed;
12146
12147   if (qtdemux->fragmented) {
12148     guint64 offset;
12149
12150     /* need all moov samples as basis; probably not many if any at all */
12151     /* prevent moof parsing taking of at this time */
12152     offset = qtdemux->moof_offset;
12153     qtdemux->moof_offset = 0;
12154     if (stream->n_samples &&
12155         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12156       qtdemux->moof_offset = offset;
12157       goto samples_failed;
12158     }
12159     qtdemux->moof_offset = 0;
12160     /* movie duration more reliable in this case (e.g. mehd) */
12161     if (qtdemux->segment.duration &&
12162         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12163       stream->duration =
12164           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12165   }
12166
12167   /* configure segments */
12168   if (!qtdemux_parse_segments (qtdemux, stream, trak))
12169     goto segments_failed;
12170
12171   /* add some language tag, if useful */
12172   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12173       strcmp (stream->lang_id, "und")) {
12174     const gchar *lang_code;
12175
12176     /* convert ISO 639-2 code to ISO 639-1 */
12177     lang_code = gst_tag_get_language_code (stream->lang_id);
12178     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12179         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12180   }
12181
12182   /* Check for UDTA tags */
12183   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12184     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12185   }
12186
12187   /* now we are ready to add the stream */
12188   if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
12189     goto too_many_streams;
12190
12191   if (!qtdemux->got_moov) {
12192     qtdemux->streams[qtdemux->n_streams] = stream;
12193     qtdemux->n_streams++;
12194     GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
12195   }
12196
12197   return TRUE;
12198
12199 /* ERRORS */
12200 skip_track:
12201   {
12202     GST_INFO_OBJECT (qtdemux, "skip disabled track");
12203     if (new_stream)
12204       gst_qtdemux_stream_free (qtdemux, stream);
12205     return TRUE;
12206   }
12207 corrupt_file:
12208   {
12209     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12210         (_("This file is corrupt and cannot be played.")), (NULL));
12211     if (new_stream)
12212       gst_qtdemux_stream_free (qtdemux, stream);
12213     return FALSE;
12214   }
12215 error_encrypted:
12216   {
12217     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12218     if (new_stream)
12219       gst_qtdemux_stream_free (qtdemux, stream);
12220     return FALSE;
12221   }
12222 samples_failed:
12223 segments_failed:
12224   {
12225     /* we posted an error already */
12226     /* free stbl sub-atoms */
12227     gst_qtdemux_stbl_free (stream);
12228     if (new_stream)
12229       gst_qtdemux_stream_free (qtdemux, stream);
12230     return FALSE;
12231   }
12232 existing_stream:
12233   {
12234     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12235         track_id);
12236     if (new_stream)
12237       gst_qtdemux_stream_free (qtdemux, stream);
12238     return TRUE;
12239   }
12240 unknown_stream:
12241   {
12242     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12243         GST_FOURCC_ARGS (stream->subtype));
12244     if (new_stream)
12245       gst_qtdemux_stream_free (qtdemux, stream);
12246     return TRUE;
12247   }
12248 too_many_streams:
12249   {
12250     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
12251         (_("This file contains too many streams. Only playing first %d"),
12252             GST_QTDEMUX_MAX_STREAMS), (NULL));
12253     return TRUE;
12254   }
12255 }
12256
12257 /* If we can estimate the overall bitrate, and don't have information about the
12258  * stream bitrate for exactly one stream, this guesses the stream bitrate as
12259  * the overall bitrate minus the sum of the bitrates of all other streams. This
12260  * should be useful for the common case where we have one audio and one video
12261  * stream and can estimate the bitrate of one, but not the other. */
12262 static void
12263 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12264 {
12265   QtDemuxStream *stream = NULL;
12266   gint64 size, sys_bitrate, sum_bitrate = 0;
12267   GstClockTime duration;
12268   gint i;
12269   guint bitrate;
12270
12271   if (qtdemux->fragmented)
12272     return;
12273
12274   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12275
12276   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12277       || size <= 0) {
12278     GST_DEBUG_OBJECT (qtdemux,
12279         "Size in bytes of the stream not known - bailing");
12280     return;
12281   }
12282
12283   /* Subtract the header size */
12284   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12285       size, qtdemux->header_size);
12286
12287   if (size < qtdemux->header_size)
12288     return;
12289
12290   size = size - qtdemux->header_size;
12291
12292   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12293     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12294     return;
12295   }
12296
12297   for (i = 0; i < qtdemux->n_streams; i++) {
12298     switch (qtdemux->streams[i]->subtype) {
12299       case FOURCC_soun:
12300       case FOURCC_vide:
12301         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12302             CUR_STREAM (qtdemux->streams[i])->caps);
12303         /* retrieve bitrate, prefer avg then max */
12304         bitrate = 0;
12305         if (qtdemux->streams[i]->stream_tags) {
12306           gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
12307               GST_TAG_MAXIMUM_BITRATE, &bitrate);
12308           GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12309           gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
12310               GST_TAG_NOMINAL_BITRATE, &bitrate);
12311           GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12312           gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
12313               GST_TAG_BITRATE, &bitrate);
12314           GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12315         }
12316         if (bitrate)
12317           sum_bitrate += bitrate;
12318         else {
12319           if (stream) {
12320             GST_DEBUG_OBJECT (qtdemux,
12321                 ">1 stream with unknown bitrate - bailing");
12322             return;
12323           } else
12324             stream = qtdemux->streams[i];
12325         }
12326
12327       default:
12328         /* For other subtypes, we assume no significant impact on bitrate */
12329         break;
12330     }
12331   }
12332
12333   if (!stream) {
12334     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12335     return;
12336   }
12337
12338   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12339
12340   if (sys_bitrate < sum_bitrate) {
12341     /* This can happen, since sum_bitrate might be derived from maximum
12342      * bitrates and not average bitrates */
12343     GST_DEBUG_OBJECT (qtdemux,
12344         "System bitrate less than sum bitrate - bailing");
12345     return;
12346   }
12347
12348   bitrate = sys_bitrate - sum_bitrate;
12349   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12350       ", Stream bitrate = %u", sys_bitrate, bitrate);
12351
12352   if (!stream->stream_tags)
12353     stream->stream_tags = gst_tag_list_new_empty ();
12354   else
12355     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12356
12357   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12358       GST_TAG_BITRATE, bitrate, NULL);
12359 }
12360
12361 static GstFlowReturn
12362 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12363 {
12364   gint i;
12365   GstFlowReturn ret = GST_FLOW_OK;
12366
12367   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12368
12369   for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
12370     QtDemuxStream *stream = qtdemux->streams[i];
12371     guint32 sample_num = 0;
12372
12373     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
12374         i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12375
12376     if (qtdemux->fragmented) {
12377       /* need all moov samples first */
12378       GST_OBJECT_LOCK (qtdemux);
12379       while (stream->n_samples == 0)
12380         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12381           break;
12382       GST_OBJECT_UNLOCK (qtdemux);
12383     } else {
12384       /* discard any stray moof */
12385       qtdemux->moof_offset = 0;
12386     }
12387
12388     /* prepare braking */
12389     if (ret != GST_FLOW_ERROR)
12390       ret = GST_FLOW_OK;
12391
12392     /* in pull mode, we should have parsed some sample info by now;
12393      * and quite some code will not handle no samples.
12394      * in push mode, we'll just have to deal with it */
12395     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12396       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12397       gst_qtdemux_remove_stream (qtdemux, i);
12398       i--;
12399       continue;
12400     }
12401
12402     /* parse the initial sample for use in setting the frame rate cap */
12403     while (sample_num == 0 && sample_num < stream->n_samples) {
12404       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12405         break;
12406       ++sample_num;
12407     }
12408     if (stream->n_samples > 0 && stream->stbl_index >= 0) {
12409       stream->first_duration = stream->samples[0].duration;
12410       GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
12411           stream->track_id, stream->first_duration);
12412     }
12413   }
12414
12415   return ret;
12416 }
12417
12418 static GstFlowReturn
12419 qtdemux_expose_streams (GstQTDemux * qtdemux)
12420 {
12421   gint i;
12422   GSList *oldpads = NULL;
12423   GSList *iter;
12424
12425   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12426
12427   for (i = 0; i < qtdemux->n_streams; i++) {
12428     QtDemuxStream *stream = qtdemux->streams[i];
12429     GstPad *oldpad = stream->pad;
12430     GstTagList *list;
12431
12432     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
12433         i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12434
12435     if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
12436         stream->track_id == qtdemux->chapters_track_id) {
12437       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12438          so that it doesn't look like a subtitle track */
12439       gst_qtdemux_remove_stream (qtdemux, i);
12440       i--;
12441       continue;
12442     }
12443
12444     /* now we have all info and can expose */
12445     list = stream->stream_tags;
12446     stream->stream_tags = NULL;
12447     if (oldpad)
12448       oldpads = g_slist_prepend (oldpads, oldpad);
12449     if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12450       return GST_FLOW_ERROR;
12451   }
12452
12453   gst_qtdemux_guess_bitrate (qtdemux);
12454
12455   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12456
12457   for (iter = oldpads; iter; iter = g_slist_next (iter)) {
12458     GstPad *oldpad = iter->data;
12459     GstEvent *event;
12460
12461     event = gst_event_new_eos ();
12462     if (qtdemux->segment_seqnum)
12463       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12464
12465     gst_pad_push_event (oldpad, event);
12466     gst_pad_set_active (oldpad, FALSE);
12467     gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
12468     gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
12469     gst_object_unref (oldpad);
12470   }
12471
12472   /* check if we should post a redirect in case there is a single trak
12473    * and it is a redirecting trak */
12474   if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
12475     GstMessage *m;
12476
12477     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12478         "an external content");
12479     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12480         gst_structure_new ("redirect",
12481             "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
12482             NULL));
12483     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12484     qtdemux->posted_redirect = TRUE;
12485   }
12486
12487   for (i = 0; i < qtdemux->n_streams; i++) {
12488     QtDemuxStream *stream = qtdemux->streams[i];
12489
12490     qtdemux_do_allocation (qtdemux, stream);
12491   }
12492
12493   qtdemux->exposed = TRUE;
12494   return GST_FLOW_OK;
12495 }
12496
12497 /* check if major or compatible brand is 3GP */
12498 static inline gboolean
12499 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12500 {
12501   if (major) {
12502     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12503         FOURCC_3g__);
12504   } else if (qtdemux->comp_brands != NULL) {
12505     GstMapInfo map;
12506     guint8 *data;
12507     gsize size;
12508     gboolean res = FALSE;
12509
12510     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12511     data = map.data;
12512     size = map.size;
12513     while (size >= 4) {
12514       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12515           FOURCC_3g__);
12516       data += 4;
12517       size -= 4;
12518     }
12519     gst_buffer_unmap (qtdemux->comp_brands, &map);
12520     return res;
12521   } else {
12522     return FALSE;
12523   }
12524 }
12525
12526 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12527 static inline gboolean
12528 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12529 {
12530   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12531       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12532       || fourcc == FOURCC_albm;
12533 }
12534
12535 static void
12536 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12537     const char *tag, const char *dummy, GNode * node)
12538 {
12539   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12540   int offset;
12541   char *name;
12542   gchar *data;
12543   gdouble longitude, latitude, altitude;
12544   gint len;
12545
12546   len = QT_UINT32 (node->data);
12547   if (len <= 14)
12548     goto short_read;
12549
12550   data = node->data;
12551   offset = 14;
12552
12553   /* TODO: language code skipped */
12554
12555   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12556
12557   if (!name) {
12558     /* do not alarm in trivial case, but bail out otherwise */
12559     if (*(data + offset) != 0) {
12560       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12561           "giving up", tag);
12562     }
12563   } else {
12564     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12565         GST_TAG_GEO_LOCATION_NAME, name, NULL);
12566     offset += strlen (name);
12567     g_free (name);
12568   }
12569
12570   if (len < offset + 2 + 4 + 4 + 4)
12571     goto short_read;
12572
12573   /* +1 +1 = skip null-terminator and location role byte */
12574   offset += 1 + 1;
12575   /* table in spec says unsigned, semantics say negative has meaning ... */
12576   longitude = QT_SFP32 (data + offset);
12577
12578   offset += 4;
12579   latitude = QT_SFP32 (data + offset);
12580
12581   offset += 4;
12582   altitude = QT_SFP32 (data + offset);
12583
12584   /* one invalid means all are invalid */
12585   if (longitude >= -180.0 && longitude <= 180.0 &&
12586       latitude >= -90.0 && latitude <= 90.0) {
12587     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12588         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12589         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12590         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12591   }
12592
12593   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12594
12595   return;
12596
12597   /* ERRORS */
12598 short_read:
12599   {
12600     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12601     return;
12602   }
12603 }
12604
12605
12606 static void
12607 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12608     const char *tag, const char *dummy, GNode * node)
12609 {
12610   guint16 y;
12611   GDate *date;
12612   gint len;
12613
12614   len = QT_UINT32 (node->data);
12615   if (len < 14)
12616     return;
12617
12618   y = QT_UINT16 ((guint8 *) node->data + 12);
12619   if (y == 0) {
12620     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12621     return;
12622   }
12623   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12624
12625   date = g_date_new_dmy (1, 1, y);
12626   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12627   g_date_free (date);
12628 }
12629
12630 static void
12631 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12632     const char *tag, const char *dummy, GNode * node)
12633 {
12634   int offset;
12635   char *tag_str = NULL;
12636   guint8 *entity;
12637   guint16 table;
12638   gint len;
12639
12640   len = QT_UINT32 (node->data);
12641   if (len <= 20)
12642     goto short_read;
12643
12644   offset = 12;
12645   entity = (guint8 *) node->data + offset;
12646   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12647     GST_DEBUG_OBJECT (qtdemux,
12648         "classification info: %c%c%c%c invalid classification entity",
12649         entity[0], entity[1], entity[2], entity[3]);
12650     return;
12651   }
12652
12653   offset += 4;
12654   table = QT_UINT16 ((guint8 *) node->data + offset);
12655
12656   /* Language code skipped */
12657
12658   offset += 4;
12659
12660   /* Tag format: "XXXX://Y[YYYY]/classification info string"
12661    * XXXX: classification entity, fixed length 4 chars.
12662    * Y[YYYY]: classification table, max 5 chars.
12663    */
12664   tag_str = g_strdup_printf ("----://%u/%s",
12665       table, (char *) node->data + offset);
12666
12667   /* memcpy To be sure we're preserving byte order */
12668   memcpy (tag_str, entity, 4);
12669   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12670
12671   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12672
12673   g_free (tag_str);
12674
12675   return;
12676
12677   /* ERRORS */
12678 short_read:
12679   {
12680     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12681     return;
12682   }
12683 }
12684
12685 static gboolean
12686 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12687     const char *tag, const char *dummy, GNode * node)
12688 {
12689   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12690   GNode *data;
12691   char *s;
12692   int len;
12693   guint32 type;
12694   int offset;
12695   gboolean ret = TRUE;
12696   const gchar *charset = NULL;
12697
12698   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12699   if (data) {
12700     len = QT_UINT32 (data->data);
12701     type = QT_UINT32 ((guint8 *) data->data + 8);
12702     if (type == 0x00000001 && len > 16) {
12703       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12704           env_vars);
12705       if (s) {
12706         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12707         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12708         g_free (s);
12709       } else {
12710         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12711       }
12712     }
12713   } else {
12714     len = QT_UINT32 (node->data);
12715     type = QT_UINT32 ((guint8 *) node->data + 4);
12716     if ((type >> 24) == 0xa9 && len > 8 + 4) {
12717       gint str_len;
12718       gint lang_code;
12719
12720       /* Type starts with the (C) symbol, so the next data is a list
12721        * of (string size(16), language code(16), string) */
12722
12723       str_len = QT_UINT16 ((guint8 *) node->data + 8);
12724       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12725
12726       /* the string + fourcc + size + 2 16bit fields,
12727        * means that there are more tags in this atom */
12728       if (len > str_len + 8 + 4) {
12729         /* TODO how to represent the same tag in different languages? */
12730         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12731             "text alternatives, reading only first one");
12732       }
12733
12734       offset = 12;
12735       len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12736       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12737
12738       if (lang_code < 0x800) {  /* MAC encoded string */
12739         charset = "mac";
12740       }
12741     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12742             QT_FOURCC ((guint8 *) node->data + 4))) {
12743       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12744
12745       /* we go for 3GP style encoding if major brands claims so,
12746        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12747       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12748           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12749               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12750         offset = 14;
12751         /* 16-bit Language code is ignored here as well */
12752         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12753       } else {
12754         goto normal;
12755       }
12756     } else {
12757     normal:
12758       offset = 8;
12759       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12760       ret = FALSE;              /* may have to fallback */
12761     }
12762     if (charset) {
12763       GError *err = NULL;
12764
12765       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12766           charset, NULL, NULL, &err);
12767       if (err) {
12768         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12769             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12770             err->message);
12771         g_error_free (err);
12772       }
12773     } else {
12774       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12775           len - offset, env_vars);
12776     }
12777     if (s) {
12778       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12779       gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12780       g_free (s);
12781       ret = TRUE;
12782     } else {
12783       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12784     }
12785   }
12786   return ret;
12787 }
12788
12789 static void
12790 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12791     const char *tag, const char *dummy, GNode * node)
12792 {
12793   qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12794 }
12795
12796 static void
12797 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12798     const char *tag, const char *dummy, GNode * node)
12799 {
12800   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12801   guint8 *data;
12802   char *s, *t, *k = NULL;
12803   int len;
12804   int offset;
12805   int count;
12806
12807   /* first try normal string tag if major brand not 3GP */
12808   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12809     if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12810       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12811        * let's try it 3gpp way after minor safety check */
12812       data = node->data;
12813       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12814         return;
12815     } else
12816       return;
12817   }
12818
12819   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12820
12821   data = node->data;
12822
12823   len = QT_UINT32 (data);
12824   if (len < 15)
12825     goto short_read;
12826
12827   count = QT_UINT8 (data + 14);
12828   offset = 15;
12829   for (; count; count--) {
12830     gint slen;
12831
12832     if (offset + 1 > len)
12833       goto short_read;
12834     slen = QT_UINT8 (data + offset);
12835     offset += 1;
12836     if (offset + slen > len)
12837       goto short_read;
12838     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12839         slen, env_vars);
12840     if (s) {
12841       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12842       if (k) {
12843         t = g_strjoin (",", k, s, NULL);
12844         g_free (s);
12845         g_free (k);
12846         k = t;
12847       } else {
12848         k = s;
12849       }
12850     } else {
12851       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12852     }
12853     offset += slen;
12854   }
12855
12856 done:
12857   if (k) {
12858     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12859     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12860   }
12861   g_free (k);
12862
12863   return;
12864
12865   /* ERRORS */
12866 short_read:
12867   {
12868     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12869     goto done;
12870   }
12871 }
12872
12873 static void
12874 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12875     const char *tag1, const char *tag2, GNode * node)
12876 {
12877   GNode *data;
12878   int len;
12879   int type;
12880   int n1, n2;
12881
12882   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12883   if (data) {
12884     len = QT_UINT32 (data->data);
12885     type = QT_UINT32 ((guint8 *) data->data + 8);
12886     if (type == 0x00000000 && len >= 22) {
12887       n1 = QT_UINT16 ((guint8 *) data->data + 18);
12888       n2 = QT_UINT16 ((guint8 *) data->data + 20);
12889       if (n1 > 0) {
12890         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12891         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12892       }
12893       if (n2 > 0) {
12894         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12895         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12896       }
12897     }
12898   }
12899 }
12900
12901 static void
12902 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12903     const char *tag1, const char *dummy, GNode * node)
12904 {
12905   GNode *data;
12906   int len;
12907   int type;
12908   int n1;
12909
12910   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12911   if (data) {
12912     len = QT_UINT32 (data->data);
12913     type = QT_UINT32 ((guint8 *) data->data + 8);
12914     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12915     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12916     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12917       n1 = QT_UINT16 ((guint8 *) data->data + 16);
12918       if (n1) {
12919         /* do not add bpm=0 */
12920         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12921         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12922             NULL);
12923       }
12924     }
12925   }
12926 }
12927
12928 static void
12929 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12930     const char *tag1, const char *dummy, GNode * node)
12931 {
12932   GNode *data;
12933   int len;
12934   int type;
12935   guint32 num;
12936
12937   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12938   if (data) {
12939     len = QT_UINT32 (data->data);
12940     type = QT_UINT32 ((guint8 *) data->data + 8);
12941     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12942     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12943     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12944       num = QT_UINT32 ((guint8 *) data->data + 16);
12945       if (num) {
12946         /* do not add num=0 */
12947         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12948         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12949       }
12950     }
12951   }
12952 }
12953
12954 static void
12955 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12956     const char *tag1, const char *dummy, GNode * node)
12957 {
12958   GNode *data;
12959   int len;
12960   int type;
12961   GstSample *sample;
12962
12963   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12964   if (data) {
12965     len = QT_UINT32 (data->data);
12966     type = QT_UINT32 ((guint8 *) data->data + 8);
12967     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12968     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12969       GstTagImageType image_type;
12970
12971       if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12972         image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12973       else
12974         image_type = GST_TAG_IMAGE_TYPE_NONE;
12975
12976       if ((sample =
12977               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12978                   len - 16, image_type))) {
12979         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12980         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12981         gst_sample_unref (sample);
12982       }
12983     }
12984   }
12985 }
12986
12987 static void
12988 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12989     const char *tag, const char *dummy, GNode * node)
12990 {
12991   GNode *data;
12992   char *s;
12993   int len;
12994   int type;
12995
12996   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12997   if (data) {
12998     len = QT_UINT32 (data->data);
12999     type = QT_UINT32 ((guint8 *) data->data + 8);
13000     if (type == 0x00000001 && len > 16) {
13001       guint y, m = 1, d = 1;
13002       gint ret;
13003
13004       s = g_strndup ((char *) data->data + 16, len - 16);
13005       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13006       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13007       if (ret >= 1 && y > 1500 && y < 3000) {
13008         GDate *date;
13009
13010         date = g_date_new_dmy (d, m, y);
13011         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13012         g_date_free (date);
13013       } else {
13014         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13015       }
13016       g_free (s);
13017     }
13018   }
13019 }
13020
13021 static void
13022 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13023     const char *tag, const char *dummy, GNode * node)
13024 {
13025   GNode *data;
13026
13027   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13028
13029   /* re-route to normal string tag if major brand says so
13030    * or no data atom and compatible brand suggests so */
13031   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13032       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13033     qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13034     return;
13035   }
13036
13037   if (data) {
13038     guint len, type, n;
13039
13040     len = QT_UINT32 (data->data);
13041     type = QT_UINT32 ((guint8 *) data->data + 8);
13042     if (type == 0x00000000 && len >= 18) {
13043       n = QT_UINT16 ((guint8 *) data->data + 16);
13044       if (n > 0) {
13045         const gchar *genre;
13046
13047         genre = gst_tag_id3_genre_get (n - 1);
13048         if (genre != NULL) {
13049           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13050           gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13051         }
13052       }
13053     }
13054   }
13055 }
13056
13057 static void
13058 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13059     const gchar * tag, guint8 * data, guint32 datasize)
13060 {
13061   gdouble value;
13062   gchar *datacopy;
13063
13064   /* make a copy to have \0 at the end */
13065   datacopy = g_strndup ((gchar *) data, datasize);
13066
13067   /* convert the str to double */
13068   if (sscanf (datacopy, "%lf", &value) == 1) {
13069     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13070     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13071   } else {
13072     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13073         datacopy);
13074   }
13075   g_free (datacopy);
13076 }
13077
13078
13079 static void
13080 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13081     const char *tag, const char *tag_bis, GNode * node)
13082 {
13083   GNode *mean;
13084   GNode *name;
13085   GNode *data;
13086   guint32 meansize;
13087   guint32 namesize;
13088   guint32 datatype;
13089   guint32 datasize;
13090   const gchar *meanstr;
13091   const gchar *namestr;
13092
13093   /* checking the whole ---- atom size for consistency */
13094   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13095     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13096     return;
13097   }
13098
13099   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13100   if (!mean) {
13101     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13102     return;
13103   }
13104
13105   meansize = QT_UINT32 (mean->data);
13106   if (meansize <= 12) {
13107     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13108     return;
13109   }
13110   meanstr = ((gchar *) mean->data) + 12;
13111   meansize -= 12;
13112
13113   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13114   if (!name) {
13115     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13116     return;
13117   }
13118
13119   namesize = QT_UINT32 (name->data);
13120   if (namesize <= 12) {
13121     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13122     return;
13123   }
13124   namestr = ((gchar *) name->data) + 12;
13125   namesize -= 12;
13126
13127   /*
13128    * Data atom is:
13129    * uint32 - size
13130    * uint32 - name
13131    * uint8  - version
13132    * uint24 - data type
13133    * uint32 - all 0
13134    * rest   - the data
13135    */
13136   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13137   if (!data) {
13138     GST_WARNING_OBJECT (demux, "No data atom in this tag");
13139     return;
13140   }
13141   datasize = QT_UINT32 (data->data);
13142   if (datasize <= 16) {
13143     GST_WARNING_OBJECT (demux, "Data atom too small");
13144     return;
13145   }
13146   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13147
13148   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13149       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13150     static const struct
13151     {
13152       const gchar name[28];
13153       const gchar tag[28];
13154     } tags[] = {
13155       {
13156       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13157       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13158       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13159       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13160       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13161       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13162       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13163       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13164     };
13165     int i;
13166
13167     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13168       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13169         switch (gst_tag_get_type (tags[i].tag)) {
13170           case G_TYPE_DOUBLE:
13171             qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13172                 ((guint8 *) data->data) + 16, datasize - 16);
13173             break;
13174           case G_TYPE_STRING:
13175             qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13176             break;
13177           default:
13178             /* not reached */
13179             break;
13180         }
13181         break;
13182       }
13183     }
13184     if (i == G_N_ELEMENTS (tags))
13185       goto unknown_tag;
13186   } else {
13187     goto unknown_tag;
13188   }
13189
13190   return;
13191
13192 /* errors */
13193 unknown_tag:
13194 #ifndef GST_DISABLE_GST_DEBUG
13195   {
13196     gchar *namestr_dbg;
13197     gchar *meanstr_dbg;
13198
13199     meanstr_dbg = g_strndup (meanstr, meansize);
13200     namestr_dbg = g_strndup (namestr, namesize);
13201
13202     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13203         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13204
13205     g_free (namestr_dbg);
13206     g_free (meanstr_dbg);
13207   }
13208 #endif
13209   return;
13210 }
13211
13212 static void
13213 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13214     const char *tag_bis, GNode * node)
13215 {
13216   guint8 *data;
13217   GstBuffer *buf;
13218   guint len;
13219   GstTagList *id32_taglist = NULL;
13220
13221   GST_LOG_OBJECT (demux, "parsing ID32");
13222
13223   data = node->data;
13224   len = GST_READ_UINT32_BE (data);
13225
13226   /* need at least full box and language tag */
13227   if (len < 12 + 2)
13228     return;
13229
13230   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13231   gst_buffer_fill (buf, 0, data + 14, len - 14);
13232
13233   id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13234   if (id32_taglist) {
13235     GST_LOG_OBJECT (demux, "parsing ok");
13236     gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13237     gst_tag_list_unref (id32_taglist);
13238   } else {
13239     GST_LOG_OBJECT (demux, "parsing failed");
13240   }
13241
13242   gst_buffer_unref (buf);
13243 }
13244
13245 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13246     const char *tag, const char *tag_bis, GNode * node);
13247
13248 /* unmapped tags
13249 FOURCC_pcst -> if media is a podcast -> bool
13250 FOURCC_cpil -> if media is part of a compilation -> bool
13251 FOURCC_pgap -> if media is part of a gapless context -> bool
13252 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13253 */
13254
13255 static const struct
13256 {
13257   guint32 fourcc;
13258   const gchar *gst_tag;
13259   const gchar *gst_tag_bis;
13260   const GstQTDemuxAddTagFunc func;
13261 } add_funcs[] = {
13262   {
13263   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13264   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13265   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13266   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13267   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13268   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13269   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13270   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13271   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13272   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13273   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13274   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13275   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13276   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13277   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13278   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13279   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13280   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13281   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13282   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13283   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13284   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13285   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13286         qtdemux_tag_add_num}, {
13287   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13288         qtdemux_tag_add_num}, {
13289   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13290   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13291   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13292   FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13293   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13294   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13295   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13296   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13297   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13298   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13299   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13300   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13301   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13302   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13303   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13304   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13305   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13306   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13307         qtdemux_tag_add_classification}, {
13308   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13309   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13310   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13311
13312     /* This is a special case, some tags are stored in this
13313      * 'reverse dns naming', according to:
13314      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13315      * bug #614471
13316      */
13317   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13318     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13319   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13320 };
13321
13322 struct _GstQtDemuxTagList
13323 {
13324   GstQTDemux *demux;
13325   GstTagList *taglist;
13326 };
13327 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13328
13329 static void
13330 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13331 {
13332   gint len;
13333   guint8 *data;
13334   GstBuffer *buf;
13335   gchar *media_type;
13336   const gchar *style;
13337   GstSample *sample;
13338   GstStructure *s;
13339   guint i;
13340   guint8 ndata[4];
13341   GstQTDemux *demux = qtdemuxtaglist->demux;
13342   GstTagList *taglist = qtdemuxtaglist->taglist;
13343
13344   data = node->data;
13345   len = QT_UINT32 (data);
13346   buf = gst_buffer_new_and_alloc (len);
13347   gst_buffer_fill (buf, 0, data, len);
13348
13349   /* heuristic to determine style of tag */
13350   if (QT_FOURCC (data + 4) == FOURCC_____ ||
13351       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13352     style = "itunes";
13353   else if (demux->major_brand == FOURCC_qt__)
13354     style = "quicktime";
13355   /* fall back to assuming iso/3gp tag style */
13356   else
13357     style = "iso";
13358
13359   /* santize the name for the caps. */
13360   for (i = 0; i < 4; i++) {
13361     guint8 d = data[4 + i];
13362     if (g_ascii_isalnum (d))
13363       ndata[i] = g_ascii_tolower (d);
13364     else
13365       ndata[i] = '_';
13366   }
13367
13368   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13369       ndata[0], ndata[1], ndata[2], ndata[3]);
13370   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13371
13372   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13373   sample = gst_sample_new (buf, NULL, NULL, s);
13374   gst_buffer_unref (buf);
13375   g_free (media_type);
13376
13377   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13378       len, s);
13379
13380   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13381       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13382
13383   gst_sample_unref (sample);
13384 }
13385
13386 static void
13387 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13388 {
13389   GNode *meta;
13390   GNode *ilst;
13391   GNode *xmp_;
13392   GNode *node;
13393   gint i;
13394   GstQtDemuxTagList demuxtaglist;
13395
13396   demuxtaglist.demux = qtdemux;
13397   demuxtaglist.taglist = taglist;
13398
13399   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13400   if (meta != NULL) {
13401     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13402     if (ilst == NULL) {
13403       GST_LOG_OBJECT (qtdemux, "no ilst");
13404       return;
13405     }
13406   } else {
13407     ilst = udta;
13408     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13409   }
13410
13411   i = 0;
13412   while (i < G_N_ELEMENTS (add_funcs)) {
13413     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13414     if (node) {
13415       gint len;
13416
13417       len = QT_UINT32 (node->data);
13418       if (len < 12) {
13419         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13420             GST_FOURCC_ARGS (add_funcs[i].fourcc));
13421       } else {
13422         add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13423             add_funcs[i].gst_tag_bis, node);
13424       }
13425       g_node_destroy (node);
13426     } else {
13427       i++;
13428     }
13429   }
13430
13431   /* parsed nodes have been removed, pass along remainder as blob */
13432   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13433       (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13434
13435   /* parse up XMP_ node if existing */
13436   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13437   if (xmp_ != NULL) {
13438     GstBuffer *buf;
13439     GstTagList *xmptaglist;
13440
13441     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13442         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13443     xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13444     gst_buffer_unref (buf);
13445
13446     qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13447   } else {
13448     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13449   }
13450 }
13451
13452 typedef struct
13453 {
13454   GstStructure *structure;      /* helper for sort function */
13455   gchar *location;
13456   guint min_req_bitrate;
13457   guint min_req_qt_version;
13458 } GstQtReference;
13459
13460 static gint
13461 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13462 {
13463   GstQtReference *ref_a = (GstQtReference *) a;
13464   GstQtReference *ref_b = (GstQtReference *) b;
13465
13466   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13467     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13468
13469   /* known bitrates go before unknown; higher bitrates go first */
13470   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13471 }
13472
13473 /* sort the redirects and post a message for the application.
13474  */
13475 static void
13476 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13477 {
13478   GstQtReference *best;
13479   GstStructure *s;
13480   GstMessage *msg;
13481   GValue list_val = { 0, };
13482   GList *l;
13483
13484   g_assert (references != NULL);
13485
13486   references = g_list_sort (references, qtdemux_redirects_sort_func);
13487
13488   best = (GstQtReference *) references->data;
13489
13490   g_value_init (&list_val, GST_TYPE_LIST);
13491
13492   for (l = references; l != NULL; l = l->next) {
13493     GstQtReference *ref = (GstQtReference *) l->data;
13494     GValue struct_val = { 0, };
13495
13496     ref->structure = gst_structure_new ("redirect",
13497         "new-location", G_TYPE_STRING, ref->location, NULL);
13498
13499     if (ref->min_req_bitrate > 0) {
13500       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13501           ref->min_req_bitrate, NULL);
13502     }
13503
13504     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13505     g_value_set_boxed (&struct_val, ref->structure);
13506     gst_value_list_append_value (&list_val, &struct_val);
13507     g_value_unset (&struct_val);
13508     /* don't free anything here yet, since we need best->structure below */
13509   }
13510
13511   g_assert (best != NULL);
13512   s = gst_structure_copy (best->structure);
13513
13514   if (g_list_length (references) > 1) {
13515     gst_structure_set_value (s, "locations", &list_val);
13516   }
13517
13518   g_value_unset (&list_val);
13519
13520   for (l = references; l != NULL; l = l->next) {
13521     GstQtReference *ref = (GstQtReference *) l->data;
13522
13523     gst_structure_free (ref->structure);
13524     g_free (ref->location);
13525     g_free (ref);
13526   }
13527   g_list_free (references);
13528
13529   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13530   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13531   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13532   qtdemux->posted_redirect = TRUE;
13533 }
13534
13535 /* look for redirect nodes, collect all redirect information and
13536  * process it.
13537  */
13538 static gboolean
13539 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13540 {
13541   GNode *rmra, *rmda, *rdrf;
13542
13543   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13544   if (rmra) {
13545     GList *redirects = NULL;
13546
13547     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13548     while (rmda) {
13549       GstQtReference ref = { NULL, NULL, 0, 0 };
13550       GNode *rmdr, *rmvc;
13551
13552       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13553         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13554         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13555             ref.min_req_bitrate);
13556       }
13557
13558       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13559         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13560         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13561
13562 #ifndef GST_DISABLE_GST_DEBUG
13563         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13564 #endif
13565         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13566
13567         GST_LOG_OBJECT (qtdemux,
13568             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13569             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13570             bitmask, check_type);
13571         if (package == FOURCC_qtim && check_type == 0) {
13572           ref.min_req_qt_version = version;
13573         }
13574       }
13575
13576       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13577       if (rdrf) {
13578         guint32 ref_type;
13579         guint8 *ref_data;
13580         guint ref_len;
13581
13582         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13583         if (ref_len > 20) {
13584           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13585           ref_data = (guint8 *) rdrf->data + 20;
13586           if (ref_type == FOURCC_alis) {
13587             guint record_len, record_version, fn_len;
13588
13589             if (ref_len > 70) {
13590               /* MacOSX alias record, google for alias-layout.txt */
13591               record_len = QT_UINT16 (ref_data + 4);
13592               record_version = QT_UINT16 (ref_data + 4 + 2);
13593               fn_len = QT_UINT8 (ref_data + 50);
13594               if (record_len > 50 && record_version == 2 && fn_len > 0) {
13595                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13596               }
13597             } else {
13598               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13599                   ref_len);
13600             }
13601           } else if (ref_type == FOURCC_url_) {
13602             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13603           } else {
13604             GST_DEBUG_OBJECT (qtdemux,
13605                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13606                 GST_FOURCC_ARGS (ref_type));
13607           }
13608           if (ref.location != NULL) {
13609             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13610             redirects =
13611                 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13612           } else {
13613             GST_WARNING_OBJECT (qtdemux,
13614                 "Failed to extract redirect location from rdrf atom");
13615           }
13616         } else {
13617           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13618         }
13619       }
13620
13621       /* look for others */
13622       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13623     }
13624
13625     if (redirects != NULL) {
13626       qtdemux_process_redirects (qtdemux, redirects);
13627     }
13628   }
13629   return TRUE;
13630 }
13631
13632 static GstTagList *
13633 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13634 {
13635   const gchar *fmt;
13636
13637   if (tags == NULL) {
13638     tags = gst_tag_list_new_empty ();
13639     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13640   }
13641
13642   if (qtdemux->major_brand == FOURCC_mjp2)
13643     fmt = "Motion JPEG 2000";
13644   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13645     fmt = "3GP";
13646   else if (qtdemux->major_brand == FOURCC_qt__)
13647     fmt = "Quicktime";
13648   else if (qtdemux->fragmented)
13649     fmt = "ISO fMP4";
13650   else
13651     fmt = "ISO MP4/M4A";
13652
13653   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13654       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13655
13656   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13657       fmt, NULL);
13658
13659   return tags;
13660 }
13661
13662 /* we have read the complete moov node now.
13663  * This function parses all of the relevant info, creates the traks and
13664  * prepares all data structures for playback
13665  */
13666 static gboolean
13667 qtdemux_parse_tree (GstQTDemux * qtdemux)
13668 {
13669   GNode *mvhd;
13670   GNode *trak;
13671   GNode *udta;
13672   GNode *mvex;
13673   GstClockTime duration;
13674   GNode *pssh;
13675   guint64 creation_time;
13676   GstDateTime *datetime = NULL;
13677   gint version;
13678
13679   /* make sure we have a usable taglist */
13680   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13681
13682   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13683   if (mvhd == NULL) {
13684     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13685     return qtdemux_parse_redirects (qtdemux);
13686   }
13687
13688   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13689   if (version == 1) {
13690     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13691     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13692     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13693   } else if (version == 0) {
13694     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13695     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13696     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13697   } else {
13698     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13699     return FALSE;
13700   }
13701
13702   /* Moving qt creation time (secs since 1904) to unix time */
13703   if (creation_time != 0) {
13704     /* Try to use epoch first as it should be faster and more commonly found */
13705     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13706       GTimeVal now;
13707
13708       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13709       /* some data cleansing sanity */
13710       g_get_current_time (&now);
13711       if (now.tv_sec + 24 * 3600 < creation_time) {
13712         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13713       } else {
13714         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13715       }
13716     } else {
13717       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13718       GDateTime *dt, *dt_local;
13719
13720       dt = g_date_time_add_seconds (base_dt, creation_time);
13721       dt_local = g_date_time_to_local (dt);
13722       datetime = gst_date_time_new_from_g_date_time (dt_local);
13723
13724       g_date_time_unref (base_dt);
13725       g_date_time_unref (dt);
13726     }
13727   }
13728   if (datetime) {
13729     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13730     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13731         datetime, NULL);
13732     gst_date_time_unref (datetime);
13733   }
13734
13735   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13736   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13737
13738   /* check for fragmented file and get some (default) data */
13739   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13740   if (mvex) {
13741     GNode *mehd;
13742     GstByteReader mehd_data;
13743
13744     /* let track parsing or anyone know weird stuff might happen ... */
13745     qtdemux->fragmented = TRUE;
13746
13747     /* compensate for total duration */
13748     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13749     if (mehd)
13750       qtdemux_parse_mehd (qtdemux, &mehd_data);
13751   }
13752
13753   /* set duration in the segment info */
13754   gst_qtdemux_get_duration (qtdemux, &duration);
13755   if (duration) {
13756     qtdemux->segment.duration = duration;
13757     /* also do not exceed duration; stop is set that way post seek anyway,
13758      * and segment activation falls back to duration,
13759      * whereas loop only checks stop, so let's align this here as well */
13760     qtdemux->segment.stop = duration;
13761   }
13762
13763   /* parse all traks */
13764   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13765   while (trak) {
13766     qtdemux_parse_trak (qtdemux, trak);
13767     /* iterate all siblings */
13768     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13769   }
13770
13771   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13772
13773   /* find tags */
13774   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13775   if (udta) {
13776     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13777   } else {
13778     GST_LOG_OBJECT (qtdemux, "No udta node found.");
13779   }
13780
13781   /* maybe also some tags in meta box */
13782   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13783   if (udta) {
13784     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13785     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13786   } else {
13787     GST_LOG_OBJECT (qtdemux, "No meta node found.");
13788   }
13789
13790   /* parse any protection system info */
13791   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13792   while (pssh) {
13793     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13794     qtdemux_parse_pssh (qtdemux, pssh);
13795     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13796   }
13797
13798   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13799
13800   return TRUE;
13801 }
13802
13803 /* taken from ffmpeg */
13804 static int
13805 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13806 {
13807   int count = 4;
13808   int len = 0;
13809
13810   while (count--) {
13811     int c;
13812
13813     if (ptr >= end)
13814       return -1;
13815
13816     c = *ptr++;
13817     len = (len << 7) | (c & 0x7f);
13818     if (!(c & 0x80))
13819       break;
13820   }
13821   *end_out = ptr;
13822   return len;
13823 }
13824
13825 /* this can change the codec originally present in @list */
13826 static void
13827 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13828     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13829 {
13830   int len = QT_UINT32 (esds->data);
13831   guint8 *ptr = esds->data;
13832   guint8 *end = ptr + len;
13833   int tag;
13834   guint8 *data_ptr = NULL;
13835   int data_len = 0;
13836   guint8 object_type_id = 0;
13837   const char *codec_name = NULL;
13838   GstCaps *caps = NULL;
13839
13840   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13841   ptr += 8;
13842   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13843   ptr += 4;
13844   while (ptr + 1 < end) {
13845     tag = QT_UINT8 (ptr);
13846     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13847     ptr++;
13848     len = read_descr_size (ptr, end, &ptr);
13849     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13850
13851     /* Check the stated amount of data is available for reading */
13852     if (len < 0 || ptr + len > end)
13853       break;
13854
13855     switch (tag) {
13856       case ES_DESCRIPTOR_TAG:
13857         GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13858         GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13859         ptr += 3;
13860         break;
13861       case DECODER_CONFIG_DESC_TAG:{
13862         guint max_bitrate, avg_bitrate;
13863
13864         object_type_id = QT_UINT8 (ptr);
13865         max_bitrate = QT_UINT32 (ptr + 5);
13866         avg_bitrate = QT_UINT32 (ptr + 9);
13867         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13868         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13869         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13870         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13871         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13872         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13873           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13874               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13875         }
13876         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13877           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13878               avg_bitrate, NULL);
13879         }
13880         ptr += 13;
13881         break;
13882       }
13883       case DECODER_SPECIFIC_INFO_TAG:
13884         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13885         if (object_type_id == 0xe0 && len == 0x40) {
13886           guint8 *data;
13887           GstStructure *s;
13888           guint32 clut[16];
13889           gint i;
13890
13891           GST_DEBUG_OBJECT (qtdemux,
13892               "Have VOBSUB palette. Creating palette event");
13893           /* move to decConfigDescr data and read palette */
13894           data = ptr;
13895           for (i = 0; i < 16; i++) {
13896             clut[i] = QT_UINT32 (data);
13897             data += 4;
13898           }
13899
13900           s = gst_structure_new ("application/x-gst-dvd", "event",
13901               G_TYPE_STRING, "dvd-spu-clut-change",
13902               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13903               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13904               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13905               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13906               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13907               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13908               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13909               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13910               NULL);
13911
13912           /* store event and trigger custom processing */
13913           stream->pending_event =
13914               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13915         } else {
13916           /* Generic codec_data handler puts it on the caps */
13917           data_ptr = ptr;
13918           data_len = len;
13919         }
13920
13921         ptr += len;
13922         break;
13923       case SL_CONFIG_DESC_TAG:
13924         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13925         ptr += 1;
13926         break;
13927       default:
13928         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13929             tag);
13930         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13931         ptr += len;
13932         break;
13933     }
13934   }
13935
13936   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13937    * in use, and should also be used to override some other parameters for some
13938    * codecs. */
13939   switch (object_type_id) {
13940     case 0x20:                 /* MPEG-4 */
13941       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13942        * profile_and_level_indication */
13943       if (data_ptr != NULL && data_len >= 5 &&
13944           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13945         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13946             data_ptr + 4, data_len - 4);
13947       }
13948       break;                    /* Nothing special needed here */
13949     case 0x21:                 /* H.264 */
13950       codec_name = "H.264 / AVC";
13951       caps = gst_caps_new_simple ("video/x-h264",
13952           "stream-format", G_TYPE_STRING, "avc",
13953           "alignment", G_TYPE_STRING, "au", NULL);
13954       break;
13955     case 0x40:                 /* AAC (any) */
13956     case 0x66:                 /* AAC Main */
13957     case 0x67:                 /* AAC LC */
13958     case 0x68:                 /* AAC SSR */
13959       /* Override channels and rate based on the codec_data, as it's often
13960        * wrong. */
13961       /* Only do so for basic setup without HE-AAC extension */
13962       if (data_ptr && data_len == 2) {
13963         guint channels, rate;
13964
13965         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13966         if (channels > 0)
13967           entry->n_channels = channels;
13968
13969         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13970         if (rate > 0)
13971           entry->rate = rate;
13972       }
13973
13974       /* Set level and profile if possible */
13975       if (data_ptr != NULL && data_len >= 2) {
13976         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13977             data_ptr, data_len);
13978       } else {
13979         const gchar *profile_str = NULL;
13980         GstBuffer *buffer;
13981         GstMapInfo map;
13982         guint8 *codec_data;
13983         gint rate_idx, profile;
13984
13985         /* No codec_data, let's invent something.
13986          * FIXME: This is wrong for SBR! */
13987
13988         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13989
13990         buffer = gst_buffer_new_and_alloc (2);
13991         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13992         codec_data = map.data;
13993
13994         rate_idx =
13995             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
13996             (stream)->rate);
13997
13998         switch (object_type_id) {
13999           case 0x66:
14000             profile_str = "main";
14001             profile = 0;
14002             break;
14003           case 0x67:
14004             profile_str = "lc";
14005             profile = 1;
14006             break;
14007           case 0x68:
14008             profile_str = "ssr";
14009             profile = 2;
14010             break;
14011           default:
14012             profile = 3;
14013             break;
14014         }
14015
14016         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14017         codec_data[1] =
14018             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14019
14020         gst_buffer_unmap (buffer, &map);
14021         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14022             GST_TYPE_BUFFER, buffer, NULL);
14023         gst_buffer_unref (buffer);
14024
14025         if (profile_str) {
14026           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14027               G_TYPE_STRING, profile_str, NULL);
14028         }
14029       }
14030       break;
14031     case 0x60:                 /* MPEG-2, various profiles */
14032     case 0x61:
14033     case 0x62:
14034     case 0x63:
14035     case 0x64:
14036     case 0x65:
14037       codec_name = "MPEG-2 video";
14038       caps = gst_caps_new_simple ("video/mpeg",
14039           "mpegversion", G_TYPE_INT, 2,
14040           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14041       break;
14042     case 0x69:                 /* MPEG-2 BC audio */
14043     case 0x6B:                 /* MPEG-1 audio */
14044       caps = gst_caps_new_simple ("audio/mpeg",
14045           "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
14046       codec_name = "MPEG-1 audio";
14047       break;
14048     case 0x6A:                 /* MPEG-1 */
14049       codec_name = "MPEG-1 video";
14050       caps = gst_caps_new_simple ("video/mpeg",
14051           "mpegversion", G_TYPE_INT, 1,
14052           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14053       break;
14054     case 0x6C:                 /* MJPEG */
14055       caps =
14056           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14057           NULL);
14058       codec_name = "Motion-JPEG";
14059       break;
14060     case 0x6D:                 /* PNG */
14061       caps =
14062           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14063           NULL);
14064       codec_name = "PNG still images";
14065       break;
14066     case 0x6E:                 /* JPEG2000 */
14067       codec_name = "JPEG-2000";
14068       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14069       break;
14070     case 0xA4:                 /* Dirac */
14071       codec_name = "Dirac";
14072       caps = gst_caps_new_empty_simple ("video/x-dirac");
14073       break;
14074     case 0xA5:                 /* AC3 */
14075       codec_name = "AC-3 audio";
14076       caps = gst_caps_new_simple ("audio/x-ac3",
14077           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14078       break;
14079     case 0xA9:                 /* AC3 */
14080       codec_name = "DTS audio";
14081       caps = gst_caps_new_simple ("audio/x-dts",
14082           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14083       break;
14084     case 0xE1:                 /* QCELP */
14085       /* QCELP, the codec_data is a riff tag (little endian) with
14086        * 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). */
14087       caps = gst_caps_new_empty_simple ("audio/qcelp");
14088       codec_name = "QCELP";
14089       break;
14090     default:
14091       break;
14092   }
14093
14094   /* If we have a replacement caps, then change our caps for this stream */
14095   if (caps) {
14096     gst_caps_unref (entry->caps);
14097     entry->caps = caps;
14098   }
14099
14100   if (codec_name && list)
14101     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14102         GST_TAG_AUDIO_CODEC, codec_name, NULL);
14103
14104   /* Add the codec_data attribute to caps, if we have it */
14105   if (data_ptr) {
14106     GstBuffer *buffer;
14107
14108     buffer = gst_buffer_new_and_alloc (data_len);
14109     gst_buffer_fill (buffer, 0, data_ptr, data_len);
14110
14111     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14112     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14113
14114     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14115         buffer, NULL);
14116     gst_buffer_unref (buffer);
14117   }
14118
14119 }
14120
14121 static inline GstCaps *
14122 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14123 {
14124   GstCaps *caps;
14125   guint i;
14126   char *s, fourstr[5];
14127
14128   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14129   for (i = 0; i < 4; i++) {
14130     if (!g_ascii_isalnum (fourstr[i]))
14131       fourstr[i] = '_';
14132   }
14133   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14134   caps = gst_caps_new_empty_simple (s);
14135   g_free (s);
14136   return caps;
14137 }
14138
14139 #define _codec(name) \
14140   do { \
14141     if (codec_name) { \
14142       *codec_name = g_strdup (name); \
14143     } \
14144   } while (0)
14145
14146 static GstCaps *
14147 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14148     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14149     const guint8 * stsd_entry_data, gchar ** codec_name)
14150 {
14151   GstCaps *caps = NULL;
14152   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14153
14154   switch (fourcc) {
14155     case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
14156       _codec ("PNG still images");
14157       caps = gst_caps_new_empty_simple ("image/png");
14158       break;
14159     case FOURCC_jpeg:
14160       _codec ("JPEG still images");
14161       caps =
14162           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14163           NULL);
14164       break;
14165     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14166     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14167     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14168     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14169       _codec ("Motion-JPEG");
14170       caps =
14171           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14172           NULL);
14173       break;
14174     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14175       _codec ("Motion-JPEG format B");
14176       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14177       break;
14178     case FOURCC_mjp2:
14179       _codec ("JPEG-2000");
14180       /* override to what it should be according to spec, avoid palette_data */
14181       entry->bits_per_sample = 24;
14182       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14183       break;
14184     case FOURCC_SVQ3:
14185       _codec ("Sorensen video v.3");
14186       caps = gst_caps_new_simple ("video/x-svq",
14187           "svqversion", G_TYPE_INT, 3, NULL);
14188       break;
14189     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14190     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14191       _codec ("Sorensen video v.1");
14192       caps = gst_caps_new_simple ("video/x-svq",
14193           "svqversion", G_TYPE_INT, 1, NULL);
14194       break;
14195     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14196       caps = gst_caps_new_empty_simple ("video/x-raw");
14197       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14198       _codec ("Windows Raw RGB");
14199       stream->alignment = 32;
14200       break;
14201     case FOURCC_raw_:
14202     {
14203       guint16 bps;
14204
14205       bps = QT_UINT16 (stsd_entry_data + 82);
14206       switch (bps) {
14207         case 15:
14208           format = GST_VIDEO_FORMAT_RGB15;
14209           break;
14210         case 16:
14211           format = GST_VIDEO_FORMAT_RGB16;
14212           break;
14213         case 24:
14214           format = GST_VIDEO_FORMAT_RGB;
14215           break;
14216         case 32:
14217           format = GST_VIDEO_FORMAT_ARGB;
14218           break;
14219         default:
14220           /* unknown */
14221           break;
14222       }
14223       break;
14224     }
14225     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14226       format = GST_VIDEO_FORMAT_I420;
14227       break;
14228     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14229     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14230       format = GST_VIDEO_FORMAT_I420;
14231       break;
14232     case FOURCC_2vuy:
14233     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14234       format = GST_VIDEO_FORMAT_UYVY;
14235       break;
14236     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14237       format = GST_VIDEO_FORMAT_v308;
14238       break;
14239     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14240       format = GST_VIDEO_FORMAT_v216;
14241       break;
14242     case FOURCC_v210:
14243       format = GST_VIDEO_FORMAT_v210;
14244       break;
14245     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14246       format = GST_VIDEO_FORMAT_r210;
14247       break;
14248       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14249          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14250          format = GST_VIDEO_FORMAT_v410;
14251          break;
14252        */
14253       /* Packed YUV 4:4:4:4 8 bit in 32 bits
14254        * but different order than AYUV
14255        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14256        format = GST_VIDEO_FORMAT_v408;
14257        break;
14258        */
14259     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14260     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14261       _codec ("MPEG-1 video");
14262       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14263           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14264       break;
14265     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14266     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14267     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14268     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14269     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14270     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14271     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14272     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14273     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14274     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14275     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14276     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14277     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14278     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14279     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14280     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14281     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14282     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14283     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14284     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14285     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14286     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14287     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14288     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14289     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14290     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14291     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14292     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14293     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14294     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14295     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14296     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14297     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14298     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14299     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14300     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14301     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14302     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14303     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14304     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14305     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14306     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14307     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14308     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14309     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14310     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14311     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14312       _codec ("MPEG-2 video");
14313       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14314           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14315       break;
14316     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14317       _codec ("GIF still images");
14318       caps = gst_caps_new_empty_simple ("image/gif");
14319       break;
14320     case FOURCC_h263:
14321     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14322     case FOURCC_s263:
14323     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14324       _codec ("H.263");
14325       /* ffmpeg uses the height/width props, don't know why */
14326       caps = gst_caps_new_simple ("video/x-h263",
14327           "variant", G_TYPE_STRING, "itu", NULL);
14328       break;
14329     case FOURCC_mp4v:
14330     case FOURCC_MP4V:
14331       _codec ("MPEG-4 video");
14332       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14333           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14334       break;
14335     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14336     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14337       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
14338       caps = gst_caps_new_simple ("video/x-msmpeg",
14339           "msmpegversion", G_TYPE_INT, 43, NULL);
14340       break;
14341     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14342       _codec ("DivX 3");
14343       caps = gst_caps_new_simple ("video/x-divx",
14344           "divxversion", G_TYPE_INT, 3, NULL);
14345       break;
14346     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14347     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14348       _codec ("DivX 4");
14349       caps = gst_caps_new_simple ("video/x-divx",
14350           "divxversion", G_TYPE_INT, 4, NULL);
14351       break;
14352     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14353       _codec ("DivX 5");
14354       caps = gst_caps_new_simple ("video/x-divx",
14355           "divxversion", G_TYPE_INT, 5, NULL);
14356       break;
14357
14358     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14359       _codec ("FFV1");
14360       caps = gst_caps_new_simple ("video/x-ffv",
14361           "ffvversion", G_TYPE_INT, 1, NULL);
14362       break;
14363
14364     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14365     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14366     case FOURCC_XVID:
14367     case FOURCC_xvid:
14368     case FOURCC_FMP4:
14369     case FOURCC_fmp4:
14370     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14371       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14372           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14373       _codec ("MPEG-4");
14374       break;
14375
14376     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14377       _codec ("Cinepak");
14378       caps = gst_caps_new_empty_simple ("video/x-cinepak");
14379       break;
14380     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14381       _codec ("Apple QuickDraw");
14382       caps = gst_caps_new_empty_simple ("video/x-qdrw");
14383       break;
14384     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14385       _codec ("Apple video");
14386       caps = gst_caps_new_empty_simple ("video/x-apple-video");
14387       break;
14388     case FOURCC_H264:
14389     case FOURCC_avc1:
14390       _codec ("H.264 / AVC");
14391       caps = gst_caps_new_simple ("video/x-h264",
14392           "stream-format", G_TYPE_STRING, "avc",
14393           "alignment", G_TYPE_STRING, "au", NULL);
14394       break;
14395     case FOURCC_avc3:
14396       _codec ("H.264 / AVC");
14397       caps = gst_caps_new_simple ("video/x-h264",
14398           "stream-format", G_TYPE_STRING, "avc3",
14399           "alignment", G_TYPE_STRING, "au", NULL);
14400       break;
14401     case FOURCC_H265:
14402     case FOURCC_hvc1:
14403       _codec ("H.265 / HEVC");
14404       caps = gst_caps_new_simple ("video/x-h265",
14405           "stream-format", G_TYPE_STRING, "hvc1",
14406           "alignment", G_TYPE_STRING, "au", NULL);
14407       break;
14408     case FOURCC_hev1:
14409       _codec ("H.265 / HEVC");
14410       caps = gst_caps_new_simple ("video/x-h265",
14411           "stream-format", G_TYPE_STRING, "hev1",
14412           "alignment", G_TYPE_STRING, "au", NULL);
14413       break;
14414     case FOURCC_rle_:
14415       _codec ("Run-length encoding");
14416       caps = gst_caps_new_simple ("video/x-rle",
14417           "layout", G_TYPE_STRING, "quicktime", NULL);
14418       break;
14419     case FOURCC_WRLE:
14420       _codec ("Run-length encoding");
14421       caps = gst_caps_new_simple ("video/x-rle",
14422           "layout", G_TYPE_STRING, "microsoft", NULL);
14423       break;
14424     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14425     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14426       _codec ("Indeo Video 3");
14427       caps = gst_caps_new_simple ("video/x-indeo",
14428           "indeoversion", G_TYPE_INT, 3, NULL);
14429       break;
14430     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14431     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14432       _codec ("Intel Video 4");
14433       caps = gst_caps_new_simple ("video/x-indeo",
14434           "indeoversion", G_TYPE_INT, 4, NULL);
14435       break;
14436     case FOURCC_dvcp:
14437     case FOURCC_dvc_:
14438     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14439     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14440     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14441     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14442     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14443     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14444       _codec ("DV Video");
14445       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14446           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14447       break;
14448     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
14449     case FOURCC_dv5p:          /* DVCPRO50 PAL */
14450       _codec ("DVCPro50 Video");
14451       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14452           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14453       break;
14454     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14455     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14456       _codec ("DVCProHD Video");
14457       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14458           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14459       break;
14460     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14461       _codec ("Apple Graphics (SMC)");
14462       caps = gst_caps_new_empty_simple ("video/x-smc");
14463       break;
14464     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14465       _codec ("VP3");
14466       caps = gst_caps_new_empty_simple ("video/x-vp3");
14467       break;
14468     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14469       _codec ("VP6 Flash");
14470       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14471       break;
14472     case FOURCC_XiTh:
14473       _codec ("Theora");
14474       caps = gst_caps_new_empty_simple ("video/x-theora");
14475       /* theora uses one byte of padding in the data stream because it does not
14476        * allow 0 sized packets while theora does */
14477       entry->padding = 1;
14478       break;
14479     case FOURCC_drac:
14480       _codec ("Dirac");
14481       caps = gst_caps_new_empty_simple ("video/x-dirac");
14482       break;
14483     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14484       _codec ("TIFF still images");
14485       caps = gst_caps_new_empty_simple ("image/tiff");
14486       break;
14487     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14488       _codec ("Apple Intermediate Codec");
14489       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14490       break;
14491     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14492       _codec ("AVID DNxHD");
14493       caps = gst_caps_from_string ("video/x-dnxhd");
14494       break;
14495     case FOURCC_VP80:
14496       _codec ("On2 VP8");
14497       caps = gst_caps_from_string ("video/x-vp8");
14498       break;
14499     case FOURCC_apcs:
14500       _codec ("Apple ProRes LT");
14501       caps =
14502           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14503           NULL);
14504       break;
14505     case FOURCC_apch:
14506       _codec ("Apple ProRes HQ");
14507       caps =
14508           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14509           NULL);
14510       break;
14511     case FOURCC_apcn:
14512       _codec ("Apple ProRes");
14513       caps =
14514           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14515           "standard", NULL);
14516       break;
14517     case FOURCC_apco:
14518       _codec ("Apple ProRes Proxy");
14519       caps =
14520           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14521           "proxy", NULL);
14522       break;
14523     case FOURCC_ap4h:
14524       _codec ("Apple ProRes 4444");
14525       caps =
14526           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14527           "4444", NULL);
14528       break;
14529     case FOURCC_ap4x:
14530       _codec ("Apple ProRes 4444 XQ");
14531       caps =
14532           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14533           "4444xq", NULL);
14534       break;
14535     case FOURCC_cfhd:
14536       _codec ("GoPro CineForm");
14537       caps = gst_caps_from_string ("video/x-cineform");
14538       break;
14539     case FOURCC_vc_1:
14540     case FOURCC_ovc1:
14541       _codec ("VC-1");
14542       caps = gst_caps_new_simple ("video/x-wmv",
14543           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14544       break;
14545     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14546     default:
14547     {
14548       caps = _get_unknown_codec_name ("video", fourcc);
14549       break;
14550     }
14551   }
14552
14553   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14554     GstVideoInfo info;
14555
14556     gst_video_info_init (&info);
14557     gst_video_info_set_format (&info, format, entry->width, entry->height);
14558
14559     caps = gst_video_info_to_caps (&info);
14560     *codec_name = gst_pb_utils_get_codec_description (caps);
14561
14562     /* enable clipping for raw video streams */
14563     stream->need_clip = TRUE;
14564     stream->alignment = 32;
14565   }
14566
14567   return caps;
14568 }
14569
14570 static guint
14571 round_up_pow2 (guint n)
14572 {
14573   n = n - 1;
14574   n = n | (n >> 1);
14575   n = n | (n >> 2);
14576   n = n | (n >> 4);
14577   n = n | (n >> 8);
14578   n = n | (n >> 16);
14579   return n + 1;
14580 }
14581
14582 static GstCaps *
14583 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14584     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14585     int len, gchar ** codec_name)
14586 {
14587   GstCaps *caps;
14588   const GstStructure *s;
14589   const gchar *name;
14590   gint endian = 0;
14591   GstAudioFormat format = 0;
14592   gint depth;
14593
14594   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14595
14596   depth = entry->bytes_per_packet * 8;
14597
14598   switch (fourcc) {
14599     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14600     case FOURCC_raw_:
14601       /* 8-bit audio is unsigned */
14602       if (depth == 8)
14603         format = GST_AUDIO_FORMAT_U8;
14604       /* otherwise it's signed and big-endian just like 'twos' */
14605     case FOURCC_twos:
14606       endian = G_BIG_ENDIAN;
14607       /* fall-through */
14608     case FOURCC_sowt:
14609     {
14610       gchar *str;
14611
14612       if (!endian)
14613         endian = G_LITTLE_ENDIAN;
14614
14615       if (!format)
14616         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14617
14618       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14619       _codec (str);
14620       g_free (str);
14621
14622       caps = gst_caps_new_simple ("audio/x-raw",
14623           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14624           "layout", G_TYPE_STRING, "interleaved", NULL);
14625       stream->alignment = GST_ROUND_UP_8 (depth);
14626       stream->alignment = round_up_pow2 (stream->alignment);
14627       break;
14628     }
14629     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14630       _codec ("Raw 64-bit floating-point audio");
14631       caps = gst_caps_new_simple ("audio/x-raw",
14632           "format", G_TYPE_STRING, "F64BE",
14633           "layout", G_TYPE_STRING, "interleaved", NULL);
14634       stream->alignment = 8;
14635       break;
14636     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14637       _codec ("Raw 32-bit floating-point audio");
14638       caps = gst_caps_new_simple ("audio/x-raw",
14639           "format", G_TYPE_STRING, "F32BE",
14640           "layout", G_TYPE_STRING, "interleaved", NULL);
14641       stream->alignment = 4;
14642       break;
14643     case FOURCC_in24:
14644       _codec ("Raw 24-bit PCM audio");
14645       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14646        * endian later */
14647       caps = gst_caps_new_simple ("audio/x-raw",
14648           "format", G_TYPE_STRING, "S24BE",
14649           "layout", G_TYPE_STRING, "interleaved", NULL);
14650       stream->alignment = 4;
14651       break;
14652     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14653       _codec ("Raw 32-bit PCM audio");
14654       caps = gst_caps_new_simple ("audio/x-raw",
14655           "format", G_TYPE_STRING, "S32BE",
14656           "layout", G_TYPE_STRING, "interleaved", NULL);
14657       stream->alignment = 4;
14658       break;
14659     case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14660       _codec ("Raw 16-bit PCM audio");
14661       caps = gst_caps_new_simple ("audio/x-raw",
14662           "format", G_TYPE_STRING, "S16LE",
14663           "layout", G_TYPE_STRING, "interleaved", NULL);
14664       stream->alignment = 2;
14665       break;
14666     case FOURCC_ulaw:
14667       _codec ("Mu-law audio");
14668       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14669       break;
14670     case FOURCC_alaw:
14671       _codec ("A-law audio");
14672       caps = gst_caps_new_empty_simple ("audio/x-alaw");
14673       break;
14674     case 0x0200736d:
14675     case 0x6d730002:
14676       _codec ("Microsoft ADPCM");
14677       /* Microsoft ADPCM-ACM code 2 */
14678       caps = gst_caps_new_simple ("audio/x-adpcm",
14679           "layout", G_TYPE_STRING, "microsoft", NULL);
14680       break;
14681     case 0x1100736d:
14682     case 0x6d730011:
14683       _codec ("DVI/IMA ADPCM");
14684       caps = gst_caps_new_simple ("audio/x-adpcm",
14685           "layout", G_TYPE_STRING, "dvi", NULL);
14686       break;
14687     case 0x1700736d:
14688     case 0x6d730017:
14689       _codec ("DVI/Intel IMA ADPCM");
14690       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14691       caps = gst_caps_new_simple ("audio/x-adpcm",
14692           "layout", G_TYPE_STRING, "quicktime", NULL);
14693       break;
14694     case 0x5500736d:
14695     case 0x6d730055:
14696       /* MPEG layer 3, CBR only (pre QT4.1) */
14697     case FOURCC__mp3:
14698       _codec ("MPEG-1 layer 3");
14699       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14700       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14701           "mpegversion", G_TYPE_INT, 1, NULL);
14702       break;
14703     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14704       _codec ("MPEG-1 layer 2");
14705       /* MPEG layer 2 */
14706       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14707           "mpegversion", G_TYPE_INT, 1, NULL);
14708       break;
14709     case 0x20736d:
14710     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14711       _codec ("EAC-3 audio");
14712       caps = gst_caps_new_simple ("audio/x-eac3",
14713           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14714       entry->sampled = TRUE;
14715       break;
14716     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14717     case FOURCC_ac_3:
14718       _codec ("AC-3 audio");
14719       caps = gst_caps_new_simple ("audio/x-ac3",
14720           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14721       entry->sampled = TRUE;
14722       break;
14723     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14724     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14725       _codec ("DTS audio");
14726       caps = gst_caps_new_simple ("audio/x-dts",
14727           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14728       entry->sampled = TRUE;
14729       break;
14730     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14731     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14732       _codec ("DTS-HD audio");
14733       caps = gst_caps_new_simple ("audio/x-dts",
14734           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14735       entry->sampled = TRUE;
14736       break;
14737     case FOURCC_MAC3:
14738       _codec ("MACE-3");
14739       caps = gst_caps_new_simple ("audio/x-mace",
14740           "maceversion", G_TYPE_INT, 3, NULL);
14741       break;
14742     case FOURCC_MAC6:
14743       _codec ("MACE-6");
14744       caps = gst_caps_new_simple ("audio/x-mace",
14745           "maceversion", G_TYPE_INT, 6, NULL);
14746       break;
14747     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14748       /* ogg/vorbis */
14749       caps = gst_caps_new_empty_simple ("application/ogg");
14750       break;
14751     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14752       _codec ("DV audio");
14753       caps = gst_caps_new_empty_simple ("audio/x-dv");
14754       break;
14755     case FOURCC_mp4a:
14756       _codec ("MPEG-4 AAC audio");
14757       caps = gst_caps_new_simple ("audio/mpeg",
14758           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14759           "stream-format", G_TYPE_STRING, "raw", NULL);
14760       break;
14761     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14762       _codec ("QDesign Music");
14763       caps = gst_caps_new_empty_simple ("audio/x-qdm");
14764       break;
14765     case FOURCC_QDM2:
14766       _codec ("QDesign Music v.2");
14767       /* FIXME: QDesign music version 2 (no constant) */
14768       if (FALSE && data) {
14769         caps = gst_caps_new_simple ("audio/x-qdm2",
14770             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14771             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14772             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14773       } else {
14774         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14775       }
14776       break;
14777     case FOURCC_agsm:
14778       _codec ("GSM audio");
14779       caps = gst_caps_new_empty_simple ("audio/x-gsm");
14780       break;
14781     case FOURCC_samr:
14782       _codec ("AMR audio");
14783       caps = gst_caps_new_empty_simple ("audio/AMR");
14784       break;
14785     case FOURCC_sawb:
14786       _codec ("AMR-WB audio");
14787       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14788       break;
14789     case FOURCC_ima4:
14790       _codec ("Quicktime IMA ADPCM");
14791       caps = gst_caps_new_simple ("audio/x-adpcm",
14792           "layout", G_TYPE_STRING, "quicktime", NULL);
14793       break;
14794     case FOURCC_alac:
14795       _codec ("Apple lossless audio");
14796       caps = gst_caps_new_empty_simple ("audio/x-alac");
14797       break;
14798     case FOURCC_fLaC:
14799       _codec ("Free Lossless Audio Codec");
14800       caps = gst_caps_new_simple ("audio/x-flac",
14801           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14802       break;
14803     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14804       _codec ("QualComm PureVoice");
14805       caps = gst_caps_from_string ("audio/qcelp");
14806       break;
14807     case FOURCC_wma_:
14808     case FOURCC_owma:
14809       _codec ("WMA");
14810       caps = gst_caps_new_empty_simple ("audio/x-wma");
14811       break;
14812     case FOURCC_opus:
14813       _codec ("Opus");
14814       caps = gst_caps_new_empty_simple ("audio/x-opus");
14815       break;
14816     case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14817     {
14818       guint32 flags = 0;
14819       guint32 depth = 0;
14820       guint32 width = 0;
14821       GstAudioFormat format;
14822       enum
14823       {
14824         FLAG_IS_FLOAT = 0x1,
14825         FLAG_IS_BIG_ENDIAN = 0x2,
14826         FLAG_IS_SIGNED = 0x4,
14827         FLAG_IS_PACKED = 0x8,
14828         FLAG_IS_ALIGNED_HIGH = 0x10,
14829         FLAG_IS_NON_INTERLEAVED = 0x20
14830       };
14831       _codec ("Raw LPCM audio");
14832
14833       if (data && len >= 56) {
14834         depth = QT_UINT32 (data + 40);
14835         flags = QT_UINT32 (data + 44);
14836         width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14837       }
14838       if ((flags & FLAG_IS_FLOAT) == 0) {
14839         if (depth == 0)
14840           depth = 16;
14841         if (width == 0)
14842           width = 16;
14843         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14844             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14845             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14846         caps = gst_caps_new_simple ("audio/x-raw",
14847             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14848             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14849             "non-interleaved" : "interleaved", NULL);
14850         stream->alignment = GST_ROUND_UP_8 (depth);
14851         stream->alignment = round_up_pow2 (stream->alignment);
14852       } else {
14853         if (width == 0)
14854           width = 32;
14855         if (width == 64) {
14856           if (flags & FLAG_IS_BIG_ENDIAN)
14857             format = GST_AUDIO_FORMAT_F64BE;
14858           else
14859             format = GST_AUDIO_FORMAT_F64LE;
14860         } else {
14861           if (flags & FLAG_IS_BIG_ENDIAN)
14862             format = GST_AUDIO_FORMAT_F32BE;
14863           else
14864             format = GST_AUDIO_FORMAT_F32LE;
14865         }
14866         caps = gst_caps_new_simple ("audio/x-raw",
14867             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14868             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14869             "non-interleaved" : "interleaved", NULL);
14870         stream->alignment = width / 8;
14871       }
14872       break;
14873     }
14874     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14875       /* ? */
14876     default:
14877     {
14878       caps = _get_unknown_codec_name ("audio", fourcc);
14879       break;
14880     }
14881   }
14882
14883   if (caps) {
14884     GstCaps *templ_caps =
14885         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14886     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14887     gst_caps_unref (caps);
14888     gst_caps_unref (templ_caps);
14889     caps = intersection;
14890   }
14891
14892   /* enable clipping for raw audio streams */
14893   s = gst_caps_get_structure (caps, 0);
14894   name = gst_structure_get_name (s);
14895   if (g_str_has_prefix (name, "audio/x-raw")) {
14896     stream->need_clip = TRUE;
14897     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14898     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14899   }
14900   return caps;
14901 }
14902
14903 static GstCaps *
14904 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14905     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14906     const guint8 * stsd_entry_data, gchar ** codec_name)
14907 {
14908   GstCaps *caps;
14909
14910   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14911
14912   switch (fourcc) {
14913     case FOURCC_mp4s:
14914       _codec ("DVD subtitle");
14915       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14916       stream->need_process = TRUE;
14917       break;
14918     case FOURCC_text:
14919       _codec ("Quicktime timed text");
14920       goto text;
14921     case FOURCC_tx3g:
14922       _codec ("3GPP timed text");
14923     text:
14924       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14925           "utf8", NULL);
14926       /* actual text piece needs to be extracted */
14927       stream->need_process = TRUE;
14928       break;
14929     case FOURCC_stpp:
14930       _codec ("XML subtitles");
14931       caps = gst_caps_new_empty_simple ("application/ttml+xml");
14932       break;
14933     default:
14934     {
14935       caps = _get_unknown_codec_name ("text", fourcc);
14936       break;
14937     }
14938   }
14939   return caps;
14940 }
14941
14942 static GstCaps *
14943 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14944     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14945     const guint8 * stsd_entry_data, gchar ** codec_name)
14946 {
14947   GstCaps *caps;
14948
14949   switch (fourcc) {
14950     case FOURCC_m1v:
14951       _codec ("MPEG 1 video");
14952       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14953           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14954       break;
14955     default:
14956       caps = NULL;
14957       break;
14958   }
14959   return caps;
14960 }
14961
14962 static void
14963 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14964     const gchar * system_id)
14965 {
14966   gint i;
14967
14968   if (!qtdemux->protection_system_ids)
14969     qtdemux->protection_system_ids =
14970         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14971   /* Check whether we already have an entry for this system ID. */
14972   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14973     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14974     if (g_ascii_strcasecmp (system_id, id) == 0) {
14975       return;
14976     }
14977   }
14978   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14979   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
14980           -1));
14981 }