f801b8fa88ea469c0c8338b330543e55c9a04cfe
[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 = (char *) malloc (value_length);
2816
2817   if (*value == NULL) {
2818     GST_ERROR_OBJECT (qtdemux, "error: malloc failed\n");
2819     return;
2820   }
2821
2822   strncpy (*value, value_start, value_length);
2823
2824   return;
2825 }
2826
2827 static void
2828 _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
2829     const char *xml_str, const char *param_name, gboolean * value)
2830 {
2831   char *value_start, *value_end;
2832   int value_length = 0;
2833
2834   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2835
2836   if (!value_start) {
2837     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2838         param_name);
2839     return;
2840   }
2841
2842   value_start += strlen (param_name);
2843   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2844     value_start++;
2845
2846   value_end = strchr (value_start, '<');
2847   if (!value_end) {
2848     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2849     return;
2850   }
2851
2852   value_length = value_end - value_start;
2853   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2854           || (value_start[value_length - 1] == '\t')))
2855     value_length--;
2856
2857   if (value_length < 1) {
2858     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2859     return;
2860   }
2861
2862   *value = strstr (value_start, "true") ? TRUE : FALSE;
2863
2864   return;
2865 }
2866
2867 static void
2868 _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux, const char *xmlStr)
2869 {
2870   const char is_spherical_str[] = "<GSpherical:Spherical>";
2871   const char is_stitched_str[] = "<GSpherical:Stitched>";
2872   const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
2873   const char projection_type_str[] = "<GSpherical:ProjectionType>";
2874   const char stereo_mode_str[] = "<GSpherical:StereoMode>";
2875   const char source_count_str[] = "<GSpherical:SourceCount>";
2876   const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
2877   const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
2878   const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
2879   const char timestamp_str[] = "<GSpherical:Timestamp>";
2880   const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
2881   const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
2882   const char cropped_area_image_width_str[] =
2883       "<GSpherical:CroppedAreaImageWidthPixels>";
2884   const char cropped_area_image_height_str[] =
2885       "<GSpherical:CroppedAreaImageHeightPixels>";
2886   const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
2887   const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
2888
2889   QtDemuxSphericalMetadata * spherical_metadata = qtdemux->spherical_metadata;
2890
2891   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
2892       (gboolean *) & spherical_metadata->is_spherical);
2893   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
2894       (gboolean *) & spherical_metadata->is_stitched);
2895
2896   if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
2897     _get_string_value_from_xml_string (qtdemux, xmlStr,
2898         stitching_software_str, &spherical_metadata->stitching_software);
2899     _get_string_value_from_xml_string (qtdemux, xmlStr,
2900         projection_type_str, &spherical_metadata->projection_type);
2901     _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
2902         &spherical_metadata->stereo_mode);
2903     _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
2904         &spherical_metadata->source_count);
2905     _get_int_value_from_xml_string (qtdemux, xmlStr,
2906         init_view_heading_str, &spherical_metadata->init_view_heading);
2907     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
2908         &spherical_metadata->init_view_pitch);
2909     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
2910         &spherical_metadata->init_view_roll);
2911     _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
2912         &spherical_metadata->timestamp);
2913     _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
2914         &spherical_metadata->full_pano_width_pixels);
2915     _get_int_value_from_xml_string (qtdemux, xmlStr,
2916         full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
2917     _get_int_value_from_xml_string (qtdemux, xmlStr,
2918         cropped_area_image_width_str,
2919         &spherical_metadata->cropped_area_image_width);
2920     _get_int_value_from_xml_string (qtdemux, xmlStr,
2921         cropped_area_image_height_str,
2922         &spherical_metadata->cropped_area_image_height);
2923     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
2924         &spherical_metadata->cropped_area_left);
2925     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
2926         &spherical_metadata->cropped_area_top);
2927   }
2928
2929   return;
2930 }
2931
2932 static void
2933 gst_tag_register_spherical_tags (void) {
2934   gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
2935       G_TYPE_INT,
2936       _("tag-spherical"),
2937       _("Flag indicating if the video is a spherical video"),
2938       NULL);
2939   gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
2940       G_TYPE_INT,
2941       _("tag-stitched"),
2942       _("Flag indicating if the video is stitched"),
2943       NULL);
2944   gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
2945       G_TYPE_STRING,
2946       _("tag-stitching-software"),
2947       _("Software used to stitch the spherical video"),
2948       NULL);
2949   gst_tag_register ("projection_type", GST_TAG_FLAG_META,
2950       G_TYPE_STRING,
2951       _("tag-projection-type"),
2952       _("Projection type used in the video frames"),
2953       NULL);
2954   gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
2955       G_TYPE_STRING,
2956       _("tag-stereo-mode"),
2957       _("Description of stereoscopic 3D layout"),
2958       NULL);
2959   gst_tag_register ("source_count", GST_TAG_FLAG_META,
2960       G_TYPE_INT,
2961       _("tag-source-count"),
2962       _("Number of cameras used to create the spherical video"),
2963       NULL);
2964   gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
2965       G_TYPE_INT,
2966       _("tag-init-view-heading"),
2967       _("The heading angle of the initial view in degrees"),
2968       NULL);
2969   gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
2970       G_TYPE_INT,
2971       _("tag-init-view-pitch"),
2972       _("The pitch angle of the initial view in degrees"),
2973       NULL);
2974   gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
2975       G_TYPE_INT,
2976       _("tag-init-view-roll"),
2977       _("The roll angle of the initial view in degrees"),
2978       NULL);
2979   gst_tag_register ("timestamp", GST_TAG_FLAG_META,
2980       G_TYPE_INT,
2981       _("tag-timestamp"),
2982       _("Epoch timestamp of when the first frame in the video was recorded"),
2983       NULL);
2984   gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
2985       G_TYPE_INT,
2986       _("tag-full-pano-width"),
2987       _("Width of the encoded video frame in pixels"),
2988       NULL);
2989   gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
2990       G_TYPE_INT,
2991       _("tag-full-pano-height"),
2992       _("Height of the encoded video frame in pixels"),
2993       NULL);
2994   gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
2995       G_TYPE_INT,
2996       _("tag-cropped-area-image-width"),
2997       _("Width of the video frame to display (e.g. cropping)"),
2998       NULL);
2999   gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
3000       G_TYPE_INT,
3001       _("tag-cropped-area-image-height"),
3002       _("Height of the video frame to display (e.g. cropping)"),
3003       NULL);
3004   gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
3005       G_TYPE_INT,
3006       _("tag-cropped-area-left"),
3007       _("Column where the left edge of the image was cropped from the"
3008           " full sized panorama"),
3009       NULL);
3010   gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
3011       G_TYPE_INT,
3012       _("tag-cropped-area-top"),
3013       _("Row where the top edge of the image was cropped from the"
3014           " full sized panorama"),
3015       NULL);
3016   gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
3017       G_TYPE_INT,
3018       _("tag-ambisonic-type"),
3019       _("Specifies the type of ambisonic audio represented"),
3020       NULL);
3021   gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
3022       G_TYPE_INT,
3023       _("tag-ambisonic-format"),
3024       _("Specifies the ambisonic audio format"),
3025       NULL);
3026   gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
3027       G_TYPE_INT,
3028       _("tag-ambisonic-order"),
3029       _("Specifies the ambisonic audio channel order"),
3030       NULL);
3031
3032   return;
3033 }
3034
3035 static void
3036 _send_spherical_metadata_msg_to_bus (GstQTDemux * qtdemux)
3037 {
3038   GstTagList *taglist;
3039   QtDemuxSphericalMetadata *spherical_metadata = qtdemux->spherical_metadata;
3040
3041   GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
3042       spherical_metadata->is_spherical);
3043   GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
3044       spherical_metadata->is_stitched);
3045   GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
3046       spherical_metadata->stitching_software);
3047   GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
3048       spherical_metadata->projection_type);
3049   GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
3050       spherical_metadata->stereo_mode);
3051   GST_DEBUG_OBJECT (qtdemux, "source_count %d",
3052       spherical_metadata->source_count);
3053   GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
3054       spherical_metadata->init_view_heading);
3055   GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
3056       spherical_metadata->init_view_pitch);
3057   GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
3058       spherical_metadata->init_view_roll);
3059   GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
3060   GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
3061       spherical_metadata->full_pano_width_pixels);
3062   GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
3063       spherical_metadata->full_pano_height_pixels);
3064   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
3065       spherical_metadata->cropped_area_image_width);
3066   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
3067       spherical_metadata->cropped_area_image_height);
3068   GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
3069       spherical_metadata->cropped_area_left);
3070   GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
3071       spherical_metadata->cropped_area_top);
3072   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
3073       spherical_metadata->ambisonic_type);
3074   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
3075       spherical_metadata->ambisonic_order);
3076   GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
3077       spherical_metadata->ambisonic_format);
3078
3079   taglist = gst_tag_list_new_empty ();
3080   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3081       "is_spherical", spherical_metadata->is_spherical,
3082       "is_stitched", spherical_metadata->is_stitched,
3083       "source_count", spherical_metadata->source_count,
3084       "init_view_heading", spherical_metadata->init_view_heading,
3085       "init_view_pitch", spherical_metadata->init_view_pitch,
3086       "init_view_roll", spherical_metadata->init_view_roll,
3087       "timestamp", spherical_metadata->timestamp,
3088       "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
3089       "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
3090       "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
3091       "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
3092       "cropped_area_left", spherical_metadata->cropped_area_left,
3093       "cropped_area_top", spherical_metadata->cropped_area_top,
3094       "ambisonic_type", spherical_metadata->ambisonic_type,
3095       "ambisonic_format", spherical_metadata->ambisonic_format,
3096       "ambisonic_order", spherical_metadata->ambisonic_order,
3097       NULL);
3098
3099   if (spherical_metadata->stitching_software)
3100     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3101         "stitching_software", spherical_metadata->stitching_software,
3102         NULL);
3103   if (spherical_metadata->projection_type)
3104     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3105         "projection_type", spherical_metadata->projection_type,
3106         NULL);
3107   if (spherical_metadata->stereo_mode)
3108     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
3109         "stereo_mode", spherical_metadata->stereo_mode,
3110         NULL);
3111
3112   gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
3113           gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
3114                   gst_tag_list_copy (taglist)));
3115
3116   gst_tag_list_unref(taglist);
3117
3118   return;
3119 }
3120
3121 static void
3122 qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3123 {
3124   guint offset = 0;
3125
3126   guint8 version = 0;
3127   guint8 ambisonic_type  = 0;
3128   guint32 ambisonic_order = 0;
3129   guint8 ambisonic_channel_ordering = 0;
3130   guint8 ambisonic_normalization = 0;
3131   guint32 num_channels = 0;
3132   guint32 channel_map[49] = { 0 };      /* Up to 6th order */
3133
3134   int i;
3135
3136   GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
3137
3138   qtdemux->header_size += length;
3139   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3140
3141   if (length <= offset + 16) {
3142     GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
3143     return;
3144   }
3145
3146   version = QT_UINT8 (buffer + offset);
3147   ambisonic_type = QT_UINT8 (buffer + offset + 1);
3148   ambisonic_order = QT_UINT32 (buffer + offset + 2);
3149   ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
3150   ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
3151   num_channels = QT_UINT32 (buffer + offset + 8);
3152   for (i = 0; i < num_channels; ++i)
3153     channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
3154
3155   GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
3156   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
3157   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
3158   GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
3159       ambisonic_channel_ordering);
3160   GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
3161       ambisonic_normalization);
3162   GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
3163   for (i = 0; i < num_channels; ++i)
3164     GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
3165
3166   if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
3167     if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
3168       qtdemux->spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
3169
3170     if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
3171       if (num_channels == 4) {
3172         qtdemux->spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
3173
3174         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
3175             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
3176             && (channel_map[0] == 0) && (channel_map[1] == 1)
3177             && (channel_map[2] == 2) && (channel_map[3] == 3))
3178           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
3179
3180         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
3181             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
3182             && (channel_map[0] == 0) && (channel_map[1] == 3)
3183             && (channel_map[2] == 1) && (channel_map[3] == 2))
3184           qtdemux->spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
3185       }
3186     }
3187   }
3188
3189   return;
3190 }
3191 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3192
3193 static void
3194 qtdemux_parse_piff (GstQTDemux * qtdemux, const guint8 * buffer, gint length,
3195     guint offset)
3196 {
3197   GstByteReader br;
3198   guint8 version;
3199   guint32 flags = 0;
3200   guint i;
3201   guint8 iv_size = 8;
3202   QtDemuxStream *stream;
3203   GstStructure *structure;
3204   QtDemuxCencSampleSetInfo *ss_info = NULL;
3205   const gchar *system_id;
3206   gboolean uses_sub_sample_encryption = FALSE;
3207
3208   if (qtdemux->n_streams == 0)
3209     return;
3210
3211   stream = qtdemux->streams[0];
3212
3213   structure = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
3214   if (!gst_structure_has_name (structure, "application/x-cenc")) {
3215     GST_WARNING_OBJECT (qtdemux,
3216         "Attempting PIFF box parsing on an unencrypted stream.");
3217     return;
3218   }
3219
3220   gst_structure_get (structure, GST_PROTECTION_SYSTEM_ID_CAPS_FIELD,
3221       G_TYPE_STRING, &system_id, NULL);
3222   gst_qtdemux_append_protection_system_id (qtdemux, system_id);
3223
3224   stream->protected = TRUE;
3225   stream->protection_scheme_type = FOURCC_cenc;
3226
3227   if (!stream->protection_scheme_info)
3228     stream->protection_scheme_info = g_new0 (QtDemuxCencSampleSetInfo, 1);
3229
3230   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3231
3232   if (ss_info->default_properties)
3233     gst_structure_free (ss_info->default_properties);
3234
3235   ss_info->default_properties =
3236       gst_structure_new ("application/x-cenc",
3237       "iv_size", G_TYPE_UINT, iv_size, "encrypted", G_TYPE_BOOLEAN, TRUE, NULL);
3238
3239   if (ss_info->crypto_info) {
3240     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3241     g_ptr_array_free (ss_info->crypto_info, TRUE);
3242     ss_info->crypto_info = NULL;
3243   }
3244
3245   /* skip UUID */
3246   gst_byte_reader_init (&br, buffer + offset + 16, length - offset - 16);
3247
3248   if (!gst_byte_reader_get_uint8 (&br, &version)) {
3249     GST_ERROR_OBJECT (qtdemux, "Error getting box's version field");
3250     return;
3251   }
3252
3253   if (!gst_byte_reader_get_uint24_be (&br, &flags)) {
3254     GST_ERROR_OBJECT (qtdemux, "Error getting box's flags field");
3255     return;
3256   }
3257
3258   if ((flags & 0x000001)) {
3259     guint32 algorithm_id = 0;
3260     const guint8 *kid;
3261     GstBuffer *kid_buf;
3262     gboolean is_encrypted = TRUE;
3263
3264     if (!gst_byte_reader_get_uint24_le (&br, &algorithm_id)) {
3265       GST_ERROR_OBJECT (qtdemux, "Error getting box's algorithm ID field");
3266       return;
3267     }
3268
3269     algorithm_id >>= 8;
3270     if (algorithm_id == 0) {
3271       is_encrypted = FALSE;
3272     } else if (algorithm_id == 1) {
3273       /* FIXME: maybe store this in properties? */
3274       GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CTR encrypted stream");
3275     } else if (algorithm_id == 2) {
3276       /* FIXME: maybe store this in properties? */
3277       GST_DEBUG_OBJECT (qtdemux, "AES 128-bits CBC encrypted stream");
3278     }
3279
3280     if (!gst_byte_reader_get_uint8 (&br, &iv_size))
3281       return;
3282
3283     if (!gst_byte_reader_get_data (&br, 16, &kid))
3284       return;
3285
3286     kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
3287     gst_buffer_fill (kid_buf, 0, kid, 16);
3288     if (ss_info->default_properties)
3289       gst_structure_free (ss_info->default_properties);
3290     ss_info->default_properties =
3291         gst_structure_new ("application/x-cenc",
3292         "iv_size", G_TYPE_UINT, iv_size,
3293         "encrypted", G_TYPE_BOOLEAN, is_encrypted,
3294         "kid", GST_TYPE_BUFFER, kid_buf, NULL);
3295     GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
3296         "is_encrypted=%u, iv_size=%u", is_encrypted, iv_size);
3297     gst_buffer_unref (kid_buf);
3298   } else if ((flags & 0x000002)) {
3299     uses_sub_sample_encryption = TRUE;
3300   }
3301
3302   if (!gst_byte_reader_get_uint32_be (&br, &qtdemux->cenc_aux_sample_count)) {
3303     GST_ERROR_OBJECT (qtdemux, "Error getting box's sample count field");
3304     return;
3305   }
3306
3307   ss_info->crypto_info =
3308       g_ptr_array_new_full (qtdemux->cenc_aux_sample_count,
3309       (GDestroyNotify) qtdemux_gst_structure_free);
3310
3311   for (i = 0; i < qtdemux->cenc_aux_sample_count; ++i) {
3312     GstStructure *properties;
3313     guint8 *data;
3314     GstBuffer *buf;
3315
3316     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3317     if (properties == NULL) {
3318       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3319       return;
3320     }
3321
3322     if (!gst_byte_reader_dup_data (&br, iv_size, &data)) {
3323       GST_ERROR_OBJECT (qtdemux, "IV data not present for sample %u", i);
3324       gst_structure_free (properties);
3325       return;
3326     }
3327     buf = gst_buffer_new_wrapped (data, iv_size);
3328     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3329     gst_buffer_unref (buf);
3330
3331     if (uses_sub_sample_encryption) {
3332       guint16 n_subsamples;
3333
3334       if (!gst_byte_reader_get_uint16_be (&br, &n_subsamples)
3335           || n_subsamples == 0) {
3336         GST_ERROR_OBJECT (qtdemux,
3337             "failed to get subsample count for sample %u", i);
3338         gst_structure_free (properties);
3339         return;
3340       }
3341       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3342       if (!gst_byte_reader_dup_data (&br, n_subsamples * 6, &data)) {
3343         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3344             i);
3345         gst_structure_free (properties);
3346         return;
3347       }
3348       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3349       gst_structure_set (properties,
3350           "subsample_count", G_TYPE_UINT, n_subsamples,
3351           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3352       gst_buffer_unref (buf);
3353     } else {
3354       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3355     }
3356
3357     g_ptr_array_add (ss_info->crypto_info, properties);
3358   }
3359 }
3360
3361 static void
3362 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3363 {
3364   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
3365     0x97, 0xA9, 0x42, 0xE8,
3366     0x9C, 0x71, 0x99, 0x94,
3367     0x91, 0xE3, 0xAF, 0xAC
3368   };
3369   static const guint8 playready_uuid[] = {
3370     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
3371     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
3372   };
3373
3374   static const guint8 piff_sample_encryption_uuid[] = {
3375     0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
3376     0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
3377   };
3378
3379 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3380   static const guint8 spherical_uuid[] = {
3381     0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
3382     0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd
3383   };
3384 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3385
3386   guint offset;
3387
3388   /* counts as header data */
3389   qtdemux->header_size += length;
3390
3391   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
3392
3393   if (length <= offset + 16) {
3394     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
3395     return;
3396   }
3397
3398 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
3399   if (memcmp (buffer + offset, spherical_uuid, 16) == 0) {
3400     const char *contents;
3401
3402     GST_DEBUG_OBJECT (qtdemux, "spherical uuid was found");
3403     contents = (char *) (buffer + offset + 16);
3404     GST_DEBUG_OBJECT (qtdemux, "contents: %s\n", contents);
3405
3406     if (qtdemux->spherical_metadata)
3407       _parse_spatial_video_metadata_from_xml_string (qtdemux, contents);
3408
3409     return;
3410   }
3411 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
3412
3413   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
3414     GstBuffer *buf;
3415     GstTagList *taglist;
3416
3417     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
3418         length - offset - 16, NULL);
3419     taglist = gst_tag_list_from_xmp_buffer (buf);
3420     gst_buffer_unref (buf);
3421
3422     /* make sure we have a usable taglist */
3423     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
3424
3425     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
3426
3427   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3428     int len;
3429     const gunichar2 *s_utf16;
3430     char *contents;
3431
3432     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3433     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3434     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3435     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3436
3437     g_free (contents);
3438
3439     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3440         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3441         (NULL));
3442   } else if (memcmp (buffer + offset, piff_sample_encryption_uuid, 16) == 0) {
3443     qtdemux_parse_piff (qtdemux, buffer, length, offset);
3444   } else {
3445     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3446         GST_READ_UINT32_LE (buffer + offset),
3447         GST_READ_UINT32_LE (buffer + offset + 4),
3448         GST_READ_UINT32_LE (buffer + offset + 8),
3449         GST_READ_UINT32_LE (buffer + offset + 12));
3450   }
3451 }
3452
3453 static void
3454 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3455 {
3456   GstSidxParser sidx_parser;
3457   GstIsoffParserResult res;
3458   guint consumed;
3459
3460   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3461
3462   res =
3463       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3464       &consumed);
3465   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3466   if (res == GST_ISOFF_QT_PARSER_DONE) {
3467     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3468   }
3469   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3470 }
3471
3472 /* caller verifies at least 8 bytes in buf */
3473 static void
3474 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3475     guint64 * plength, guint32 * pfourcc)
3476 {
3477   guint64 length;
3478   guint32 fourcc;
3479
3480   length = QT_UINT32 (data);
3481   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3482   fourcc = QT_FOURCC (data + 4);
3483   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3484
3485   if (length == 0) {
3486     length = G_MAXUINT64;
3487   } else if (length == 1 && size >= 16) {
3488     /* this means we have an extended size, which is the 64 bit value of
3489      * the next 8 bytes */
3490     length = QT_UINT64 (data + 8);
3491     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3492   }
3493
3494   if (plength)
3495     *plength = length;
3496   if (pfourcc)
3497     *pfourcc = fourcc;
3498 }
3499
3500 static gboolean
3501 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3502 {
3503   guint32 version = 0;
3504   GstClockTime duration = 0;
3505
3506   if (!gst_byte_reader_get_uint32_be (br, &version))
3507     goto failed;
3508
3509   version >>= 24;
3510   if (version == 1) {
3511     if (!gst_byte_reader_get_uint64_be (br, &duration))
3512       goto failed;
3513   } else {
3514     guint32 dur = 0;
3515
3516     if (!gst_byte_reader_get_uint32_be (br, &dur))
3517       goto failed;
3518     duration = dur;
3519   }
3520
3521   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3522   qtdemux->duration = duration;
3523
3524   return TRUE;
3525
3526 failed:
3527   {
3528     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3529     return FALSE;
3530   }
3531 }
3532
3533 static gboolean
3534 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3535     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3536 {
3537   if (!stream->parsed_trex && qtdemux->moov_node) {
3538     GNode *mvex, *trex;
3539     GstByteReader trex_data;
3540
3541     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3542     if (mvex) {
3543       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3544           &trex_data);
3545       while (trex) {
3546         guint32 id = 0, sdi = 0, dur = 0, size = 0, flags = 0;
3547
3548         /* skip version/flags */
3549         if (!gst_byte_reader_skip (&trex_data, 4))
3550           goto next;
3551         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3552           goto next;
3553         if (id != stream->track_id)
3554           goto next;
3555         if (!gst_byte_reader_get_uint32_be (&trex_data, &sdi))
3556           goto next;
3557         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3558           goto next;
3559         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3560           goto next;
3561         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3562           goto next;
3563
3564         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3565             "duration %d,  size %d, flags 0x%x", stream->track_id,
3566             dur, size, flags);
3567
3568         stream->parsed_trex = TRUE;
3569         stream->def_sample_description_index = sdi;
3570         stream->def_sample_duration = dur;
3571         stream->def_sample_size = size;
3572         stream->def_sample_flags = flags;
3573
3574       next:
3575         /* iterate all siblings */
3576         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3577             &trex_data);
3578       }
3579     }
3580   }
3581
3582   *ds_duration = stream->def_sample_duration;
3583   *ds_size = stream->def_sample_size;
3584   *ds_flags = stream->def_sample_flags;
3585
3586   /* even then, above values are better than random ... */
3587   if (G_UNLIKELY (!stream->parsed_trex)) {
3588     GST_WARNING_OBJECT (qtdemux,
3589         "failed to find fragment defaults for stream %d", stream->track_id);
3590     return FALSE;
3591   }
3592
3593   return TRUE;
3594 }
3595
3596 /* This method should be called whenever a more accurate duration might
3597  * have been found. It will update all relevant variables if/where needed
3598  */
3599 static void
3600 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3601 {
3602   guint i;
3603   guint64 movdur;
3604   GstClockTime prevdur;
3605
3606   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3607
3608   if (movdur > qtdemux->duration) {
3609     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3610     GST_DEBUG_OBJECT (qtdemux,
3611         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3612         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3613     qtdemux->duration = movdur;
3614     GST_DEBUG_OBJECT (qtdemux,
3615         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3616         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3617         GST_TIME_ARGS (qtdemux->segment.stop));
3618     if (qtdemux->segment.duration == prevdur) {
3619       /* If the current segment has duration/stop identical to previous duration
3620        * update them also (because they were set at that point in time with
3621        * the wrong duration */
3622       /* We convert the value *from* the timescale version to avoid rounding errors */
3623       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3624       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3625       qtdemux->segment.duration = fixeddur;
3626       qtdemux->segment.stop = fixeddur;
3627     }
3628   }
3629   for (i = 0; i < qtdemux->n_streams; i++) {
3630     QtDemuxStream *stream = qtdemux->streams[i];
3631     if (stream) {
3632       movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3633       if (movdur > stream->duration) {
3634         GST_DEBUG_OBJECT (qtdemux,
3635             "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3636             GST_TIME_ARGS (duration));
3637         stream->duration = movdur;
3638         if (stream->dummy_segment) {
3639           /* Update all dummy values to new duration */
3640           stream->segments[0].stop_time = duration;
3641           stream->segments[0].duration = duration;
3642           stream->segments[0].media_stop = duration;
3643
3644           /* let downstream know we possibly have a new stop time */
3645           if (stream->segment_index != -1) {
3646             GstClockTime pos;
3647
3648             if (qtdemux->segment.rate >= 0) {
3649               pos = stream->segment.start;
3650             } else {
3651               pos = stream->segment.stop;
3652             }
3653
3654             gst_qtdemux_stream_update_segment (qtdemux, stream,
3655                 stream->segment_index, pos, NULL, NULL);
3656           }
3657         }
3658       }
3659     }
3660   }
3661 }
3662
3663 static gboolean
3664 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3665     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3666     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3667     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts,
3668     gboolean has_tfdt)
3669 {
3670   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3671   guint64 timestamp;
3672   gint32 data_offset = 0;
3673   guint32 flags = 0, first_flags = 0, samples_count = 0;
3674   gint i;
3675   guint8 *data;
3676   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3677   QtDemuxSample *sample;
3678   gboolean ismv = FALSE;
3679   gint64 initial_offset;
3680
3681   GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3682       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3683       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3684       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3685
3686   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3687     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3688     return TRUE;
3689   }
3690
3691   /* presence of stss or not can't really tell us much,
3692    * and flags and so on tend to be marginally reliable in these files */
3693   if (stream->subtype == FOURCC_soun) {
3694     GST_DEBUG_OBJECT (qtdemux,
3695         "sound track in fragmented file; marking all keyframes");
3696     stream->all_keyframe = TRUE;
3697   }
3698
3699   if (!gst_byte_reader_skip (trun, 1) ||
3700       !gst_byte_reader_get_uint24_be (trun, &flags))
3701     goto fail;
3702
3703   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3704     goto fail;
3705
3706   if (flags & TR_DATA_OFFSET) {
3707     /* note this is really signed */
3708     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3709       goto fail;
3710     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3711     /* default base offset = first byte of moof */
3712     if (*base_offset == -1) {
3713       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3714       *base_offset = moof_offset;
3715     }
3716     *running_offset = *base_offset + data_offset;
3717   } else {
3718     /* if no offset at all, that would mean data starts at moof start,
3719      * which is a bit wrong and is ismv crappy way, so compensate
3720      * assuming data is in mdat following moof */
3721     if (*base_offset == -1) {
3722       *base_offset = moof_offset + moof_length + 8;
3723       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3724       ismv = TRUE;
3725     }
3726     if (*running_offset == -1)
3727       *running_offset = *base_offset;
3728   }
3729
3730   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3731       *running_offset);
3732   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3733       data_offset, flags, samples_count);
3734
3735   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3736     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3737       GST_DEBUG_OBJECT (qtdemux,
3738           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3739       flags ^= TR_FIRST_SAMPLE_FLAGS;
3740     } else {
3741       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3742         goto fail;
3743       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3744     }
3745   }
3746
3747   /* FIXME ? spec says other bits should also be checked to determine
3748    * entry size (and prefix size for that matter) */
3749   entry_size = 0;
3750   dur_offset = size_offset = 0;
3751   if (flags & TR_SAMPLE_DURATION) {
3752     GST_LOG_OBJECT (qtdemux, "entry duration present");
3753     dur_offset = entry_size;
3754     entry_size += 4;
3755   }
3756   if (flags & TR_SAMPLE_SIZE) {
3757     GST_LOG_OBJECT (qtdemux, "entry size present");
3758     size_offset = entry_size;
3759     entry_size += 4;
3760   }
3761   if (flags & TR_SAMPLE_FLAGS) {
3762     GST_LOG_OBJECT (qtdemux, "entry flags present");
3763     flags_offset = entry_size;
3764     entry_size += 4;
3765   }
3766   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3767     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3768     ct_offset = entry_size;
3769     entry_size += 4;
3770   }
3771
3772   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3773     goto fail;
3774   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3775
3776   if (stream->n_samples + samples_count >=
3777       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3778     goto index_too_big;
3779
3780   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3781       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3782       (stream->n_samples + samples_count) *
3783       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3784
3785   /* create a new array of samples if it's the first sample parsed */
3786   if (stream->n_samples == 0) {
3787     g_assert (stream->samples == NULL);
3788     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3789     /* or try to reallocate it with space enough to insert the new samples */
3790   } else
3791     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3792         stream->n_samples + samples_count);
3793   if (stream->samples == NULL)
3794     goto out_of_memory;
3795
3796   if (qtdemux->fragment_start != -1) {
3797     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3798     qtdemux->fragment_start = -1;
3799   } else {
3800     if (stream->n_samples == 0) {
3801       if (decode_ts > 0) {
3802         timestamp = decode_ts;
3803       } else if (stream->pending_seek != NULL) {
3804         /* if we don't have a timestamp from a tfdt box, we'll use the one
3805          * from the mfra seek table */
3806         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3807             GST_TIME_ARGS (stream->pending_seek->ts));
3808
3809         /* FIXME: this is not fully correct, the timestamp refers to the random
3810          * access sample refered to in the tfra entry, which may not necessarily
3811          * be the first sample in the tfrag/trun (but hopefully/usually is) */
3812         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3813       } else {
3814         timestamp = 0;
3815       }
3816
3817       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3818       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3819           GST_TIME_ARGS (gst_ts));
3820     } else {
3821       /* subsequent fragments extend stream */
3822       timestamp =
3823           stream->samples[stream->n_samples - 1].timestamp +
3824           stream->samples[stream->n_samples - 1].duration;
3825
3826       /* If this is a GST_FORMAT_BYTES stream and there's a significant
3827        * difference (1 sec.) between decode_ts and timestamp, prefer the
3828        * former */
3829       if (has_tfdt && !qtdemux->upstream_format_is_time
3830           && ABSDIFF (decode_ts, timestamp) >
3831           MAX (stream->duration_last_moof / 2,
3832               GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND))) {
3833         GST_INFO_OBJECT (qtdemux,
3834             "decode_ts (%" GST_TIME_FORMAT ") and timestamp (%" GST_TIME_FORMAT
3835             ") are significantly different (more than %" GST_TIME_FORMAT
3836             "), using decode_ts",
3837             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, decode_ts)),
3838             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, timestamp)),
3839             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
3840                     MAX (stream->duration_last_moof / 2,
3841                         GSTTIME_TO_QTSTREAMTIME (stream, GST_SECOND)))));
3842         timestamp = decode_ts;
3843       }
3844
3845       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3846       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3847           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3848     }
3849   }
3850
3851   initial_offset = *running_offset;
3852
3853   sample = stream->samples + stream->n_samples;
3854   for (i = 0; i < samples_count; i++) {
3855     guint32 dur, size, sflags, ct;
3856
3857     /* first read sample data */
3858     if (flags & TR_SAMPLE_DURATION) {
3859       dur = QT_UINT32 (data + dur_offset);
3860     } else {
3861       dur = d_sample_duration;
3862     }
3863     if (flags & TR_SAMPLE_SIZE) {
3864       size = QT_UINT32 (data + size_offset);
3865     } else {
3866       size = d_sample_size;
3867     }
3868     if (flags & TR_FIRST_SAMPLE_FLAGS) {
3869       if (i == 0) {
3870         sflags = first_flags;
3871       } else {
3872         sflags = d_sample_flags;
3873       }
3874     } else if (flags & TR_SAMPLE_FLAGS) {
3875       sflags = QT_UINT32 (data + flags_offset);
3876     } else {
3877       sflags = d_sample_flags;
3878     }
3879     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3880       ct = QT_UINT32 (data + ct_offset);
3881     } else {
3882       ct = 0;
3883     }
3884     data += entry_size;
3885
3886     /* fill the sample information */
3887     sample->offset = *running_offset;
3888     sample->pts_offset = ct;
3889     sample->size = size;
3890     sample->timestamp = timestamp;
3891     sample->duration = dur;
3892     /* sample-is-difference-sample */
3893     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3894      * now idea how it relates to bitfield other than massive LE/BE confusion */
3895     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3896     *running_offset += size;
3897     timestamp += dur;
3898     stream->duration_moof += dur;
3899     sample++;
3900   }
3901
3902   /* Update total duration if needed */
3903   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3904
3905   /* Pre-emptively figure out size of mdat based on trun information.
3906    * If the [mdat] atom is effectivelly read, it will be replaced by the actual
3907    * size, else we will still be able to use this when dealing with gap'ed
3908    * input */
3909   qtdemux->mdatleft = *running_offset - initial_offset;
3910   qtdemux->mdatoffset = initial_offset;
3911   qtdemux->mdatsize = qtdemux->mdatleft;
3912
3913   stream->n_samples += samples_count;
3914   stream->n_samples_moof += samples_count;
3915
3916   if (stream->pending_seek != NULL)
3917     stream->pending_seek = NULL;
3918
3919   return TRUE;
3920
3921 fail:
3922   {
3923     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3924     return FALSE;
3925   }
3926 out_of_memory:
3927   {
3928     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3929         stream->n_samples);
3930     return FALSE;
3931   }
3932 index_too_big:
3933   {
3934     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3935         "be larger than %uMB (broken file?)", stream->n_samples,
3936         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3937     return FALSE;
3938   }
3939 }
3940
3941 /* find stream with @id */
3942 static inline QtDemuxStream *
3943 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3944 {
3945   QtDemuxStream *stream;
3946   gint i;
3947
3948   /* check */
3949   if (G_UNLIKELY (!id)) {
3950     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3951     return NULL;
3952   }
3953
3954   /* try to get it fast and simple */
3955   if (G_LIKELY (id <= qtdemux->n_streams)) {
3956     stream = qtdemux->streams[id - 1];
3957     if (G_LIKELY (stream->track_id == id))
3958       return stream;
3959   }
3960
3961   /* linear search otherwise */
3962   for (i = 0; i < qtdemux->n_streams; i++) {
3963     stream = qtdemux->streams[i];
3964     if (stream->track_id == id)
3965       return stream;
3966   }
3967   if (qtdemux->mss_mode) {
3968     /* mss should have only 1 stream anyway */
3969     return qtdemux->streams[0];
3970   }
3971
3972   return NULL;
3973 }
3974
3975 static gboolean
3976 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3977     guint32 * fragment_number)
3978 {
3979   if (!gst_byte_reader_skip (mfhd, 4))
3980     goto fail;
3981   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3982     goto fail;
3983   return TRUE;
3984 fail:
3985   {
3986     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3987     return FALSE;
3988   }
3989 }
3990
3991 static gboolean
3992 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3993     QtDemuxStream ** stream, guint32 * default_sample_duration,
3994     guint32 * default_sample_size, guint32 * default_sample_flags,
3995     gint64 * base_offset)
3996 {
3997   guint32 flags = 0;
3998   guint32 track_id = 0;
3999
4000   if (!gst_byte_reader_skip (tfhd, 1) ||
4001       !gst_byte_reader_get_uint24_be (tfhd, &flags))
4002     goto invalid_track;
4003
4004   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
4005     goto invalid_track;
4006
4007   *stream = qtdemux_find_stream (qtdemux, track_id);
4008   if (G_UNLIKELY (!*stream))
4009     goto unknown_stream;
4010
4011   if (flags & TF_DEFAULT_BASE_IS_MOOF)
4012     *base_offset = qtdemux->moof_offset;
4013
4014   if (flags & TF_BASE_DATA_OFFSET)
4015     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
4016       goto invalid_track;
4017
4018   /* obtain stream defaults */
4019   qtdemux_parse_trex (qtdemux, *stream,
4020       default_sample_duration, default_sample_size, default_sample_flags);
4021
4022   (*stream)->stsd_sample_description_id =
4023       (*stream)->def_sample_description_index - 1;
4024
4025   if (flags & TF_SAMPLE_DESCRIPTION_INDEX) {
4026     guint32 sample_description_index;
4027     if (!gst_byte_reader_get_uint32_be (tfhd, &sample_description_index))
4028       goto invalid_track;
4029     (*stream)->stsd_sample_description_id = sample_description_index - 1;
4030   }
4031
4032   if (qtdemux->mss_mode) {
4033     /* mss has no stsd entry */
4034     (*stream)->stsd_sample_description_id = 0;
4035   }
4036
4037   if (flags & TF_DEFAULT_SAMPLE_DURATION)
4038     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
4039       goto invalid_track;
4040
4041   if (flags & TF_DEFAULT_SAMPLE_SIZE)
4042     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
4043       goto invalid_track;
4044
4045   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
4046     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
4047       goto invalid_track;
4048
4049   return TRUE;
4050
4051 invalid_track:
4052   {
4053     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
4054     return FALSE;
4055   }
4056 unknown_stream:
4057   {
4058     GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
4059     return TRUE;
4060   }
4061 }
4062
4063 static gboolean
4064 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
4065     guint64 * decode_time)
4066 {
4067   guint32 version = 0;
4068
4069   if (!gst_byte_reader_get_uint32_be (br, &version))
4070     return FALSE;
4071
4072   version >>= 24;
4073   if (version == 1) {
4074     if (!gst_byte_reader_get_uint64_be (br, decode_time))
4075       goto failed;
4076   } else {
4077     guint32 dec_time = 0;
4078     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
4079       goto failed;
4080     *decode_time = dec_time;
4081   }
4082
4083   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
4084       *decode_time);
4085
4086   return TRUE;
4087
4088 failed:
4089   {
4090     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
4091     return FALSE;
4092   }
4093 }
4094
4095 /* Returns a pointer to a GstStructure containing the properties of
4096  * the stream sample identified by @sample_index. The caller must unref
4097  * the returned object after use. Returns NULL if unsuccessful. */
4098 static GstStructure *
4099 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
4100     QtDemuxStream * stream, guint sample_index)
4101 {
4102   QtDemuxCencSampleSetInfo *info = NULL;
4103
4104   g_return_val_if_fail (stream != NULL, NULL);
4105   g_return_val_if_fail (stream->protected, NULL);
4106   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
4107
4108   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4109
4110   /* Currently, cenc properties for groups of samples are not supported, so
4111    * simply return a copy of the default sample properties */
4112   return gst_structure_copy (info->default_properties);
4113 }
4114
4115 /* Parses the sizes of sample auxiliary information contained within a stream,
4116  * as given in a saiz box. Returns array of sample_count guint8 size values,
4117  * or NULL on failure */
4118 static guint8 *
4119 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
4120     GstByteReader * br, guint32 * sample_count)
4121 {
4122   guint32 flags = 0;
4123   guint8 *info_sizes;
4124   guint8 default_info_size;
4125
4126   g_return_val_if_fail (qtdemux != NULL, NULL);
4127   g_return_val_if_fail (stream != NULL, NULL);
4128   g_return_val_if_fail (br != NULL, NULL);
4129   g_return_val_if_fail (sample_count != NULL, NULL);
4130
4131   if (!gst_byte_reader_get_uint32_be (br, &flags))
4132     return NULL;
4133
4134   if (flags & 0x1) {
4135     /* aux_info_type and aux_info_type_parameter are ignored */
4136     if (!gst_byte_reader_skip (br, 8))
4137       return NULL;
4138   }
4139
4140   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
4141     return NULL;
4142   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
4143
4144   if (!gst_byte_reader_get_uint32_be (br, sample_count))
4145     return NULL;
4146   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
4147
4148
4149   if (default_info_size == 0) {
4150     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
4151       return NULL;
4152     }
4153   } else {
4154     info_sizes = g_new (guint8, *sample_count);
4155     memset (info_sizes, default_info_size, *sample_count);
4156   }
4157
4158   return info_sizes;
4159 }
4160
4161 /* Parses the offset of sample auxiliary information contained within a stream,
4162  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
4163 static gboolean
4164 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
4165     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
4166     guint64 * offset)
4167 {
4168   guint8 version = 0;
4169   guint32 flags = 0;
4170   guint32 aux_info_type = 0;
4171   guint32 aux_info_type_parameter = 0;
4172   guint32 entry_count;
4173   guint32 off_32;
4174   guint64 off_64;
4175   const guint8 *aux_info_type_data = NULL;
4176
4177   g_return_val_if_fail (qtdemux != NULL, FALSE);
4178   g_return_val_if_fail (stream != NULL, FALSE);
4179   g_return_val_if_fail (br != NULL, FALSE);
4180   g_return_val_if_fail (offset != NULL, FALSE);
4181
4182   if (!gst_byte_reader_get_uint8 (br, &version))
4183     return FALSE;
4184
4185   if (!gst_byte_reader_get_uint24_be (br, &flags))
4186     return FALSE;
4187
4188   if (flags & 0x1) {
4189
4190     if (!gst_byte_reader_get_data (br, 4, &aux_info_type_data))
4191       return FALSE;
4192     aux_info_type = QT_FOURCC (aux_info_type_data);
4193
4194     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
4195       return FALSE;
4196   } else if (stream->protected) {
4197     aux_info_type = stream->protection_scheme_type;
4198   } else {
4199     aux_info_type = CUR_STREAM (stream)->fourcc;
4200   }
4201
4202   if (info_type)
4203     *info_type = aux_info_type;
4204   if (info_type_parameter)
4205     *info_type_parameter = aux_info_type_parameter;
4206
4207   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
4208       "aux_info_type_parameter:  %#06x",
4209       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
4210
4211   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
4212     return FALSE;
4213
4214   if (entry_count != 1) {
4215     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
4216     return FALSE;
4217   }
4218
4219   if (version == 0) {
4220     if (!gst_byte_reader_get_uint32_be (br, &off_32))
4221       return FALSE;
4222     *offset = (guint64) off_32;
4223   } else {
4224     if (!gst_byte_reader_get_uint64_be (br, &off_64))
4225       return FALSE;
4226     *offset = off_64;
4227   }
4228
4229   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
4230   return TRUE;
4231 }
4232
4233 static void
4234 qtdemux_gst_structure_free (GstStructure * gststructure)
4235 {
4236   if (gststructure) {
4237     gst_structure_free (gststructure);
4238   }
4239 }
4240
4241 /* Parses auxiliary information relating to samples protected using Common
4242  * Encryption (cenc); the format of this information is defined in
4243  * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
4244 static gboolean
4245 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
4246     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
4247 {
4248   QtDemuxCencSampleSetInfo *ss_info = NULL;
4249   guint8 size;
4250   gint i;
4251   GPtrArray *old_crypto_info = NULL;
4252   guint old_entries = 0;
4253
4254   g_return_val_if_fail (qtdemux != NULL, FALSE);
4255   g_return_val_if_fail (stream != NULL, FALSE);
4256   g_return_val_if_fail (br != NULL, FALSE);
4257   g_return_val_if_fail (stream->protected, FALSE);
4258   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
4259
4260   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
4261
4262   if (ss_info->crypto_info) {
4263     old_crypto_info = ss_info->crypto_info;
4264     /* Count number of non-null entries remaining at the tail end */
4265     for (i = old_crypto_info->len - 1; i >= 0; i--) {
4266       if (g_ptr_array_index (old_crypto_info, i) == NULL)
4267         break;
4268       old_entries++;
4269     }
4270   }
4271
4272   ss_info->crypto_info =
4273       g_ptr_array_new_full (sample_count + old_entries,
4274       (GDestroyNotify) qtdemux_gst_structure_free);
4275
4276   /* We preserve old entries because we parse the next moof in advance
4277    * of consuming all samples from the previous moof, and otherwise
4278    * we'd discard the corresponding crypto info for the samples
4279    * from the previous fragment. */
4280   if (old_entries) {
4281     GST_DEBUG_OBJECT (qtdemux, "Preserving %d old crypto info entries",
4282         old_entries);
4283     for (i = old_crypto_info->len - old_entries; i < old_crypto_info->len; i++) {
4284       g_ptr_array_add (ss_info->crypto_info, g_ptr_array_index (old_crypto_info,
4285               i));
4286       g_ptr_array_index (old_crypto_info, i) = NULL;
4287     }
4288   }
4289
4290   if (old_crypto_info) {
4291     /* Everything now belongs to the new array */
4292     g_ptr_array_free (old_crypto_info, TRUE);
4293   }
4294
4295   for (i = 0; i < sample_count; ++i) {
4296     GstStructure *properties;
4297     guint16 n_subsamples = 0;
4298     guint8 *data;
4299     guint iv_size;
4300     GstBuffer *buf;
4301
4302     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
4303     if (properties == NULL) {
4304       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
4305       return FALSE;
4306     }
4307     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
4308       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
4309       gst_structure_free (properties);
4310       return FALSE;
4311     }
4312     if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
4313       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
4314       gst_structure_free (properties);
4315       return FALSE;
4316     }
4317     buf = gst_buffer_new_wrapped (data, iv_size);
4318     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
4319     gst_buffer_unref (buf);
4320     size = info_sizes[i];
4321     if (size > iv_size) {
4322       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
4323           || !(n_subsamples > 0)) {
4324         gst_structure_free (properties);
4325         GST_ERROR_OBJECT (qtdemux,
4326             "failed to get subsample count for sample %u", i);
4327         return FALSE;
4328       }
4329       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
4330       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
4331         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
4332             i);
4333         gst_structure_free (properties);
4334         return FALSE;
4335       }
4336       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
4337       if (!buf) {
4338         gst_structure_free (properties);
4339         return FALSE;
4340       }
4341       gst_structure_set (properties,
4342           "subsample_count", G_TYPE_UINT, n_subsamples,
4343           "subsamples", GST_TYPE_BUFFER, buf, NULL);
4344       gst_buffer_unref (buf);
4345     } else {
4346       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
4347     }
4348     g_ptr_array_add (ss_info->crypto_info, properties);
4349   }
4350   return TRUE;
4351 }
4352
4353 /* Converts a UUID in raw byte form to a string representation, as defined in
4354  * RFC 4122. The caller takes ownership of the returned string and is
4355  * responsible for freeing it after use. */
4356 static gchar *
4357 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
4358 {
4359   const guint8 *uuid = (const guint8 *) uuid_bytes;
4360
4361   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
4362       "%02x%02x-%02x%02x%02x%02x%02x%02x",
4363       uuid[0], uuid[1], uuid[2], uuid[3],
4364       uuid[4], uuid[5], uuid[6], uuid[7],
4365       uuid[8], uuid[9], uuid[10], uuid[11],
4366       uuid[12], uuid[13], uuid[14], uuid[15]);
4367 }
4368
4369 /* Parses a Protection System Specific Header box (pssh), as defined in the
4370  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
4371  * information needed by a specific content protection system in order to
4372  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
4373  * otherwise. */
4374 static gboolean
4375 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
4376 {
4377   gchar *sysid_string;
4378   guint32 pssh_size = QT_UINT32 (node->data);
4379   GstBuffer *pssh = NULL;
4380   GstEvent *event = NULL;
4381   guint32 parent_box_type;
4382   gint i;
4383
4384   if (G_UNLIKELY (pssh_size < 32U)) {
4385     GST_ERROR_OBJECT (qtdemux, "invalid box size");
4386     return FALSE;
4387   }
4388
4389   sysid_string =
4390       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
4391
4392   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
4393
4394   pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
4395   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
4396       gst_buffer_get_size (pssh));
4397
4398   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
4399
4400   /* Push an event containing the pssh box onto the queues of all streams. */
4401   event = gst_event_new_protection (sysid_string, pssh,
4402       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
4403   for (i = 0; i < qtdemux->n_streams; ++i) {
4404     g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
4405         gst_event_ref (event));
4406   }
4407   g_free (sysid_string);
4408   gst_event_unref (event);
4409   gst_buffer_unref (pssh);
4410   return TRUE;
4411 }
4412
4413 static gboolean
4414 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
4415     guint64 moof_offset, QtDemuxStream * stream)
4416 {
4417   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
4418   GNode *uuid_node;
4419   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
4420   GNode *saiz_node, *saio_node, *pssh_node;
4421   GstByteReader saiz_data, saio_data;
4422   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
4423   gint64 base_offset, running_offset;
4424   guint32 frag_num;
4425
4426   /* NOTE @stream ignored */
4427
4428   moof_node = g_node_new ((guint8 *) buffer);
4429   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
4430   qtdemux_node_dump (qtdemux, moof_node);
4431
4432   /* Get fragment number from mfhd and check it's valid */
4433   mfhd_node =
4434       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
4435   if (mfhd_node == NULL)
4436     goto missing_mfhd;
4437   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
4438     goto fail;
4439   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
4440
4441   /* unknown base_offset to start with */
4442   base_offset = running_offset = -1;
4443   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
4444   while (traf_node) {
4445     guint64 decode_time = 0;
4446
4447     /* Fragment Header node */
4448     tfhd_node =
4449         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
4450         &tfhd_data);
4451     if (!tfhd_node)
4452       goto missing_tfhd;
4453     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
4454             &ds_size, &ds_flags, &base_offset))
4455       goto missing_tfhd;
4456
4457     /* The following code assumes at most a single set of sample auxiliary
4458      * data in the fragment (consisting of a saiz box and a corresponding saio
4459      * box); in theory, however, there could be multiple sets of sample
4460      * auxiliary data in a fragment. */
4461     saiz_node =
4462         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
4463         &saiz_data);
4464     if (saiz_node) {
4465       guint32 info_type = 0;
4466       guint64 offset = 0;
4467       guint32 info_type_parameter = 0;
4468
4469       g_free (qtdemux->cenc_aux_info_sizes);
4470
4471       qtdemux->cenc_aux_info_sizes =
4472           qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
4473           &qtdemux->cenc_aux_sample_count);
4474       if (qtdemux->cenc_aux_info_sizes == NULL) {
4475         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
4476         goto fail;
4477       }
4478       saio_node =
4479           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
4480           &saio_data);
4481       if (!saio_node) {
4482         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
4483         g_free (qtdemux->cenc_aux_info_sizes);
4484         qtdemux->cenc_aux_info_sizes = NULL;
4485         goto fail;
4486       }
4487
4488       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
4489                   &info_type, &info_type_parameter, &offset))) {
4490         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
4491         g_free (qtdemux->cenc_aux_info_sizes);
4492         qtdemux->cenc_aux_info_sizes = NULL;
4493         goto fail;
4494       }
4495       if (base_offset > -1 && base_offset > qtdemux->moof_offset)
4496         offset += (guint64) (base_offset - qtdemux->moof_offset);
4497       if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
4498         GstByteReader br;
4499         if (offset > length) {
4500           GST_DEBUG_OBJECT (qtdemux, "cenc auxiliary info stored out of moof");
4501           qtdemux->cenc_aux_info_offset = offset;
4502         } else {
4503           gst_byte_reader_init (&br, buffer + offset, length - offset);
4504           if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
4505                   qtdemux->cenc_aux_info_sizes,
4506                   qtdemux->cenc_aux_sample_count)) {
4507             GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
4508             g_free (qtdemux->cenc_aux_info_sizes);
4509             qtdemux->cenc_aux_info_sizes = NULL;
4510             goto fail;
4511           }
4512         }
4513       }
4514     }
4515
4516     tfdt_node =
4517         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
4518         &tfdt_data);
4519     if (tfdt_node) {
4520       /* We'll use decode_time to interpolate timestamps
4521        * in case the input timestamps are missing */
4522       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4523
4524       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4525           " (%" GST_TIME_FORMAT ")", decode_time,
4526           GST_TIME_ARGS (stream ? QTSTREAMTIME_TO_GSTTIME (stream,
4527                   decode_time) : GST_CLOCK_TIME_NONE));
4528
4529       /* Discard the fragment buffer timestamp info to avoid using it.
4530        * Rely on tfdt instead as it is more accurate than the timestamp
4531        * that is fetched from a manifest/playlist and is usually
4532        * less accurate. */
4533       qtdemux->fragment_start = -1;
4534     }
4535
4536     if (G_UNLIKELY (!stream)) {
4537       /* we lost track of offset, we'll need to regain it,
4538        * but can delay complaining until later or avoid doing so altogether */
4539       base_offset = -2;
4540       goto next;
4541     }
4542     if (G_UNLIKELY (base_offset < -1))
4543       goto lost_offset;
4544
4545     if (qtdemux->upstream_format_is_time)
4546       gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
4547
4548     /* initialise moof sample data */
4549     stream->n_samples_moof = 0;
4550     stream->duration_last_moof = stream->duration_moof;
4551     stream->duration_moof = 0;
4552
4553     /* Track Run node */
4554     trun_node =
4555         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4556         &trun_data);
4557     while (trun_node) {
4558       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4559           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4560           &running_offset, decode_time, (tfdt_node != NULL));
4561       /* iterate all siblings */
4562       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4563           &trun_data);
4564     }
4565
4566     uuid_node = qtdemux_tree_get_child_by_type (traf_node, FOURCC_uuid);
4567     if (uuid_node) {
4568       guint8 *uuid_buffer = (guint8 *) uuid_node->data;
4569       guint32 box_length = QT_UINT32 (uuid_buffer);
4570
4571       qtdemux_parse_uuid (qtdemux, uuid_buffer, box_length);
4572     }
4573
4574     /* if no new base_offset provided for next traf,
4575      * base is end of current traf */
4576     base_offset = running_offset;
4577     running_offset = -1;
4578
4579     if (stream->n_samples_moof && stream->duration_moof)
4580       stream->new_caps = TRUE;
4581
4582   next:
4583     /* iterate all siblings */
4584     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4585   }
4586
4587   /* parse any protection system info */
4588   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4589   while (pssh_node) {
4590     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4591     qtdemux_parse_pssh (qtdemux, pssh_node);
4592     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4593   }
4594
4595   g_node_destroy (moof_node);
4596   return TRUE;
4597
4598 missing_tfhd:
4599   {
4600     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4601     goto fail;
4602   }
4603 missing_mfhd:
4604   {
4605     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4606     goto fail;
4607   }
4608 lost_offset:
4609   {
4610     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4611     goto fail;
4612   }
4613 fail:
4614   {
4615     g_node_destroy (moof_node);
4616     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4617         (_("This file is corrupt and cannot be played.")), (NULL));
4618     return FALSE;
4619   }
4620 }
4621
4622 #if 0
4623 /* might be used if some day we actually use mfra & co
4624  * for random access to fragments,
4625  * but that will require quite some modifications and much less relying
4626  * on a sample array */
4627 #endif
4628
4629 static gboolean
4630 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4631 {
4632   QtDemuxStream *stream;
4633   guint32 ver_flags, track_id, len, num_entries, i;
4634   guint value_size, traf_size, trun_size, sample_size;
4635   guint64 time = 0, moof_offset = 0;
4636 #if 0
4637   GstBuffer *buf = NULL;
4638   GstFlowReturn ret;
4639 #endif
4640   GstByteReader tfra;
4641
4642   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4643
4644   if (!gst_byte_reader_skip (&tfra, 8))
4645     return FALSE;
4646
4647   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4648     return FALSE;
4649
4650   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4651       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4652       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4653     return FALSE;
4654
4655   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4656
4657   stream = qtdemux_find_stream (qtdemux, track_id);
4658   if (stream == NULL)
4659     goto unknown_trackid;
4660
4661   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4662   sample_size = (len & 3) + 1;
4663   trun_size = ((len & 12) >> 2) + 1;
4664   traf_size = ((len & 48) >> 4) + 1;
4665
4666   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4667       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4668
4669   if (num_entries == 0)
4670     goto no_samples;
4671
4672   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4673           value_size + value_size + traf_size + trun_size + sample_size))
4674     goto corrupt_file;
4675
4676   g_free (stream->ra_entries);
4677   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4678   stream->n_ra_entries = num_entries;
4679
4680   for (i = 0; i < num_entries; i++) {
4681     qt_atom_parser_get_offset (&tfra, value_size, &time);
4682     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4683     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4684     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4685     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4686
4687     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4688
4689     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4690         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4691
4692     stream->ra_entries[i].ts = time;
4693     stream->ra_entries[i].moof_offset = moof_offset;
4694
4695     /* don't want to go through the entire file and read all moofs at startup */
4696 #if 0
4697     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4698     if (ret != GST_FLOW_OK)
4699       goto corrupt_file;
4700     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4701         moof_offset, stream);
4702     gst_buffer_unref (buf);
4703 #endif
4704   }
4705
4706   check_update_duration (qtdemux, time);
4707
4708   return TRUE;
4709
4710 /* ERRORS */
4711 unknown_trackid:
4712   {
4713     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4714     return FALSE;
4715   }
4716 corrupt_file:
4717   {
4718     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4719     return FALSE;
4720   }
4721 no_samples:
4722   {
4723     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4724     return FALSE;
4725   }
4726 }
4727
4728 static gboolean
4729 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4730 {
4731   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4732   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4733   GstBuffer *mfro = NULL, *mfra = NULL;
4734   GstFlowReturn flow;
4735   gboolean ret = FALSE;
4736   GNode *mfra_node, *tfra_node;
4737   guint64 mfra_offset = 0;
4738   guint32 fourcc, mfra_size;
4739   gint64 len;
4740
4741   /* query upstream size in bytes */
4742   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4743     goto size_query_failed;
4744
4745   /* mfro box should be at the very end of the file */
4746   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4747   if (flow != GST_FLOW_OK)
4748     goto exit;
4749
4750   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4751
4752   fourcc = QT_FOURCC (mfro_map.data + 4);
4753   if (fourcc != FOURCC_mfro)
4754     goto exit;
4755
4756   GST_INFO_OBJECT (qtdemux, "Found mfro box");
4757   if (mfro_map.size < 16)
4758     goto invalid_mfro_size;
4759
4760   mfra_size = QT_UINT32 (mfro_map.data + 12);
4761   if (mfra_size >= len)
4762     goto invalid_mfra_size;
4763
4764   mfra_offset = len - mfra_size;
4765
4766   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4767       mfra_offset, mfra_size);
4768
4769   /* now get and parse mfra box */
4770   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4771   if (flow != GST_FLOW_OK)
4772     goto broken_file;
4773
4774   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4775
4776   mfra_node = g_node_new ((guint8 *) mfra_map.data);
4777   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4778
4779   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4780
4781   while (tfra_node) {
4782     qtdemux_parse_tfra (qtdemux, tfra_node);
4783     /* iterate all siblings */
4784     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4785   }
4786   g_node_destroy (mfra_node);
4787
4788   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4789   ret = TRUE;
4790
4791 exit:
4792
4793   if (mfro) {
4794     if (mfro_map.memory != NULL)
4795       gst_buffer_unmap (mfro, &mfro_map);
4796     gst_buffer_unref (mfro);
4797   }
4798   if (mfra) {
4799     if (mfra_map.memory != NULL)
4800       gst_buffer_unmap (mfra, &mfra_map);
4801     gst_buffer_unref (mfra);
4802   }
4803   return ret;
4804
4805 /* ERRORS */
4806 size_query_failed:
4807   {
4808     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4809     goto exit;
4810   }
4811 invalid_mfro_size:
4812   {
4813     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4814     goto exit;
4815   }
4816 invalid_mfra_size:
4817   {
4818     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4819     goto exit;
4820   }
4821 broken_file:
4822   {
4823     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4824     goto exit;
4825   }
4826 }
4827
4828 static guint64
4829 add_offset (guint64 offset, guint64 advance)
4830 {
4831   /* Avoid 64-bit overflow by clamping */
4832   if (offset > G_MAXUINT64 - advance)
4833     return G_MAXUINT64;
4834   return offset + advance;
4835 }
4836
4837 static GstFlowReturn
4838 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4839 {
4840   guint64 length = 0;
4841   guint32 fourcc = 0;
4842   GstBuffer *buf = NULL;
4843   GstFlowReturn ret = GST_FLOW_OK;
4844   guint64 cur_offset = qtdemux->offset;
4845   GstMapInfo map;
4846
4847   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4848   if (G_UNLIKELY (ret != GST_FLOW_OK))
4849     goto beach;
4850   gst_buffer_map (buf, &map, GST_MAP_READ);
4851   if (G_LIKELY (map.size >= 8))
4852     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4853   gst_buffer_unmap (buf, &map);
4854   gst_buffer_unref (buf);
4855
4856   /* maybe we already got most we needed, so only consider this eof */
4857   if (G_UNLIKELY (length == 0)) {
4858     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4859         (_("Invalid atom size.")),
4860         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4861             GST_FOURCC_ARGS (fourcc)));
4862     ret = GST_FLOW_EOS;
4863     goto beach;
4864   }
4865
4866   switch (fourcc) {
4867     case FOURCC_moof:
4868       /* record for later parsing when needed */
4869       if (!qtdemux->moof_offset) {
4870         qtdemux->moof_offset = qtdemux->offset;
4871       }
4872       if (qtdemux_pull_mfro_mfra (qtdemux)) {
4873         /* FIXME */
4874       } else {
4875         qtdemux->offset += length;      /* skip moof and keep going */
4876       }
4877       if (qtdemux->got_moov) {
4878         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4879         ret = GST_FLOW_EOS;
4880         goto beach;
4881       }
4882       break;
4883     case FOURCC_mdat:
4884     case FOURCC_free:
4885     case FOURCC_wide:
4886     case FOURCC_PICT:
4887     case FOURCC_pnot:
4888     {
4889       GST_LOG_OBJECT (qtdemux,
4890           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4891           GST_FOURCC_ARGS (fourcc), cur_offset);
4892       qtdemux->offset = add_offset (qtdemux->offset, length);
4893       break;
4894     }
4895     case FOURCC_moov:
4896     {
4897       GstBuffer *moov = NULL;
4898
4899       if (qtdemux->got_moov) {
4900         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4901         qtdemux->offset = add_offset (qtdemux->offset, length);
4902         goto beach;
4903       }
4904
4905       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4906       if (ret != GST_FLOW_OK)
4907         goto beach;
4908       gst_buffer_map (moov, &map, GST_MAP_READ);
4909
4910       if (length != map.size) {
4911         /* Some files have a 'moov' atom at the end of the file which contains
4912          * a terminal 'free' atom where the body of the atom is missing.
4913          * Check for, and permit, this special case.
4914          */
4915         if (map.size >= 8) {
4916           guint8 *final_data = map.data + (map.size - 8);
4917           guint32 final_length = QT_UINT32 (final_data);
4918           guint32 final_fourcc = QT_FOURCC (final_data + 4);
4919
4920           if (final_fourcc == FOURCC_free
4921               && map.size + final_length - 8 == length) {
4922             /* Ok, we've found that special case. Allocate a new buffer with
4923              * that free atom actually present. */
4924             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4925             gst_buffer_fill (newmoov, 0, map.data, map.size);
4926             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4927             gst_buffer_unmap (moov, &map);
4928             gst_buffer_unref (moov);
4929             moov = newmoov;
4930             gst_buffer_map (moov, &map, GST_MAP_READ);
4931           }
4932         }
4933       }
4934
4935       if (length != map.size) {
4936         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4937             (_("This file is incomplete and cannot be played.")),
4938             ("We got less than expected (received %" G_GSIZE_FORMAT
4939                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4940                 (guint) length, cur_offset));
4941         gst_buffer_unmap (moov, &map);
4942         gst_buffer_unref (moov);
4943         ret = GST_FLOW_ERROR;
4944         goto beach;
4945       }
4946       qtdemux->offset += length;
4947
4948       qtdemux_parse_moov (qtdemux, map.data, length);
4949       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4950
4951       qtdemux_parse_tree (qtdemux);
4952       if (qtdemux->moov_node_compressed) {
4953         g_node_destroy (qtdemux->moov_node_compressed);
4954         g_free (qtdemux->moov_node->data);
4955       }
4956       qtdemux->moov_node_compressed = NULL;
4957       g_node_destroy (qtdemux->moov_node);
4958       qtdemux->moov_node = NULL;
4959       gst_buffer_unmap (moov, &map);
4960       gst_buffer_unref (moov);
4961       qtdemux->got_moov = TRUE;
4962
4963       break;
4964     }
4965     case FOURCC_ftyp:
4966     {
4967       GstBuffer *ftyp = NULL;
4968
4969       /* extract major brand; might come in handy for ISO vs QT issues */
4970       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4971       if (ret != GST_FLOW_OK)
4972         goto beach;
4973       qtdemux->offset += length;
4974       gst_buffer_map (ftyp, &map, GST_MAP_READ);
4975       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4976       gst_buffer_unmap (ftyp, &map);
4977       gst_buffer_unref (ftyp);
4978       break;
4979     }
4980     case FOURCC_uuid:
4981     {
4982       GstBuffer *uuid = NULL;
4983
4984       /* uuid are extension atoms */
4985       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4986       if (ret != GST_FLOW_OK)
4987         goto beach;
4988       qtdemux->offset += length;
4989       gst_buffer_map (uuid, &map, GST_MAP_READ);
4990       qtdemux_parse_uuid (qtdemux, map.data, map.size);
4991       gst_buffer_unmap (uuid, &map);
4992       gst_buffer_unref (uuid);
4993       break;
4994     }
4995     case FOURCC_sidx:
4996     {
4997       GstBuffer *sidx = NULL;
4998       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4999       if (ret != GST_FLOW_OK)
5000         goto beach;
5001       qtdemux->offset += length;
5002       gst_buffer_map (sidx, &map, GST_MAP_READ);
5003       qtdemux_parse_sidx (qtdemux, map.data, map.size);
5004       gst_buffer_unmap (sidx, &map);
5005       gst_buffer_unref (sidx);
5006       break;
5007     }
5008     default:
5009     {
5010       GstBuffer *unknown = NULL;
5011
5012       GST_LOG_OBJECT (qtdemux,
5013           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
5014           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
5015           cur_offset);
5016       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
5017       if (ret != GST_FLOW_OK)
5018         goto beach;
5019       gst_buffer_map (unknown, &map, GST_MAP_READ);
5020       GST_MEMDUMP ("Unknown tag", map.data, map.size);
5021       gst_buffer_unmap (unknown, &map);
5022       gst_buffer_unref (unknown);
5023       qtdemux->offset += length;
5024       break;
5025     }
5026   }
5027
5028 beach:
5029   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
5030     /* digested all data, show what we have */
5031 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
5032     if (qtdemux->spherical_metadata)
5033       _send_spherical_metadata_msg_to_bus (qtdemux);
5034 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
5035     qtdemux_prepare_streams (qtdemux);
5036     ret = qtdemux_expose_streams (qtdemux);
5037
5038     qtdemux->state = QTDEMUX_STATE_MOVIE;
5039     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
5040         qtdemux->state);
5041     return ret;
5042   }
5043   return ret;
5044 }
5045
5046 /* Seeks to the previous keyframe of the indexed stream and
5047  * aligns other streams with respect to the keyframe timestamp
5048  * of indexed stream. Only called in case of Reverse Playback
5049  */
5050 static GstFlowReturn
5051 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
5052 {
5053   guint8 n = 0;
5054   guint32 seg_idx = 0, k_index = 0;
5055   guint32 ref_seg_idx, ref_k_index;
5056   GstClockTime k_pos = 0, last_stop = 0;
5057   QtDemuxSegment *seg = NULL;
5058   QtDemuxStream *ref_str = NULL;
5059   guint64 seg_media_start_mov;  /* segment media start time in mov format */
5060   guint64 target_ts;
5061
5062   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
5063    * and finally align all the other streams on that timestamp with their
5064    * respective keyframes */
5065   for (n = 0; n < qtdemux->n_streams; n++) {
5066     QtDemuxStream *str = qtdemux->streams[n];
5067
5068     /* No candidate yet, take the first stream */
5069     if (!ref_str) {
5070       ref_str = str;
5071       continue;
5072     }
5073
5074     /* So that stream has a segment, we prefer video streams */
5075     if (str->subtype == FOURCC_vide) {
5076       ref_str = str;
5077       break;
5078     }
5079   }
5080
5081   if (G_UNLIKELY (!ref_str)) {
5082     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
5083     goto eos;
5084   }
5085
5086   if (G_UNLIKELY (!ref_str->from_sample)) {
5087     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
5088     goto eos;
5089   }
5090
5091   /* So that stream has been playing from from_sample to to_sample. We will
5092    * get the timestamp of the previous sample and search for a keyframe before
5093    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
5094   if (ref_str->subtype == FOURCC_vide) {
5095     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
5096         ref_str->from_sample - 1, FALSE);
5097   } else {
5098     if (ref_str->from_sample >= 10)
5099       k_index = ref_str->from_sample - 10;
5100     else
5101       k_index = 0;
5102   }
5103
5104   target_ts =
5105       ref_str->samples[k_index].timestamp +
5106       ref_str->samples[k_index].pts_offset;
5107
5108   /* get current segment for that stream */
5109   seg = &ref_str->segments[ref_str->segment_index];
5110   /* Use segment start in original timescale for comparisons */
5111   seg_media_start_mov = seg->trak_media_start;
5112
5113   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
5114       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
5115       k_index, target_ts, seg_media_start_mov,
5116       GST_TIME_ARGS (seg->media_start));
5117
5118   /* Crawl back through segments to find the one containing this I frame */
5119   while (target_ts < seg_media_start_mov) {
5120     GST_DEBUG_OBJECT (qtdemux,
5121         "keyframe position (sample %u) is out of segment %u " " target %"
5122         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
5123         ref_str->segment_index, target_ts, seg_media_start_mov);
5124
5125     if (G_UNLIKELY (!ref_str->segment_index)) {
5126       /* Reached first segment, let's consider it's EOS */
5127       goto eos;
5128     }
5129     ref_str->segment_index--;
5130     seg = &ref_str->segments[ref_str->segment_index];
5131     /* Use segment start in original timescale for comparisons */
5132     seg_media_start_mov = seg->trak_media_start;
5133   }
5134   /* Calculate time position of the keyframe and where we should stop */
5135   k_pos =
5136       QTSTREAMTIME_TO_GSTTIME (ref_str,
5137       target_ts - seg->trak_media_start) + seg->time;
5138   last_stop =
5139       QTSTREAMTIME_TO_GSTTIME (ref_str,
5140       ref_str->samples[ref_str->from_sample].timestamp -
5141       seg->trak_media_start) + seg->time;
5142
5143   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
5144       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
5145       k_index, GST_TIME_ARGS (k_pos));
5146
5147   /* Set last_stop with the keyframe timestamp we pushed of that stream */
5148   qtdemux->segment.position = last_stop;
5149   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
5150       GST_TIME_ARGS (last_stop));
5151
5152   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
5153     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
5154     goto eos;
5155   }
5156
5157   ref_seg_idx = ref_str->segment_index;
5158   ref_k_index = k_index;
5159
5160   /* Align them all on this */
5161   for (n = 0; n < qtdemux->n_streams; n++) {
5162     guint32 index = 0;
5163     GstClockTime seg_time = 0;
5164     QtDemuxStream *str = qtdemux->streams[n];
5165
5166     /* aligning reference stream again might lead to backing up to yet another
5167      * keyframe (due to timestamp rounding issues),
5168      * potentially putting more load on downstream; so let's try to avoid */
5169     if (str == ref_str) {
5170       seg_idx = ref_seg_idx;
5171       seg = &str->segments[seg_idx];
5172       k_index = ref_k_index;
5173       GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
5174           "sample at index %d", n, ref_str->segment_index, k_index);
5175     } else {
5176       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
5177       GST_DEBUG_OBJECT (qtdemux,
5178           "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
5179           seg_idx, GST_TIME_ARGS (k_pos));
5180
5181       /* get segment and time in the segment */
5182       seg = &str->segments[seg_idx];
5183       seg_time = k_pos - seg->time;
5184
5185       /* get the media time in the segment.
5186        * No adjustment for empty "filler" segments */
5187       if (seg->media_start != GST_CLOCK_TIME_NONE)
5188         seg_time += seg->media_start;
5189
5190       /* get the index of the sample with media time */
5191       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
5192       GST_DEBUG_OBJECT (qtdemux,
5193           "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
5194           GST_TIME_ARGS (seg_time), index);
5195
5196       /* find previous keyframe */
5197       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index, FALSE);
5198     }
5199
5200     /* Remember until where we want to go */
5201     str->to_sample = str->from_sample - 1;
5202     /* Define our time position */
5203     target_ts =
5204         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
5205     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
5206     if (seg->media_start != GST_CLOCK_TIME_NONE)
5207       str->time_position -= seg->media_start;
5208
5209     /* Now seek back in time */
5210     gst_qtdemux_move_stream (qtdemux, str, k_index);
5211     GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
5212         GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
5213         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
5214   }
5215
5216   return GST_FLOW_OK;
5217
5218 eos:
5219   return GST_FLOW_EOS;
5220 }
5221
5222 /*
5223  * Gets the current qt segment start, stop and position for the
5224  * given time offset. This is used in update_segment()
5225  */
5226 static void
5227 gst_qtdemux_stream_segment_get_boundaries (GstQTDemux * qtdemux,
5228     QtDemuxStream * stream, GstClockTime offset,
5229     GstClockTime * _start, GstClockTime * _stop, GstClockTime * _time)
5230 {
5231   GstClockTime seg_time;
5232   GstClockTime start, stop, time;
5233   QtDemuxSegment *segment;
5234
5235   segment = &stream->segments[stream->segment_index];
5236
5237   /* get time in this segment */
5238   seg_time = (offset - segment->time) * segment->rate;
5239
5240   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
5241       GST_TIME_ARGS (seg_time));
5242
5243   if (G_UNLIKELY (seg_time > segment->duration)) {
5244     GST_LOG_OBJECT (stream->pad,
5245         "seg_time > segment->duration %" GST_TIME_FORMAT,
5246         GST_TIME_ARGS (segment->duration));
5247     seg_time = segment->duration;
5248   }
5249
5250   /* qtdemux->segment.stop is in outside-time-realm, whereas
5251    * segment->media_stop is in track-time-realm.
5252    *
5253    * In order to compare the two, we need to bring segment.stop
5254    * into the track-time-realm
5255    *
5256    * FIXME - does this comment still hold? Don't see any conversion here */
5257
5258   stop = qtdemux->segment.stop;
5259   if (stop == GST_CLOCK_TIME_NONE)
5260     stop = qtdemux->segment.duration;
5261   if (stop == GST_CLOCK_TIME_NONE)
5262     stop = segment->media_stop;
5263   else
5264     stop =
5265         MIN (segment->media_stop, stop - segment->time + segment->media_start);
5266
5267   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5268     start = segment->time + seg_time;
5269     time = offset;
5270     stop = start - seg_time + segment->duration;
5271   } else if (qtdemux->segment.rate >= 0) {
5272     start = MIN (segment->media_start + seg_time, stop);
5273     time = offset;
5274   } else {
5275     if (segment->media_start >= qtdemux->segment.start) {
5276       time = segment->time;
5277     } else {
5278       time = segment->time + (qtdemux->segment.start - segment->media_start);
5279     }
5280
5281     start = MAX (segment->media_start, qtdemux->segment.start);
5282     stop = MIN (segment->media_start + seg_time, stop);
5283   }
5284
5285   *_start = start;
5286   *_stop = stop;
5287   *_time = time;
5288 }
5289
5290 /*
5291  * Updates the qt segment used for the stream and pushes a new segment event
5292  * downstream on this stream's pad.
5293  */
5294 static gboolean
5295 gst_qtdemux_stream_update_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5296     gint seg_idx, GstClockTime offset, GstClockTime * _start,
5297     GstClockTime * _stop)
5298 {
5299   QtDemuxSegment *segment;
5300   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE, time = 0;
5301   gdouble rate;
5302   GstEvent *event;
5303
5304   /* update the current segment */
5305   stream->segment_index = seg_idx;
5306
5307   /* get the segment */
5308   segment = &stream->segments[seg_idx];
5309
5310   if (G_UNLIKELY (offset < segment->time)) {
5311     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
5312         GST_TIME_ARGS (segment->time));
5313     return FALSE;
5314   }
5315
5316   /* segment lies beyond total indicated duration */
5317   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
5318           segment->time > qtdemux->segment.duration)) {
5319     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
5320         " < segment->time %" GST_TIME_FORMAT,
5321         GST_TIME_ARGS (qtdemux->segment.duration),
5322         GST_TIME_ARGS (segment->time));
5323     return FALSE;
5324   }
5325
5326   gst_qtdemux_stream_segment_get_boundaries (qtdemux, stream, offset,
5327       &start, &stop, &time);
5328
5329   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
5330       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
5331       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
5332
5333   /* combine global rate with that of the segment */
5334   rate = segment->rate * qtdemux->segment.rate;
5335
5336   /* Copy flags from main segment */
5337   stream->segment.flags = qtdemux->segment.flags;
5338
5339   /* update the segment values used for clipping */
5340   stream->segment.offset = qtdemux->segment.offset;
5341   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
5342   stream->segment.applied_rate = qtdemux->segment.applied_rate;
5343   stream->segment.rate = rate;
5344   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
5345       stream->cslg_shift);
5346   stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
5347       stream->cslg_shift);
5348   stream->segment.time = time;
5349   stream->segment.position = stream->segment.start;
5350
5351   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
5352       &stream->segment);
5353
5354   /* now prepare and send the segment */
5355   if (stream->pad) {
5356     event = gst_event_new_segment (&stream->segment);
5357     if (qtdemux->segment_seqnum) {
5358       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
5359     }
5360     gst_pad_push_event (stream->pad, event);
5361     /* assume we can send more data now */
5362     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
5363     /* clear to send tags on this pad now */
5364     gst_qtdemux_push_tags (qtdemux, stream);
5365   }
5366
5367   if (_start)
5368     *_start = start;
5369   if (_stop)
5370     *_stop = stop;
5371
5372   return TRUE;
5373 }
5374
5375 /* activate the given segment number @seg_idx of @stream at time @offset.
5376  * @offset is an absolute global position over all the segments.
5377  *
5378  * This will push out a NEWSEGMENT event with the right values and
5379  * position the stream index to the first decodable sample before
5380  * @offset.
5381  */
5382 static gboolean
5383 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5384     guint32 seg_idx, GstClockTime offset)
5385 {
5386   QtDemuxSegment *segment;
5387   guint32 index, kf_index;
5388   GstClockTime start = 0, stop = GST_CLOCK_TIME_NONE;
5389
5390   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
5391       seg_idx, GST_TIME_ARGS (offset));
5392
5393   if (!gst_qtdemux_stream_update_segment (qtdemux, stream, seg_idx, offset,
5394           &start, &stop))
5395     return FALSE;
5396
5397   segment = &stream->segments[stream->segment_index];
5398
5399   /* in the fragmented case, we pick a fragment that starts before our
5400    * desired position and rely on downstream to wait for a keyframe
5401    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
5402    * tfra entries tells us which trun/sample the key unit is in, but we don't
5403    * make use of this additional information at the moment) */
5404   if (qtdemux->fragmented) {
5405     stream->to_sample = G_MAXUINT32;
5406     return TRUE;
5407   }
5408
5409   /* We don't need to look for a sample in push-based */
5410   if (!qtdemux->pullbased)
5411     return TRUE;
5412
5413   /* and move to the keyframe before the indicated media time of the
5414    * segment */
5415   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
5416     if (qtdemux->segment.rate >= 0) {
5417       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
5418       stream->to_sample = G_MAXUINT32;
5419       GST_DEBUG_OBJECT (stream->pad,
5420           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5421           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
5422           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5423     } else {
5424       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
5425       stream->to_sample = index;
5426       GST_DEBUG_OBJECT (stream->pad,
5427           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
5428           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
5429           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
5430     }
5431   } else {
5432     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
5433         "this is an empty segment");
5434     return TRUE;
5435   }
5436
5437   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
5438    * encountered an error and printed a message so we return appropriately */
5439   if (index == -1)
5440     return FALSE;
5441
5442   /* we're at the right spot */
5443   if (index == stream->sample_index) {
5444     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
5445     return TRUE;
5446   }
5447
5448   /* find keyframe of the target index */
5449   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index, FALSE);
5450
5451 /* *INDENT-OFF* */
5452 /* indent does stupid stuff with stream->samples[].timestamp */
5453
5454   /* if we move forwards, we don't have to go back to the previous
5455    * keyframe since we already sent that. We can also just jump to
5456    * the keyframe right before the target index if there is one. */
5457   if (index > stream->sample_index) {
5458     /* moving forwards check if we move past a keyframe */
5459     if (kf_index > stream->sample_index) {
5460       GST_DEBUG_OBJECT (stream->pad,
5461            "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5462            GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5463            GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5464       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5465     } else {
5466       GST_DEBUG_OBJECT (stream->pad,
5467           "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
5468           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
5469           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
5470     }
5471   } else {
5472     GST_DEBUG_OBJECT (stream->pad,
5473         "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
5474         GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
5475         GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
5476     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
5477   }
5478
5479 /* *INDENT-ON* */
5480
5481   return TRUE;
5482 }
5483
5484 /* prepare to get the current sample of @stream, getting essential values.
5485  *
5486  * This function will also prepare and send the segment when needed.
5487  *
5488  * Return FALSE if the stream is EOS.
5489  *
5490  * PULL-BASED
5491  */
5492 static gboolean
5493 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
5494     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
5495     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
5496     gboolean * keyframe)
5497 {
5498   QtDemuxSample *sample;
5499   GstClockTime time_position;
5500   guint32 seg_idx;
5501
5502   g_return_val_if_fail (stream != NULL, FALSE);
5503
5504   time_position = stream->time_position;
5505   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
5506     goto eos;
5507
5508   seg_idx = stream->segment_index;
5509   if (G_UNLIKELY (seg_idx == -1)) {
5510     /* find segment corresponding to time_position if we are looking
5511      * for a segment. */
5512     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
5513   }
5514
5515   /* different segment, activate it, sample_index will be set. */
5516   if (G_UNLIKELY (stream->segment_index != seg_idx))
5517     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
5518
5519   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
5520                   segment_index]))) {
5521     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
5522
5523     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
5524         " prepare empty sample");
5525
5526     *empty = TRUE;
5527     *pts = *dts = time_position;
5528     *duration = seg->duration - (time_position - seg->time);
5529
5530     return TRUE;
5531   }
5532
5533   *empty = FALSE;
5534
5535   if (stream->sample_index == -1)
5536     stream->sample_index = 0;
5537
5538   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
5539       stream->sample_index, stream->n_samples);
5540
5541   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
5542     if (!qtdemux->fragmented)
5543       goto eos;
5544
5545     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
5546     do {
5547       GstFlowReturn flow;
5548
5549       GST_OBJECT_LOCK (qtdemux);
5550       flow = qtdemux_add_fragmented_samples (qtdemux);
5551       GST_OBJECT_UNLOCK (qtdemux);
5552
5553       if (flow != GST_FLOW_OK)
5554         goto eos;
5555     }
5556     while (stream->sample_index >= stream->n_samples);
5557   }
5558
5559   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5560     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5561         stream->sample_index);
5562     return FALSE;
5563   }
5564
5565   /* now get the info for the sample we're at */
5566   sample = &stream->samples[stream->sample_index];
5567
5568   *dts = QTSAMPLE_DTS (stream, sample);
5569   *pts = QTSAMPLE_PTS (stream, sample);
5570   *offset = sample->offset;
5571   *size = sample->size;
5572   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
5573   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5574
5575   return TRUE;
5576
5577   /* special cases */
5578 eos:
5579   {
5580     stream->time_position = GST_CLOCK_TIME_NONE;
5581     return FALSE;
5582   }
5583 }
5584
5585 /* move to the next sample in @stream.
5586  *
5587  * Moves to the next segment when needed.
5588  */
5589 static void
5590 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
5591 {
5592   QtDemuxSample *sample;
5593   QtDemuxSegment *segment;
5594
5595   /* get current segment */
5596   segment = &stream->segments[stream->segment_index];
5597
5598   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5599     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5600     goto next_segment;
5601   }
5602
5603   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5604     /* Mark the stream as EOS */
5605     GST_DEBUG_OBJECT (qtdemux,
5606         "reached max allowed sample %u, mark EOS", stream->to_sample);
5607     stream->time_position = GST_CLOCK_TIME_NONE;
5608     return;
5609   }
5610
5611   /* move to next sample */
5612   stream->sample_index++;
5613   stream->offset_in_sample = 0;
5614
5615   /* reached the last sample, we need the next segment */
5616   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5617     goto next_segment;
5618
5619   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5620     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5621         stream->sample_index);
5622     return;
5623   }
5624
5625   /* get next sample */
5626   sample = &stream->samples[stream->sample_index];
5627
5628   /* see if we are past the segment */
5629   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5630     goto next_segment;
5631
5632   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5633     /* inside the segment, update time_position, looks very familiar to
5634      * GStreamer segments, doesn't it? */
5635     stream->time_position =
5636         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5637   } else {
5638     /* not yet in segment, time does not yet increment. This means
5639      * that we are still prerolling keyframes to the decoder so it can
5640      * decode the first sample of the segment. */
5641     stream->time_position = segment->time;
5642   }
5643   return;
5644
5645   /* move to the next segment */
5646 next_segment:
5647   {
5648     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5649
5650     if (stream->segment_index == stream->n_segments - 1) {
5651       /* are we at the end of the last segment, we're EOS */
5652       stream->time_position = GST_CLOCK_TIME_NONE;
5653     } else {
5654       /* else we're only at the end of the current segment */
5655       stream->time_position = segment->stop_time;
5656     }
5657     /* make sure we select a new segment */
5658
5659     /* accumulate previous segments */
5660     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5661       stream->accumulated_base +=
5662           (stream->segment.stop -
5663           stream->segment.start) / ABS (stream->segment.rate);
5664
5665     stream->segment_index = -1;
5666   }
5667 }
5668
5669 static void
5670 gst_qtdemux_sync_streams (GstQTDemux * demux)
5671 {
5672   gint i;
5673
5674   if (demux->n_streams <= 1)
5675     return;
5676
5677   for (i = 0; i < demux->n_streams; i++) {
5678     QtDemuxStream *stream;
5679     GstClockTime end_time;
5680
5681     stream = demux->streams[i];
5682
5683     if (!stream->pad)
5684       continue;
5685
5686     /* TODO advance time on subtitle streams here, if any some day */
5687
5688     /* some clips/trailers may have unbalanced streams at the end,
5689      * so send EOS on shorter stream to prevent stalling others */
5690
5691     /* do not mess with EOS if SEGMENT seeking */
5692     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5693       continue;
5694
5695     if (demux->pullbased) {
5696       /* loop mode is sample time based */
5697       if (!STREAM_IS_EOS (stream))
5698         continue;
5699     } else {
5700       /* push mode is byte position based */
5701       if (stream->n_samples &&
5702           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5703         continue;
5704     }
5705
5706     if (stream->sent_eos)
5707       continue;
5708
5709     /* only act if some gap */
5710     end_time = stream->segments[stream->n_segments - 1].stop_time;
5711     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5712         ", stream end: %" GST_TIME_FORMAT,
5713         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5714     if (GST_CLOCK_TIME_IS_VALID (end_time)
5715         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5716       GstEvent *event;
5717
5718       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5719           GST_PAD_NAME (stream->pad));
5720       stream->sent_eos = TRUE;
5721       event = gst_event_new_eos ();
5722       if (demux->segment_seqnum)
5723         gst_event_set_seqnum (event, demux->segment_seqnum);
5724       gst_pad_push_event (stream->pad, event);
5725     }
5726   }
5727 }
5728
5729 /* EOS and NOT_LINKED need to be combined. This means that we return:
5730  *
5731  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5732  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5733  */
5734 static GstFlowReturn
5735 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5736     GstFlowReturn ret)
5737 {
5738   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5739
5740   if (stream->pad)
5741     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5742         ret);
5743   else
5744     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5745
5746   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5747   return ret;
5748 }
5749
5750 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5751  * completely clipped
5752  *
5753  * Should be used only with raw buffers */
5754 static GstBuffer *
5755 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5756     GstBuffer * buf)
5757 {
5758   guint64 start, stop, cstart, cstop, diff;
5759   GstClockTime pts, duration;
5760   gsize size, osize;
5761   gint num_rate, denom_rate;
5762   gint frame_size;
5763   gboolean clip_data;
5764   guint offset;
5765
5766   osize = size = gst_buffer_get_size (buf);
5767   offset = 0;
5768
5769   /* depending on the type, setup the clip parameters */
5770   if (stream->subtype == FOURCC_soun) {
5771     frame_size = CUR_STREAM (stream)->bytes_per_frame;
5772     num_rate = GST_SECOND;
5773     denom_rate = (gint) CUR_STREAM (stream)->rate;
5774     clip_data = TRUE;
5775   } else if (stream->subtype == FOURCC_vide) {
5776     frame_size = size;
5777     num_rate = CUR_STREAM (stream)->fps_n;
5778     denom_rate = CUR_STREAM (stream)->fps_d;
5779     clip_data = FALSE;
5780   } else
5781     goto wrong_type;
5782
5783   if (frame_size <= 0)
5784     goto bad_frame_size;
5785
5786   /* we can only clip if we have a valid pts */
5787   pts = GST_BUFFER_PTS (buf);
5788   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5789     goto no_pts;
5790
5791   duration = GST_BUFFER_DURATION (buf);
5792
5793   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5794     duration =
5795         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5796   }
5797
5798   start = pts;
5799   stop = start + duration;
5800
5801   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5802               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5803     goto clipped;
5804
5805   /* see if some clipping happened */
5806   diff = cstart - start;
5807   if (diff > 0) {
5808     pts += diff;
5809     duration -= diff;
5810
5811     if (clip_data) {
5812       /* bring clipped time to samples and to bytes */
5813       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5814       diff *= frame_size;
5815
5816       GST_DEBUG_OBJECT (qtdemux,
5817           "clipping start to %" GST_TIME_FORMAT " %"
5818           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5819
5820       offset = diff;
5821       size -= diff;
5822     }
5823   }
5824   diff = stop - cstop;
5825   if (diff > 0) {
5826     duration -= diff;
5827
5828     if (clip_data) {
5829       /* bring clipped time to samples and then to bytes */
5830       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5831       diff *= frame_size;
5832       GST_DEBUG_OBJECT (qtdemux,
5833           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5834           " bytes", GST_TIME_ARGS (cstop), diff);
5835       size -= diff;
5836     }
5837   }
5838
5839   if (offset != 0 || size != osize)
5840     gst_buffer_resize (buf, offset, size);
5841
5842   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5843   GST_BUFFER_PTS (buf) = pts;
5844   GST_BUFFER_DURATION (buf) = duration;
5845
5846   return buf;
5847
5848   /* dropped buffer */
5849 wrong_type:
5850   {
5851     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5852     return buf;
5853   }
5854 bad_frame_size:
5855   {
5856     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5857     return buf;
5858   }
5859 no_pts:
5860   {
5861     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5862     return buf;
5863   }
5864 clipped:
5865   {
5866     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5867     gst_buffer_unref (buf);
5868     return NULL;
5869   }
5870 }
5871
5872 static GstBuffer *
5873 gst_qtdemux_align_buffer (GstQTDemux * demux,
5874     GstBuffer * buffer, gsize alignment)
5875 {
5876   GstMapInfo map;
5877
5878   gst_buffer_map (buffer, &map, GST_MAP_READ);
5879
5880   if (map.size < sizeof (guintptr)) {
5881     gst_buffer_unmap (buffer, &map);
5882     return buffer;
5883   }
5884
5885   if (((guintptr) map.data) & (alignment - 1)) {
5886     GstBuffer *new_buffer;
5887     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5888
5889     new_buffer = gst_buffer_new_allocate (NULL,
5890         gst_buffer_get_size (buffer), &params);
5891
5892     /* Copy data "by hand", so ensure alignment is kept: */
5893     gst_buffer_fill (new_buffer, 0, map.data, map.size);
5894
5895     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5896     GST_DEBUG_OBJECT (demux,
5897         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5898         alignment);
5899
5900     gst_buffer_unmap (buffer, &map);
5901     gst_buffer_unref (buffer);
5902
5903     return new_buffer;
5904   }
5905
5906   gst_buffer_unmap (buffer, &map);
5907   return buffer;
5908 }
5909
5910 /* the input buffer metadata must be writable,
5911  * but time/duration etc not yet set and need not be preserved */
5912 static GstBuffer *
5913 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5914     GstBuffer * buf)
5915 {
5916   GstMapInfo map;
5917   guint nsize = 0;
5918   gchar *str;
5919
5920   /* not many cases for now */
5921   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_mp4s)) {
5922     /* send a one time dvd clut event */
5923     if (stream->pending_event && stream->pad)
5924       gst_pad_push_event (stream->pad, stream->pending_event);
5925     stream->pending_event = NULL;
5926   }
5927
5928   if (G_UNLIKELY (stream->subtype != FOURCC_text
5929           && stream->subtype != FOURCC_sbtl &&
5930           stream->subtype != FOURCC_subp)) {
5931     return buf;
5932   }
5933
5934   gst_buffer_map (buf, &map, GST_MAP_READ);
5935
5936   /* empty buffer is sent to terminate previous subtitle */
5937   if (map.size <= 2) {
5938     gst_buffer_unmap (buf, &map);
5939     gst_buffer_unref (buf);
5940     return NULL;
5941   }
5942   if (stream->subtype == FOURCC_subp) {
5943     /* That's all the processing needed for subpictures */
5944     gst_buffer_unmap (buf, &map);
5945     return buf;
5946   }
5947
5948   nsize = GST_READ_UINT16_BE (map.data);
5949   nsize = MIN (nsize, map.size - 2);
5950
5951   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5952       nsize, map.size);
5953
5954   /* takes care of UTF-8 validation or UTF-16 recognition,
5955    * no other encoding expected */
5956   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5957   gst_buffer_unmap (buf, &map);
5958   if (str) {
5959     gst_buffer_unref (buf);
5960     buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5961   } else {
5962     /* this should not really happen unless the subtitle is corrupted */
5963     gst_buffer_unref (buf);
5964     buf = NULL;
5965   }
5966
5967   /* FIXME ? convert optional subsequent style info to markup */
5968
5969   return buf;
5970 }
5971
5972 /* Sets a buffer's attributes properly and pushes it downstream.
5973  * Also checks for additional actions and custom processing that may
5974  * need to be done first.
5975  */
5976 static GstFlowReturn
5977 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5978     QtDemuxStream * stream, GstBuffer * buf,
5979     GstClockTime dts, GstClockTime pts, GstClockTime duration,
5980     gboolean keyframe, GstClockTime position, guint64 byte_position)
5981 {
5982   GstFlowReturn ret = GST_FLOW_OK;
5983
5984   /* offset the timestamps according to the edit list */
5985
5986   if (G_UNLIKELY (CUR_STREAM (stream)->fourcc == FOURCC_rtsp)) {
5987     gchar *url;
5988     GstMapInfo map;
5989
5990     gst_buffer_map (buf, &map, GST_MAP_READ);
5991     url = g_strndup ((gchar *) map.data, map.size);
5992     gst_buffer_unmap (buf, &map);
5993     if (url != NULL && strlen (url) != 0) {
5994       /* we have RTSP redirect now */
5995       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5996           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5997               gst_structure_new ("redirect",
5998                   "new-location", G_TYPE_STRING, url, NULL)));
5999       qtdemux->posted_redirect = TRUE;
6000     } else {
6001       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
6002           "posting");
6003     }
6004     g_free (url);
6005   }
6006
6007   /* position reporting */
6008   if (qtdemux->segment.rate >= 0) {
6009     qtdemux->segment.position = position;
6010     gst_qtdemux_sync_streams (qtdemux);
6011   }
6012
6013   if (G_UNLIKELY (!stream->pad)) {
6014     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
6015     gst_buffer_unref (buf);
6016     goto exit;
6017   }
6018
6019   /* send out pending buffers */
6020   while (stream->buffers) {
6021     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
6022
6023     if (G_UNLIKELY (stream->discont)) {
6024       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6025       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
6026       stream->discont = FALSE;
6027     } else {
6028       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6029     }
6030
6031     if (stream->alignment > 1)
6032       buffer = gst_qtdemux_align_buffer (qtdemux, buffer, stream->alignment);
6033     gst_pad_push (stream->pad, buffer);
6034
6035     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
6036   }
6037
6038   /* we're going to modify the metadata */
6039   buf = gst_buffer_make_writable (buf);
6040
6041   if (G_UNLIKELY (stream->need_process))
6042     buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
6043
6044   if (!buf) {
6045     goto exit;
6046   }
6047
6048   GST_BUFFER_DTS (buf) = dts;
6049   GST_BUFFER_PTS (buf) = pts;
6050   GST_BUFFER_DURATION (buf) = duration;
6051   GST_BUFFER_OFFSET (buf) = -1;
6052   GST_BUFFER_OFFSET_END (buf) = -1;
6053
6054   if (G_UNLIKELY (CUR_STREAM (stream)->rgb8_palette))
6055     gst_buffer_append_memory (buf,
6056         gst_memory_ref (CUR_STREAM (stream)->rgb8_palette));
6057
6058   if (G_UNLIKELY (CUR_STREAM (stream)->padding)) {
6059     gst_buffer_resize (buf, CUR_STREAM (stream)->padding, -1);
6060   }
6061 #if 0
6062   if (G_UNLIKELY (qtdemux->element_index)) {
6063     GstClockTime stream_time;
6064
6065     stream_time =
6066         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
6067         timestamp);
6068     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
6069       GST_LOG_OBJECT (qtdemux,
6070           "adding association %" GST_TIME_FORMAT "-> %"
6071           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
6072       gst_index_add_association (qtdemux->element_index,
6073           qtdemux->index_id,
6074           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
6075           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
6076           GST_FORMAT_BYTES, byte_position, NULL);
6077     }
6078   }
6079 #endif
6080
6081   if (stream->need_clip)
6082     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
6083
6084   if (G_UNLIKELY (buf == NULL))
6085     goto exit;
6086
6087   if (G_UNLIKELY (stream->discont)) {
6088     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
6089     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
6090     stream->discont = FALSE;
6091   } else {
6092     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
6093   }
6094
6095   if (!keyframe) {
6096     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
6097     stream->on_keyframe = FALSE;
6098   } else {
6099     stream->on_keyframe = TRUE;
6100   }
6101
6102
6103   GST_LOG_OBJECT (qtdemux,
6104       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
6105       ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
6106       GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
6107       GST_PAD_NAME (stream->pad));
6108
6109   if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
6110     GstStructure *crypto_info;
6111     QtDemuxCencSampleSetInfo *info =
6112         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6113     gint index;
6114     GstEvent *event;
6115
6116     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
6117       gst_pad_push_event (stream->pad, event);
6118     }
6119
6120     if (info->crypto_info == NULL) {
6121       GST_DEBUG_OBJECT (qtdemux, "cenc metadata hasn't been parsed yet");
6122       gst_buffer_unref (buf);
6123       goto exit;
6124     }
6125
6126     /* The end of the crypto_info array matches our n_samples position,
6127      * so count backward from there */
6128     index = stream->sample_index - stream->n_samples + info->crypto_info->len;
6129     if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
6130       /* steal structure from array */
6131       crypto_info = g_ptr_array_index (info->crypto_info, index);
6132       g_ptr_array_index (info->crypto_info, index) = NULL;
6133       GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u/%u]", index,
6134           info->crypto_info->len);
6135       if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
6136         GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
6137     } else {
6138       GST_INFO_OBJECT (qtdemux, "No crypto info with index %d and sample %d",
6139           index, stream->sample_index);
6140     }
6141   }
6142
6143   if (stream->alignment > 1)
6144     buf = gst_qtdemux_align_buffer (qtdemux, buf, stream->alignment);
6145
6146   ret = gst_pad_push (stream->pad, buf);
6147
6148   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
6149     /* mark position in stream, we'll need this to know when to send GAP event */
6150     stream->segment.position = pts + duration;
6151   }
6152
6153 exit:
6154   return ret;
6155 }
6156
6157 static const QtDemuxRandomAccessEntry *
6158 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
6159     GstClockTime pos, gboolean after)
6160 {
6161   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
6162   guint n_entries = stream->n_ra_entries;
6163   guint i;
6164
6165   /* we assume the table is sorted */
6166   for (i = 0; i < n_entries; ++i) {
6167     if (entries[i].ts > pos)
6168       break;
6169   }
6170
6171   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
6172    * probably okay to assume that the index lists the very first fragment */
6173   if (i == 0)
6174     return &entries[0];
6175
6176   if (after)
6177     return &entries[i];
6178   else
6179     return &entries[i - 1];
6180 }
6181
6182 static gboolean
6183 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
6184 {
6185   const QtDemuxRandomAccessEntry *best_entry = NULL;
6186   guint i;
6187
6188   GST_OBJECT_LOCK (qtdemux);
6189
6190   g_assert (qtdemux->n_streams > 0);
6191
6192   for (i = 0; i < qtdemux->n_streams; i++) {
6193     const QtDemuxRandomAccessEntry *entry;
6194     QtDemuxStream *stream;
6195     gboolean is_audio_or_video;
6196
6197     stream = qtdemux->streams[i];
6198
6199     g_free (stream->samples);
6200     stream->samples = NULL;
6201     stream->n_samples = 0;
6202     stream->stbl_index = -1;    /* no samples have yet been parsed */
6203     stream->sample_index = -1;
6204
6205     if (stream->protection_scheme_info) {
6206       /* Clear out any old cenc crypto info entries as we'll move to a new moof */
6207       if (stream->protection_scheme_type == FOURCC_cenc) {
6208         QtDemuxCencSampleSetInfo *info =
6209             (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
6210         if (info->crypto_info) {
6211           g_ptr_array_free (info->crypto_info, TRUE);
6212           info->crypto_info = NULL;
6213         }
6214       }
6215     }
6216
6217     if (stream->ra_entries == NULL)
6218       continue;
6219
6220     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
6221       is_audio_or_video = TRUE;
6222     else
6223       is_audio_or_video = FALSE;
6224
6225     entry =
6226         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
6227         stream->time_position, !is_audio_or_video);
6228
6229     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
6230         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
6231
6232     stream->pending_seek = entry;
6233
6234     /* decide position to jump to just based on audio/video tracks, not subs */
6235     if (!is_audio_or_video)
6236       continue;
6237
6238     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
6239       best_entry = entry;
6240   }
6241
6242   if (best_entry == NULL) {
6243     GST_OBJECT_UNLOCK (qtdemux);
6244     return FALSE;
6245   }
6246
6247   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
6248       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
6249       GST_TIME_ARGS (qtdemux->streams[0]->time_position),
6250       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
6251
6252   qtdemux->moof_offset = best_entry->moof_offset;
6253
6254   qtdemux_add_fragmented_samples (qtdemux);
6255
6256   GST_OBJECT_UNLOCK (qtdemux);
6257   return TRUE;
6258 }
6259
6260 static GstFlowReturn
6261 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
6262 {
6263   GstFlowReturn ret = GST_FLOW_OK;
6264   GstBuffer *buf = NULL;
6265   QtDemuxStream *stream;
6266   GstClockTime min_time;
6267   guint64 offset = 0;
6268   GstClockTime dts = GST_CLOCK_TIME_NONE;
6269   GstClockTime pts = GST_CLOCK_TIME_NONE;
6270   GstClockTime duration = 0;
6271   gboolean keyframe = FALSE;
6272   guint sample_size = 0;
6273   gboolean empty = 0;
6274   guint size;
6275   gint index;
6276   gint i;
6277
6278   gst_qtdemux_push_pending_newsegment (qtdemux);
6279
6280   if (qtdemux->fragmented_seek_pending) {
6281     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
6282     gst_qtdemux_do_fragmented_seek (qtdemux);
6283     GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
6284     qtdemux->fragmented_seek_pending = FALSE;
6285   }
6286
6287   /* Figure out the next stream sample to output, min_time is expressed in
6288    * global time and runs over the edit list segments. */
6289   min_time = G_MAXUINT64;
6290   index = -1;
6291   for (i = 0; i < qtdemux->n_streams; i++) {
6292     GstClockTime position;
6293
6294     stream = qtdemux->streams[i];
6295     position = stream->time_position;
6296
6297     /* position of -1 is EOS */
6298     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
6299       min_time = position;
6300       index = i;
6301     }
6302   }
6303   /* all are EOS */
6304   if (G_UNLIKELY (index == -1)) {
6305     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
6306     goto eos;
6307   }
6308
6309   /* check for segment end */
6310   if (G_UNLIKELY (qtdemux->segment.stop != -1
6311           && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
6312               || (qtdemux->segment.rate < 0
6313                   && qtdemux->segment.start > min_time))
6314           && qtdemux->streams[index]->on_keyframe)) {
6315     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
6316     qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
6317     goto eos_stream;
6318   }
6319
6320   /* gap events for subtitle streams */
6321   for (i = 0; i < qtdemux->n_streams; i++) {
6322     stream = qtdemux->streams[i];
6323     if (stream->pad && (stream->subtype == FOURCC_subp
6324             || stream->subtype == FOURCC_text
6325             || stream->subtype == FOURCC_sbtl)) {
6326       /* send one second gap events until the stream catches up */
6327       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
6328       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
6329           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
6330           stream->segment.position + GST_SECOND < min_time) {
6331         GstEvent *gap =
6332             gst_event_new_gap (stream->segment.position, GST_SECOND);
6333         gst_pad_push_event (stream->pad, gap);
6334         stream->segment.position += GST_SECOND;
6335       }
6336     }
6337   }
6338
6339   stream = qtdemux->streams[index];
6340   /* fetch info for the current sample of this stream */
6341   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
6342               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
6343     goto eos_stream;
6344
6345   gst_qtdemux_stream_check_and_change_stsd_index (qtdemux, stream);
6346   if (stream->new_caps) {
6347     gst_qtdemux_configure_stream (qtdemux, stream);
6348     qtdemux_do_allocation (qtdemux, stream);
6349   }
6350
6351   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
6352   if (G_UNLIKELY (qtdemux->
6353           segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
6354     if (stream->subtype == FOURCC_vide && !keyframe) {
6355       GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
6356       goto next;
6357     }
6358   }
6359
6360   GST_DEBUG_OBJECT (qtdemux,
6361       "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
6362       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
6363       ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
6364       GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
6365
6366   if (G_UNLIKELY (empty)) {
6367     /* empty segment, push a gap and move to the next one */
6368     gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
6369     stream->segment.position = pts + duration;
6370     goto next;
6371   }
6372
6373   /* hmm, empty sample, skip and move to next sample */
6374   if (G_UNLIKELY (sample_size <= 0))
6375     goto next;
6376
6377   /* last pushed sample was out of boundary, goto next sample */
6378   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
6379     goto next;
6380
6381   if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
6382     size = sample_size;
6383   } else {
6384     GST_DEBUG_OBJECT (qtdemux,
6385         "size %d larger than stream max_buffer_size %d, trimming",
6386         sample_size, stream->max_buffer_size);
6387     size =
6388         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
6389   }
6390
6391   if (qtdemux->cenc_aux_info_offset > 0) {
6392     GstMapInfo map;
6393     GstByteReader br;
6394     GstBuffer *aux_info = NULL;
6395
6396     /* pull the data stored before the sample */
6397     ret =
6398         gst_qtdemux_pull_atom (qtdemux, qtdemux->offset,
6399         offset + stream->offset_in_sample - qtdemux->offset, &aux_info);
6400     if (G_UNLIKELY (ret != GST_FLOW_OK))
6401       goto beach;
6402     gst_buffer_map (aux_info, &map, GST_MAP_READ);
6403     GST_DEBUG_OBJECT (qtdemux, "parsing cenc auxiliary info");
6404     gst_byte_reader_init (&br, map.data + 8, map.size);
6405     if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
6406             qtdemux->cenc_aux_info_sizes, qtdemux->cenc_aux_sample_count)) {
6407       GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
6408       gst_buffer_unmap (aux_info, &map);
6409       gst_buffer_unref (aux_info);
6410       ret = GST_FLOW_ERROR;
6411       goto beach;
6412     }
6413     gst_buffer_unmap (aux_info, &map);
6414     gst_buffer_unref (aux_info);
6415   }
6416
6417   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
6418       offset);
6419
6420   if (stream->use_allocator) {
6421     /* if we have a per-stream allocator, use it */
6422     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
6423   }
6424
6425   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
6426       size, &buf);
6427   if (G_UNLIKELY (ret != GST_FLOW_OK))
6428     goto beach;
6429
6430   if (size != sample_size) {
6431     pts += gst_util_uint64_scale_int (GST_SECOND,
6432         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6433         stream->timescale);
6434     dts +=
6435         gst_util_uint64_scale_int (GST_SECOND,
6436         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame,
6437         stream->timescale);
6438     duration =
6439         gst_util_uint64_scale_int (GST_SECOND,
6440         size / CUR_STREAM (stream)->bytes_per_frame, stream->timescale);
6441   }
6442
6443   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
6444       dts, pts, duration, keyframe, min_time, offset);
6445
6446   if (size != sample_size) {
6447     QtDemuxSample *sample = &stream->samples[stream->sample_index];
6448     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
6449
6450     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
6451         sample->timestamp +
6452         stream->offset_in_sample / CUR_STREAM (stream)->bytes_per_frame);
6453     if (time_position >= segment->media_start) {
6454       /* inside the segment, update time_position, looks very familiar to
6455        * GStreamer segments, doesn't it? */
6456       stream->time_position = (time_position - segment->media_start) +
6457           segment->time;
6458     } else {
6459       /* not yet in segment, time does not yet increment. This means
6460        * that we are still prerolling keyframes to the decoder so it can
6461        * decode the first sample of the segment. */
6462       stream->time_position = segment->time;
6463     }
6464   }
6465
6466   /* combine flows */
6467   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
6468   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
6469    * we have no more data for the pad to push */
6470   if (ret == GST_FLOW_EOS)
6471     ret = GST_FLOW_OK;
6472
6473   stream->offset_in_sample += size;
6474   if (stream->offset_in_sample >= sample_size) {
6475     gst_qtdemux_advance_sample (qtdemux, stream);
6476   }
6477   goto beach;
6478
6479 next:
6480   gst_qtdemux_advance_sample (qtdemux, stream);
6481
6482 beach:
6483   return ret;
6484
6485   /* special cases */
6486 eos:
6487   {
6488     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
6489     ret = GST_FLOW_EOS;
6490     goto beach;
6491   }
6492 eos_stream:
6493   {
6494     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
6495     /* EOS will be raised if all are EOS */
6496     ret = GST_FLOW_OK;
6497     goto beach;
6498   }
6499 }
6500
6501 static void
6502 gst_qtdemux_loop (GstPad * pad)
6503 {
6504   GstQTDemux *qtdemux;
6505   guint64 cur_offset;
6506   GstFlowReturn ret;
6507
6508   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
6509
6510   cur_offset = qtdemux->offset;
6511   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %s",
6512       cur_offset, qt_demux_state_string (qtdemux->state));
6513
6514   switch (qtdemux->state) {
6515     case QTDEMUX_STATE_INITIAL:
6516     case QTDEMUX_STATE_HEADER:
6517       ret = gst_qtdemux_loop_state_header (qtdemux);
6518       break;
6519     case QTDEMUX_STATE_MOVIE:
6520       ret = gst_qtdemux_loop_state_movie (qtdemux);
6521       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
6522         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
6523       }
6524       break;
6525     default:
6526       /* ouch */
6527       goto invalid_state;
6528   }
6529
6530   /* if something went wrong, pause */
6531   if (ret != GST_FLOW_OK)
6532     goto pause;
6533
6534 done:
6535   gst_object_unref (qtdemux);
6536   return;
6537
6538   /* ERRORS */
6539 invalid_state:
6540   {
6541     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
6542         (NULL), ("streaming stopped, invalid state"));
6543     gst_pad_pause_task (pad);
6544     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6545     goto done;
6546   }
6547 pause:
6548   {
6549     const gchar *reason = gst_flow_get_name (ret);
6550
6551     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
6552
6553     gst_pad_pause_task (pad);
6554
6555     /* fatal errors need special actions */
6556     /* check EOS */
6557     if (ret == GST_FLOW_EOS) {
6558       if (qtdemux->n_streams == 0) {
6559         /* we have no streams, post an error */
6560         gst_qtdemux_post_no_playable_stream_error (qtdemux);
6561       }
6562       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
6563         gint64 stop;
6564
6565         if ((stop = qtdemux->segment.stop) == -1)
6566           stop = qtdemux->segment.duration;
6567
6568         if (qtdemux->segment.rate >= 0) {
6569           GstMessage *message;
6570           GstEvent *event;
6571
6572           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
6573           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6574               GST_FORMAT_TIME, stop);
6575           event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
6576           if (qtdemux->segment_seqnum) {
6577             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6578             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6579           }
6580           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6581           gst_qtdemux_push_event (qtdemux, event);
6582         } else {
6583           GstMessage *message;
6584           GstEvent *event;
6585
6586           /*  For Reverse Playback */
6587           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
6588           message = gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
6589               GST_FORMAT_TIME, qtdemux->segment.start);
6590           event = gst_event_new_segment_done (GST_FORMAT_TIME,
6591               qtdemux->segment.start);
6592           if (qtdemux->segment_seqnum) {
6593             gst_message_set_seqnum (message, qtdemux->segment_seqnum);
6594             gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6595           }
6596           gst_element_post_message (GST_ELEMENT_CAST (qtdemux), message);
6597           gst_qtdemux_push_event (qtdemux, event);
6598         }
6599       } else {
6600         GstEvent *event;
6601
6602         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
6603         event = gst_event_new_eos ();
6604         if (qtdemux->segment_seqnum)
6605           gst_event_set_seqnum (event, qtdemux->segment_seqnum);
6606         gst_qtdemux_push_event (qtdemux, event);
6607       }
6608     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
6609       GST_ELEMENT_FLOW_ERROR (qtdemux, ret);
6610       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
6611     }
6612     goto done;
6613   }
6614 }
6615
6616 /*
6617  * has_next_entry
6618  *
6619  * Returns if there are samples to be played.
6620  */
6621 static gboolean
6622 has_next_entry (GstQTDemux * demux)
6623 {
6624   QtDemuxStream *stream;
6625   int i;
6626
6627   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
6628
6629   for (i = 0; i < demux->n_streams; i++) {
6630     stream = demux->streams[i];
6631
6632     if (stream->sample_index == -1) {
6633       stream->sample_index = 0;
6634       stream->offset_in_sample = 0;
6635     }
6636
6637     if (stream->sample_index >= stream->n_samples) {
6638       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6639       continue;
6640     }
6641     GST_DEBUG_OBJECT (demux, "Found a sample");
6642     return TRUE;
6643   }
6644
6645   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
6646   return FALSE;
6647 }
6648
6649 /*
6650  * next_entry_size
6651  *
6652  * Returns the size of the first entry at the current offset.
6653  * If -1, there are none (which means EOS or empty file).
6654  */
6655 static guint64
6656 next_entry_size (GstQTDemux * demux)
6657 {
6658   QtDemuxStream *stream;
6659   int i;
6660   int smallidx = -1;
6661   guint64 smalloffs = (guint64) - 1;
6662   QtDemuxSample *sample;
6663
6664   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
6665       demux->offset);
6666
6667   for (i = 0; i < demux->n_streams; i++) {
6668     stream = demux->streams[i];
6669
6670     if (stream->sample_index == -1) {
6671       stream->sample_index = 0;
6672       stream->offset_in_sample = 0;
6673     }
6674
6675     if (stream->sample_index >= stream->n_samples) {
6676       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
6677       continue;
6678     }
6679
6680     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
6681       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
6682           stream->sample_index);
6683       return -1;
6684     }
6685
6686     sample = &stream->samples[stream->sample_index];
6687
6688     GST_LOG_OBJECT (demux,
6689         "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6690         " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
6691         sample->offset, sample->size);
6692
6693     if (((smalloffs == -1)
6694             || (sample->offset < smalloffs)) && (sample->size)) {
6695       smallidx = i;
6696       smalloffs = sample->offset;
6697     }
6698   }
6699
6700   GST_LOG_OBJECT (demux,
6701       "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
6702       G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
6703
6704   if (smallidx == -1)
6705     return -1;
6706
6707   stream = demux->streams[smallidx];
6708   sample = &stream->samples[stream->sample_index];
6709
6710   if (sample->offset >= demux->offset) {
6711     demux->todrop = sample->offset - demux->offset;
6712     return sample->size + demux->todrop;
6713   }
6714
6715   GST_DEBUG_OBJECT (demux,
6716       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
6717   return -1;
6718 }
6719
6720 static void
6721 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6722 {
6723   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6724
6725   gst_element_post_message (GST_ELEMENT_CAST (demux),
6726       gst_message_new_element (GST_OBJECT_CAST (demux),
6727           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6728 }
6729
6730 static gboolean
6731 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6732 {
6733   GstEvent *event;
6734   gboolean res = 0;
6735
6736   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6737
6738   event =
6739       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6740       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6741       GST_SEEK_TYPE_NONE, -1);
6742
6743   /* store seqnum to drop flush events, they don't need to reach downstream */
6744   demux->offset_seek_seqnum = gst_event_get_seqnum (event);
6745   res = gst_pad_push_event (demux->sinkpad, event);
6746   demux->offset_seek_seqnum = 0;
6747
6748   return res;
6749 }
6750
6751 /* check for seekable upstream, above and beyond a mere query */
6752 static void
6753 gst_qtdemux_check_seekability (GstQTDemux * demux)
6754 {
6755   GstQuery *query;
6756   gboolean seekable = FALSE;
6757   gint64 start = -1, stop = -1;
6758
6759   if (demux->upstream_size)
6760     return;
6761
6762   if (demux->upstream_format_is_time)
6763     return;
6764
6765   query = gst_query_new_seeking (GST_FORMAT_BYTES);
6766   if (!gst_pad_peer_query (demux->sinkpad, query)) {
6767     GST_DEBUG_OBJECT (demux, "seeking query failed");
6768     goto done;
6769   }
6770
6771   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6772
6773   /* try harder to query upstream size if we didn't get it the first time */
6774   if (seekable && stop == -1) {
6775     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6776     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6777   }
6778
6779   /* if upstream doesn't know the size, it's likely that it's not seekable in
6780    * practice even if it technically may be seekable */
6781   if (seekable && (start != 0 || stop <= start)) {
6782     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6783     seekable = FALSE;
6784   }
6785
6786 done:
6787   gst_query_unref (query);
6788
6789   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6790       G_GUINT64_FORMAT ")", seekable, start, stop);
6791   demux->upstream_seekable = seekable;
6792   demux->upstream_size = seekable ? stop : -1;
6793 }
6794
6795 static void
6796 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6797 {
6798   g_return_if_fail (bytes <= demux->todrop);
6799
6800   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6801   gst_adapter_flush (demux->adapter, bytes);
6802   demux->neededbytes -= bytes;
6803   demux->offset += bytes;
6804   demux->todrop -= bytes;
6805 }
6806
6807 static void
6808 gst_qtdemux_check_send_pending_segment (GstQTDemux * demux)
6809 {
6810   if (G_UNLIKELY (demux->pending_newsegment)) {
6811     gint i;
6812
6813     gst_qtdemux_push_pending_newsegment (demux);
6814     /* clear to send tags on all streams */
6815     for (i = 0; i < demux->n_streams; i++) {
6816       QtDemuxStream *stream;
6817       stream = demux->streams[i];
6818       gst_qtdemux_push_tags (demux, stream);
6819       if (CUR_STREAM (stream)->sparse) {
6820         GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6821         gst_pad_push_event (stream->pad,
6822             gst_event_new_gap (stream->segment.position, GST_CLOCK_TIME_NONE));
6823       }
6824     }
6825   }
6826 }
6827
6828 static void
6829 gst_qtdemux_send_gap_for_segment (GstQTDemux * demux,
6830     QtDemuxStream * stream, gint segment_index, GstClockTime pos)
6831 {
6832   GstClockTime ts, dur;
6833   GstEvent *gap;
6834
6835   ts = pos;
6836   dur =
6837       stream->segments[segment_index].duration - (pos -
6838       stream->segments[segment_index].time);
6839   gap = gst_event_new_gap (ts, dur);
6840   stream->time_position += dur;
6841
6842   GST_DEBUG_OBJECT (stream->pad, "Pushing gap for empty "
6843       "segment: %" GST_PTR_FORMAT, gap);
6844   gst_pad_push_event (stream->pad, gap);
6845 }
6846
6847 static void
6848 gst_qtdemux_stream_send_initial_gap_segments (GstQTDemux * demux,
6849     QtDemuxStream * stream)
6850 {
6851   gint i;
6852
6853   /* Push any initial gap segments before proceeding to the
6854    * 'real' data */
6855   for (i = 0; i < stream->n_segments; i++) {
6856     gst_qtdemux_activate_segment (demux, stream, i, stream->time_position);
6857
6858     if (QTSEGMENT_IS_EMPTY (&stream->segments[i])) {
6859       gst_qtdemux_send_gap_for_segment (demux, stream, i,
6860           stream->time_position);
6861     } else {
6862       /* Only support empty segment at the beginning followed by
6863        * one non-empty segment, this was checked when parsing the
6864        * edts atom, arriving here is unexpected */
6865       g_assert (i + 1 == stream->n_segments);
6866       break;
6867     }
6868   }
6869 }
6870
6871 static GstFlowReturn
6872 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6873 {
6874   GstQTDemux *demux;
6875
6876   demux = GST_QTDEMUX (parent);
6877
6878   GST_DEBUG_OBJECT (demux,
6879       "Received buffer pts:%" GST_TIME_FORMAT " dts:%" GST_TIME_FORMAT
6880       " offset:%" G_GUINT64_FORMAT " size:%" G_GSIZE_FORMAT " demux offset:%"
6881       G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_PTS (inbuf)),
6882       GST_TIME_ARGS (GST_BUFFER_DTS (inbuf)), GST_BUFFER_OFFSET (inbuf),
6883       gst_buffer_get_size (inbuf), demux->offset);
6884
6885   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6886     gboolean is_gap_input = FALSE;
6887     gint i;
6888
6889     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6890
6891     for (i = 0; i < demux->n_streams; i++) {
6892       demux->streams[i]->discont = TRUE;
6893     }
6894
6895     /* Check if we can land back on our feet in the case where upstream is
6896      * handling the seeking/pushing of samples with gaps in between (like
6897      * in the case of trick-mode DASH for example) */
6898     if (demux->upstream_format_is_time
6899         && GST_BUFFER_OFFSET (inbuf) != GST_BUFFER_OFFSET_NONE) {
6900       gint i;
6901       for (i = 0; i < demux->n_streams; i++) {
6902         guint32 res;
6903         GST_LOG_OBJECT (demux,
6904             "Stream #%d , checking if offset %" G_GUINT64_FORMAT
6905             " is a sample start", i, GST_BUFFER_OFFSET (inbuf));
6906         res =
6907             gst_qtdemux_find_index_for_given_media_offset_linear (demux,
6908             demux->streams[i], GST_BUFFER_OFFSET (inbuf));
6909         if (res != -1) {
6910           QtDemuxSample *sample = &demux->streams[i]->samples[res];
6911           GST_LOG_OBJECT (demux,
6912               "Checking if sample %d from stream %d is valid (offset:%"
6913               G_GUINT64_FORMAT " size:%" G_GUINT32_FORMAT ")", res, i,
6914               sample->offset, sample->size);
6915           if (sample->offset == GST_BUFFER_OFFSET (inbuf)) {
6916             GST_LOG_OBJECT (demux,
6917                 "new buffer corresponds to a valid sample : %" G_GUINT32_FORMAT,
6918                 res);
6919             is_gap_input = TRUE;
6920             /* We can go back to standard playback mode */
6921             demux->state = QTDEMUX_STATE_MOVIE;
6922             /* Remember which sample this stream is at */
6923             demux->streams[i]->sample_index = res;
6924             /* Finally update all push-based values to the expected values */
6925             demux->neededbytes = demux->streams[i]->samples[res].size;
6926             demux->offset = GST_BUFFER_OFFSET (inbuf);
6927             demux->mdatleft =
6928                 demux->mdatsize - demux->offset + demux->mdatoffset;
6929             demux->todrop = 0;
6930           }
6931         }
6932       }
6933       if (!is_gap_input) {
6934         GST_DEBUG_OBJECT (demux, "Resetting, actual DISCONT");
6935         /* Reset state if it's a real discont */
6936         demux->neededbytes = 16;
6937         demux->state = QTDEMUX_STATE_INITIAL;
6938         demux->offset = GST_BUFFER_OFFSET (inbuf);
6939         gst_adapter_clear (demux->adapter);
6940       }
6941     }
6942     /* Reverse fragmented playback, need to flush all we have before
6943      * consuming a new fragment.
6944      * The samples array have the timestamps calculated by accumulating the
6945      * durations but this won't work for reverse playback of fragments as
6946      * the timestamps of a subsequent fragment should be smaller than the
6947      * previously received one. */
6948     if (!is_gap_input && demux->fragmented && demux->segment.rate < 0) {
6949       gst_qtdemux_process_adapter (demux, TRUE);
6950       for (i = 0; i < demux->n_streams; i++)
6951         gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6952     }
6953   }
6954
6955   gst_adapter_push (demux->adapter, inbuf);
6956
6957   GST_DEBUG_OBJECT (demux,
6958       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6959       demux->neededbytes, gst_adapter_available (demux->adapter));
6960
6961   return gst_qtdemux_process_adapter (demux, FALSE);
6962 }
6963
6964 static GstFlowReturn
6965 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6966 {
6967   GstFlowReturn ret = GST_FLOW_OK;
6968
6969   /* we never really mean to buffer that much */
6970   if (demux->neededbytes == -1) {
6971     goto eos;
6972   }
6973
6974   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6975       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6976
6977 #ifndef GST_DISABLE_GST_DEBUG
6978     {
6979       guint64 discont_offset, distance_from_discont;
6980
6981       discont_offset = gst_adapter_offset_at_discont (demux->adapter);
6982       distance_from_discont =
6983           gst_adapter_distance_from_discont (demux->adapter);
6984
6985       GST_DEBUG_OBJECT (demux,
6986           "state:%s , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT
6987           " adapter offset :%" G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT
6988           " bytes)", qt_demux_state_string (demux->state), demux->neededbytes,
6989           demux->offset, discont_offset, distance_from_discont);
6990     }
6991 #endif
6992
6993     switch (demux->state) {
6994       case QTDEMUX_STATE_INITIAL:{
6995         const guint8 *data;
6996         guint32 fourcc;
6997         guint64 size;
6998
6999         gst_qtdemux_check_seekability (demux);
7000
7001         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7002
7003         /* get fourcc/length, set neededbytes */
7004         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
7005             &size, &fourcc);
7006         gst_adapter_unmap (demux->adapter);
7007         data = NULL;
7008         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
7009             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
7010         if (size == 0) {
7011           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7012               (_("This file is invalid and cannot be played.")),
7013               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
7014                   GST_FOURCC_ARGS (fourcc)));
7015           ret = GST_FLOW_ERROR;
7016           break;
7017         }
7018         if (fourcc == FOURCC_mdat) {
7019           gint next_entry = next_entry_size (demux);
7020           if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
7021             /* we have the headers, start playback */
7022             demux->state = QTDEMUX_STATE_MOVIE;
7023             demux->neededbytes = next_entry;
7024             demux->mdatleft = size;
7025             demux->mdatsize = demux->mdatleft;
7026           } else {
7027             /* no headers yet, try to get them */
7028             guint bs;
7029             gboolean res;
7030             guint64 old, target;
7031
7032           buffer_data:
7033             old = demux->offset;
7034             target = old + size;
7035
7036             /* try to jump over the atom with a seek */
7037             /* only bother if it seems worth doing so,
7038              * and avoids possible upstream/server problems */
7039             if (demux->upstream_seekable &&
7040                 demux->upstream_size > 4 * (1 << 20)) {
7041               res = qtdemux_seek_offset (demux, target);
7042             } else {
7043               GST_DEBUG_OBJECT (demux, "skipping seek");
7044               res = FALSE;
7045             }
7046
7047             if (res) {
7048               GST_DEBUG_OBJECT (demux, "seek success");
7049               /* remember the offset fo the first mdat so we can seek back to it
7050                * after we have the headers */
7051               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
7052                 demux->first_mdat = old;
7053                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
7054                     demux->first_mdat);
7055               }
7056               /* seek worked, continue reading */
7057               demux->offset = target;
7058               demux->neededbytes = 16;
7059               demux->state = QTDEMUX_STATE_INITIAL;
7060             } else {
7061               /* seek failed, need to buffer */
7062               demux->offset = old;
7063               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
7064               /* there may be multiple mdat (or alike) buffers */
7065               /* sanity check */
7066               if (demux->mdatbuffer)
7067                 bs = gst_buffer_get_size (demux->mdatbuffer);
7068               else
7069                 bs = 0;
7070               if (size + bs > 10 * (1 << 20))
7071                 goto no_moov;
7072               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
7073               demux->neededbytes = size;
7074               if (!demux->mdatbuffer)
7075                 demux->mdatoffset = demux->offset;
7076             }
7077           }
7078         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
7079           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7080               (_("This file is invalid and cannot be played.")),
7081               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
7082                   GST_FOURCC_ARGS (fourcc), size));
7083           ret = GST_FLOW_ERROR;
7084           break;
7085         } else {
7086           /* this means we already started buffering and still no moov header,
7087            * let's continue buffering everything till we get moov */
7088           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
7089                   || fourcc == FOURCC_moof))
7090             goto buffer_data;
7091           demux->neededbytes = size;
7092           demux->state = QTDEMUX_STATE_HEADER;
7093         }
7094         break;
7095       }
7096       case QTDEMUX_STATE_HEADER:{
7097         const guint8 *data;
7098         guint32 fourcc;
7099
7100         GST_DEBUG_OBJECT (demux, "In header");
7101
7102         data = gst_adapter_map (demux->adapter, demux->neededbytes);
7103
7104         /* parse the header */
7105         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
7106             &fourcc);
7107         if (fourcc == FOURCC_moov) {
7108           gint n;
7109
7110           /* in usual fragmented setup we could try to scan for more
7111            * and end up at the the moov (after mdat) again */
7112           if (demux->got_moov && demux->n_streams > 0 &&
7113               (!demux->fragmented
7114                   || demux->last_moov_offset == demux->offset)) {
7115             GST_DEBUG_OBJECT (demux,
7116                 "Skipping moov atom as we have (this) one already");
7117           } else {
7118             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
7119
7120             if (demux->got_moov && demux->fragmented) {
7121               GST_DEBUG_OBJECT (demux,
7122                   "Got a second moov, clean up data from old one");
7123               if (demux->moov_node_compressed) {
7124                 g_node_destroy (demux->moov_node_compressed);
7125                 if (demux->moov_node)
7126                   g_free (demux->moov_node->data);
7127               }
7128               demux->moov_node_compressed = NULL;
7129               if (demux->moov_node)
7130                 g_node_destroy (demux->moov_node);
7131               demux->moov_node = NULL;
7132             } else {
7133               /* prepare newsegment to send when streaming actually starts */
7134               if (!demux->pending_newsegment) {
7135                 demux->pending_newsegment =
7136                     gst_event_new_segment (&demux->segment);
7137                 if (demux->segment_seqnum)
7138                   gst_event_set_seqnum (demux->pending_newsegment,
7139                       demux->segment_seqnum);
7140               }
7141             }
7142
7143             demux->last_moov_offset = demux->offset;
7144
7145             qtdemux_parse_moov (demux, data, demux->neededbytes);
7146             qtdemux_node_dump (demux, demux->moov_node);
7147             qtdemux_parse_tree (demux);
7148             qtdemux_prepare_streams (demux);
7149             if (!demux->got_moov)
7150               qtdemux_expose_streams (demux);
7151             else {
7152
7153               for (n = 0; n < demux->n_streams; n++) {
7154                 QtDemuxStream *stream = demux->streams[n];
7155
7156                 gst_qtdemux_configure_stream (demux, stream);
7157               }
7158             }
7159
7160             demux->got_moov = TRUE;
7161             gst_qtdemux_check_send_pending_segment (demux);
7162
7163             /* fragmented streams headers shouldn't contain edts atoms */
7164             if (!demux->fragmented) {
7165               for (n = 0; n < demux->n_streams; n++) {
7166                 gst_qtdemux_stream_send_initial_gap_segments (demux,
7167                     demux->streams[n]);
7168               }
7169             }
7170
7171             if (demux->moov_node_compressed) {
7172               g_node_destroy (demux->moov_node_compressed);
7173               g_free (demux->moov_node->data);
7174             }
7175             demux->moov_node_compressed = NULL;
7176             g_node_destroy (demux->moov_node);
7177             demux->moov_node = NULL;
7178             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
7179           }
7180         } else if (fourcc == FOURCC_moof) {
7181           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
7182             guint64 dist = 0;
7183             GstClockTime prev_pts;
7184             guint64 prev_offset;
7185             guint64 adapter_discont_offset, adapter_discont_dist;
7186
7187             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
7188
7189             /*
7190              * The timestamp of the moof buffer is relevant as some scenarios
7191              * won't have the initial timestamp in the atoms. Whenever a new
7192              * buffer has started, we get that buffer's PTS and use it as a base
7193              * timestamp for the trun entries.
7194              *
7195              * To keep track of the current buffer timestamp and starting point
7196              * we use gst_adapter_prev_pts that gives us the PTS and the distance
7197              * from the beggining of the buffer, with the distance and demux->offset
7198              * we know if it is still the same buffer or not.
7199              */
7200             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
7201             prev_offset = demux->offset - dist;
7202             if (demux->fragment_start_offset == -1
7203                 || prev_offset > demux->fragment_start_offset) {
7204               demux->fragment_start_offset = prev_offset;
7205               demux->fragment_start = prev_pts;
7206               GST_DEBUG_OBJECT (demux,
7207                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
7208                   GST_TIME_FORMAT, demux->fragment_start_offset,
7209                   GST_TIME_ARGS (demux->fragment_start));
7210             }
7211
7212             /* We can't use prev_offset() here because this would require
7213              * upstream to set consistent and correct offsets on all buffers
7214              * since the discont. Nothing ever did that in the past and we
7215              * would break backwards compatibility here then.
7216              * Instead take the offset we had at the last discont and count
7217              * the bytes from there. This works with old code as there would
7218              * be no discont between moov and moof, and also works with
7219              * adaptivedemux which correctly sets offset and will set the
7220              * DISCONT flag accordingly when needed.
7221              *
7222              * We also only do this for upstream TIME segments as otherwise
7223              * there are potential backwards compatibility problems with
7224              * seeking in PUSH mode and upstream providing inconsistent
7225              * timestamps. */
7226             adapter_discont_offset =
7227                 gst_adapter_offset_at_discont (demux->adapter);
7228             adapter_discont_dist =
7229                 gst_adapter_distance_from_discont (demux->adapter);
7230
7231             GST_DEBUG_OBJECT (demux,
7232                 "demux offset %" G_GUINT64_FORMAT " adapter offset %"
7233                 G_GUINT64_FORMAT " (+ %" G_GUINT64_FORMAT " bytes)",
7234                 demux->offset, adapter_discont_offset, adapter_discont_dist);
7235
7236             if (demux->upstream_format_is_time) {
7237               demux->moof_offset = adapter_discont_offset;
7238               if (demux->moof_offset != GST_BUFFER_OFFSET_NONE)
7239                 demux->moof_offset += adapter_discont_dist;
7240               if (demux->moof_offset == GST_BUFFER_OFFSET_NONE)
7241                 demux->moof_offset = demux->offset;
7242             } else {
7243               demux->moof_offset = demux->offset;
7244             }
7245
7246             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
7247                     demux->moof_offset, NULL)) {
7248               gst_adapter_unmap (demux->adapter);
7249               ret = GST_FLOW_ERROR;
7250               goto done;
7251             }
7252             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
7253             if (demux->mss_mode && !demux->exposed) {
7254               if (!demux->pending_newsegment) {
7255                 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
7256                 demux->pending_newsegment =
7257                     gst_event_new_segment (&demux->segment);
7258                 if (demux->segment_seqnum)
7259                   gst_event_set_seqnum (demux->pending_newsegment,
7260                       demux->segment_seqnum);
7261               }
7262               qtdemux_expose_streams (demux);
7263             }
7264           } else {
7265             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
7266           }
7267         } else if (fourcc == FOURCC_ftyp) {
7268           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
7269           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
7270         } else if (fourcc == FOURCC_uuid) {
7271           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
7272           qtdemux_parse_uuid (demux, data, demux->neededbytes);
7273         } else if (fourcc == FOURCC_sidx) {
7274           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
7275           qtdemux_parse_sidx (demux, data, demux->neededbytes);
7276         } else {
7277           switch (fourcc) {
7278             case FOURCC_styp:
7279               /* [styp] is like a [ftyp], but in fragment header. We ignore it for now
7280                * FALLTHROUGH */
7281             case FOURCC_free:
7282               /* [free] is a padding atom */
7283               GST_DEBUG_OBJECT (demux,
7284                   "Skipping fourcc while parsing header : %" GST_FOURCC_FORMAT,
7285                   GST_FOURCC_ARGS (fourcc));
7286               break;
7287             default:
7288               GST_WARNING_OBJECT (demux,
7289                   "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
7290                   GST_FOURCC_ARGS (fourcc));
7291               /* Let's jump that one and go back to initial state */
7292               break;
7293           }
7294         }
7295         gst_adapter_unmap (demux->adapter);
7296         data = NULL;
7297
7298         if (demux->mdatbuffer && demux->n_streams) {
7299           gsize remaining_data_size = 0;
7300
7301           /* the mdat was before the header */
7302           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
7303               demux->n_streams, demux->mdatbuffer);
7304           /* restore our adapter/offset view of things with upstream;
7305            * put preceding buffered data ahead of current moov data.
7306            * This should also handle evil mdat, moov, mdat cases and alike */
7307           gst_adapter_flush (demux->adapter, demux->neededbytes);
7308
7309           /* Store any remaining data after the mdat for later usage */
7310           remaining_data_size = gst_adapter_available (demux->adapter);
7311           if (remaining_data_size > 0) {
7312             g_assert (demux->restoredata_buffer == NULL);
7313             demux->restoredata_buffer =
7314                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
7315             demux->restoredata_offset = demux->offset + demux->neededbytes;
7316             GST_DEBUG_OBJECT (demux,
7317                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
7318                 G_GUINT64_FORMAT, remaining_data_size,
7319                 demux->restoredata_offset);
7320           }
7321
7322           gst_adapter_push (demux->adapter, demux->mdatbuffer);
7323           demux->mdatbuffer = NULL;
7324           demux->offset = demux->mdatoffset;
7325           demux->neededbytes = next_entry_size (demux);
7326           demux->state = QTDEMUX_STATE_MOVIE;
7327           demux->mdatleft = gst_adapter_available (demux->adapter);
7328           demux->mdatsize = demux->mdatleft;
7329         } else {
7330           GST_DEBUG_OBJECT (demux, "Carrying on normally");
7331           gst_adapter_flush (demux->adapter, demux->neededbytes);
7332
7333           /* only go back to the mdat if there are samples to play */
7334           if (demux->got_moov && demux->first_mdat != -1
7335               && has_next_entry (demux)) {
7336             gboolean res;
7337
7338             /* we need to seek back */
7339             res = qtdemux_seek_offset (demux, demux->first_mdat);
7340             if (res) {
7341               demux->offset = demux->first_mdat;
7342             } else {
7343               GST_DEBUG_OBJECT (demux, "Seek back failed");
7344             }
7345           } else {
7346             demux->offset += demux->neededbytes;
7347           }
7348           demux->neededbytes = 16;
7349           demux->state = QTDEMUX_STATE_INITIAL;
7350         }
7351
7352         break;
7353       }
7354       case QTDEMUX_STATE_BUFFER_MDAT:{
7355         GstBuffer *buf;
7356         guint8 fourcc[4];
7357
7358         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
7359             demux->offset);
7360         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7361         gst_buffer_extract (buf, 0, fourcc, 4);
7362         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
7363             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
7364         if (demux->mdatbuffer)
7365           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
7366         else
7367           demux->mdatbuffer = buf;
7368         demux->offset += demux->neededbytes;
7369         demux->neededbytes = 16;
7370         demux->state = QTDEMUX_STATE_INITIAL;
7371         gst_qtdemux_post_progress (demux, 1, 1);
7372
7373         break;
7374       }
7375       case QTDEMUX_STATE_MOVIE:{
7376         QtDemuxStream *stream = NULL;
7377         QtDemuxSample *sample;
7378         int i = -1;
7379         GstClockTime dts, pts, duration;
7380         gboolean keyframe;
7381
7382         GST_DEBUG_OBJECT (demux,
7383             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
7384
7385         if (demux->fragmented) {
7386           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
7387               demux->mdatleft);
7388           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
7389             /* if needed data starts within this atom,
7390              * then it should not exceed this atom */
7391             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
7392               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
7393                   (_("This file is invalid and cannot be played.")),
7394                   ("sample data crosses atom boundary"));
7395               ret = GST_FLOW_ERROR;
7396               break;
7397             }
7398             demux->mdatleft -= demux->neededbytes;
7399           } else {
7400             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
7401             /* so we are dropping more than left in this atom */
7402             gst_qtdemux_drop_data (demux, demux->mdatleft);
7403             demux->mdatleft = 0;
7404
7405             /* need to resume atom parsing so we do not miss any other pieces */
7406             demux->state = QTDEMUX_STATE_INITIAL;
7407             demux->neededbytes = 16;
7408
7409             /* check if there was any stored post mdat data from previous buffers */
7410             if (demux->restoredata_buffer) {
7411               g_assert (gst_adapter_available (demux->adapter) == 0);
7412
7413               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
7414               demux->restoredata_buffer = NULL;
7415               demux->offset = demux->restoredata_offset;
7416             }
7417
7418             break;
7419           }
7420         }
7421
7422         if (demux->todrop) {
7423           if (demux->cenc_aux_info_offset > 0) {
7424             GstByteReader br;
7425             const guint8 *data;
7426
7427             GST_DEBUG_OBJECT (demux, "parsing cenc auxiliary info");
7428             data = gst_adapter_map (demux->adapter, demux->todrop);
7429             gst_byte_reader_init (&br, data + 8, demux->todrop);
7430             if (!qtdemux_parse_cenc_aux_info (demux, demux->streams[0], &br,
7431                     demux->cenc_aux_info_sizes, demux->cenc_aux_sample_count)) {
7432               GST_ERROR_OBJECT (demux, "failed to parse cenc auxiliary info");
7433               ret = GST_FLOW_ERROR;
7434               gst_adapter_unmap (demux->adapter);
7435               g_free (demux->cenc_aux_info_sizes);
7436               demux->cenc_aux_info_sizes = NULL;
7437               goto done;
7438             }
7439             demux->cenc_aux_info_offset = 0;
7440             g_free (demux->cenc_aux_info_sizes);
7441             demux->cenc_aux_info_sizes = NULL;
7442             gst_adapter_unmap (demux->adapter);
7443           }
7444           gst_qtdemux_drop_data (demux, demux->todrop);
7445         }
7446
7447         /* first buffer? */
7448         /* initial newsegment sent here after having added pads,
7449          * possible others in sink_event */
7450         gst_qtdemux_check_send_pending_segment (demux);
7451
7452         /* Figure out which stream this packet belongs to */
7453         for (i = 0; i < demux->n_streams; i++) {
7454           stream = demux->streams[i];
7455           if (stream->sample_index >= stream->n_samples)
7456             continue;
7457           GST_LOG_OBJECT (demux,
7458               "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
7459               " / size:%d)", i, stream->sample_index,
7460               stream->samples[stream->sample_index].offset,
7461               stream->samples[stream->sample_index].size);
7462
7463           if (stream->samples[stream->sample_index].offset == demux->offset)
7464             break;
7465         }
7466
7467         if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
7468           goto unknown_stream;
7469
7470         gst_qtdemux_stream_check_and_change_stsd_index (demux, stream);
7471
7472         if (stream->new_caps) {
7473           gst_qtdemux_configure_stream (demux, stream);
7474         }
7475
7476         /* Put data in a buffer, set timestamps, caps, ... */
7477         sample = &stream->samples[stream->sample_index];
7478
7479         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
7480           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
7481               GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
7482
7483           dts = QTSAMPLE_DTS (stream, sample);
7484           pts = QTSAMPLE_PTS (stream, sample);
7485           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
7486           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
7487
7488           /* check for segment end */
7489           if (G_UNLIKELY (demux->segment.stop != -1
7490                   && demux->segment.stop <= pts && stream->on_keyframe)) {
7491             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
7492             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
7493
7494             /* skip this data, stream is EOS */
7495             gst_adapter_flush (demux->adapter, demux->neededbytes);
7496             demux->offset += demux->neededbytes;
7497
7498             /* check if all streams are eos */
7499             ret = GST_FLOW_EOS;
7500             for (i = 0; i < demux->n_streams; i++) {
7501               if (!STREAM_IS_EOS (demux->streams[i])) {
7502                 ret = GST_FLOW_OK;
7503                 break;
7504               }
7505             }
7506           } else {
7507             GstBuffer *outbuf;
7508
7509             outbuf =
7510                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
7511
7512             /* FIXME: should either be an assert or a plain check */
7513             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
7514
7515             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
7516                 dts, pts, duration, keyframe, dts, demux->offset);
7517           }
7518
7519           /* combine flows */
7520           ret = gst_qtdemux_combine_flows (demux, stream, ret);
7521         } else {
7522           /* skip this data, stream is EOS */
7523           gst_adapter_flush (demux->adapter, demux->neededbytes);
7524         }
7525
7526         stream->sample_index++;
7527         stream->offset_in_sample = 0;
7528
7529         /* update current offset and figure out size of next buffer */
7530         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
7531             demux->offset, demux->neededbytes);
7532         demux->offset += demux->neededbytes;
7533         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
7534             demux->offset);
7535
7536
7537         if (ret == GST_FLOW_EOS) {
7538           GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
7539           demux->neededbytes = -1;
7540           goto eos;
7541         }
7542
7543         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
7544           if (demux->fragmented) {
7545             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
7546             /* there may be more to follow, only finish this atom */
7547             demux->todrop = demux->mdatleft;
7548             demux->neededbytes = demux->todrop;
7549             break;
7550           }
7551           goto eos;
7552         }
7553         if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) {
7554           goto non_ok_unlinked_flow;
7555         }
7556         break;
7557       }
7558       default:
7559         goto invalid_state;
7560     }
7561   }
7562
7563   /* when buffering movie data, at least show user something is happening */
7564   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
7565       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
7566     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
7567         demux->neededbytes);
7568   }
7569 done:
7570
7571   return ret;
7572
7573   /* ERRORS */
7574 non_ok_unlinked_flow:
7575   {
7576     GST_DEBUG_OBJECT (demux, "Stopping, combined return flow %s",
7577         gst_flow_get_name (ret));
7578     return ret;
7579   }
7580 unknown_stream:
7581   {
7582     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
7583     ret = GST_FLOW_ERROR;
7584     goto done;
7585   }
7586 eos:
7587   {
7588     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
7589     ret = GST_FLOW_EOS;
7590     goto done;
7591   }
7592 invalid_state:
7593   {
7594     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7595         (NULL), ("qtdemuxer invalid state %d", demux->state));
7596     ret = GST_FLOW_ERROR;
7597     goto done;
7598   }
7599 no_moov:
7600   {
7601     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
7602         (NULL), ("no 'moov' atom within the first 10 MB"));
7603     ret = GST_FLOW_ERROR;
7604     goto done;
7605   }
7606 }
7607
7608 static gboolean
7609 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
7610 {
7611   GstQuery *query;
7612   gboolean pull_mode;
7613
7614   query = gst_query_new_scheduling ();
7615
7616   if (!gst_pad_peer_query (sinkpad, query)) {
7617     gst_query_unref (query);
7618     goto activate_push;
7619   }
7620
7621   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
7622       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
7623   gst_query_unref (query);
7624
7625   if (!pull_mode)
7626     goto activate_push;
7627
7628   GST_DEBUG_OBJECT (sinkpad, "activating pull");
7629   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
7630
7631 activate_push:
7632   {
7633     GST_DEBUG_OBJECT (sinkpad, "activating push");
7634     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
7635   }
7636 }
7637
7638 static gboolean
7639 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
7640     GstPadMode mode, gboolean active)
7641 {
7642   gboolean res;
7643   GstQTDemux *demux = GST_QTDEMUX (parent);
7644
7645   switch (mode) {
7646     case GST_PAD_MODE_PUSH:
7647       demux->pullbased = FALSE;
7648       res = TRUE;
7649       break;
7650     case GST_PAD_MODE_PULL:
7651       if (active) {
7652         demux->pullbased = TRUE;
7653         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
7654             sinkpad, NULL);
7655       } else {
7656         res = gst_pad_stop_task (sinkpad);
7657       }
7658       break;
7659     default:
7660       res = FALSE;
7661       break;
7662   }
7663   return res;
7664 }
7665
7666 #ifdef HAVE_ZLIB
7667 static void *
7668 qtdemux_inflate (void *z_buffer, guint z_length, guint * length)
7669 {
7670   guint8 *buffer;
7671   z_stream z;
7672   int ret;
7673
7674   memset (&z, 0, sizeof (z));
7675   z.zalloc = NULL;
7676   z.zfree = NULL;
7677   z.opaque = NULL;
7678
7679   if ((ret = inflateInit (&z)) != Z_OK) {
7680     GST_ERROR ("inflateInit() returned %d", ret);
7681     return NULL;
7682   }
7683
7684   z.next_in = z_buffer;
7685   z.avail_in = z_length;
7686
7687   buffer = (guint8 *) g_malloc (*length);
7688   z.avail_out = *length;
7689   z.next_out = (Bytef *) buffer;
7690   do {
7691     ret = inflate (&z, Z_NO_FLUSH);
7692     if (ret == Z_STREAM_END) {
7693       break;
7694     } else if (ret != Z_OK) {
7695       GST_WARNING ("inflate() returned %d", ret);
7696       break;
7697     }
7698
7699     *length += 4096;
7700     buffer = (guint8 *) g_realloc (buffer, *length);
7701     z.next_out = (Bytef *) (buffer + z.total_out);
7702     z.avail_out += 4096;
7703   } while (z.avail_in > 0);
7704
7705   if (ret != Z_STREAM_END) {
7706     g_free (buffer);
7707     buffer = NULL;
7708     *length = 0;
7709   } else {
7710     *length = z.total_out;
7711   }
7712
7713   inflateEnd (&z);
7714
7715   return buffer;
7716 }
7717 #endif /* HAVE_ZLIB */
7718
7719 static gboolean
7720 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
7721 {
7722   GNode *cmov;
7723
7724   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
7725
7726   /* counts as header data */
7727   qtdemux->header_size += length;
7728
7729   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
7730   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
7731
7732   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
7733   if (cmov) {
7734     guint32 method;
7735     GNode *dcom;
7736     GNode *cmvd;
7737     guint32 dcom_len;
7738
7739     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
7740     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
7741     if (dcom == NULL || cmvd == NULL)
7742       goto invalid_compression;
7743
7744     dcom_len = QT_UINT32 (dcom->data);
7745     if (dcom_len < 12)
7746       goto invalid_compression;
7747
7748     method = QT_FOURCC ((guint8 *) dcom->data + 8);
7749     switch (method) {
7750 #ifdef HAVE_ZLIB
7751       case FOURCC_zlib:{
7752         guint uncompressed_length;
7753         guint compressed_length;
7754         guint8 *buf;
7755         guint32 cmvd_len;
7756
7757         cmvd_len = QT_UINT32 ((guint8 *) cmvd->data);
7758         if (cmvd_len < 12)
7759           goto invalid_compression;
7760
7761         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
7762         compressed_length = cmvd_len - 12;
7763         GST_LOG ("length = %u", uncompressed_length);
7764
7765         buf =
7766             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
7767             compressed_length, &uncompressed_length);
7768
7769         if (buf) {
7770           qtdemux->moov_node_compressed = qtdemux->moov_node;
7771           qtdemux->moov_node = g_node_new (buf);
7772
7773           qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
7774               uncompressed_length);
7775         }
7776         break;
7777       }
7778 #endif /* HAVE_ZLIB */
7779       default:
7780         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
7781             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
7782         break;
7783     }
7784   }
7785   return TRUE;
7786
7787   /* ERRORS */
7788 invalid_compression:
7789   {
7790     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
7791     return FALSE;
7792   }
7793 }
7794
7795 static gboolean
7796 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
7797     const guint8 * end)
7798 {
7799   while (G_UNLIKELY (buf < end)) {
7800     GNode *child;
7801     guint32 len;
7802
7803     if (G_UNLIKELY (buf + 4 > end)) {
7804       GST_LOG_OBJECT (qtdemux, "buffer overrun");
7805       break;
7806     }
7807     len = QT_UINT32 (buf);
7808     if (G_UNLIKELY (len == 0)) {
7809       GST_LOG_OBJECT (qtdemux, "empty container");
7810       break;
7811     }
7812     if (G_UNLIKELY (len < 8)) {
7813       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
7814       break;
7815     }
7816     if (G_UNLIKELY (len > (end - buf))) {
7817       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
7818           (gint) (end - buf));
7819       break;
7820     }
7821
7822     child = g_node_new ((guint8 *) buf);
7823     g_node_append (node, child);
7824     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
7825     qtdemux_parse_node (qtdemux, child, buf, len);
7826
7827     buf += len;
7828   }
7829   return TRUE;
7830 }
7831
7832 static gboolean
7833 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
7834     GNode * xdxt)
7835 {
7836   int len = QT_UINT32 (xdxt->data);
7837   guint8 *buf = xdxt->data;
7838   guint8 *end = buf + len;
7839   GstBuffer *buffer;
7840
7841   /* skip size and type */
7842   buf += 8;
7843   end -= 8;
7844
7845   while (buf < end) {
7846     gint size;
7847     guint32 type;
7848
7849     size = QT_UINT32 (buf);
7850     type = QT_FOURCC (buf + 4);
7851
7852     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
7853
7854     if (buf + size > end || size <= 0)
7855       break;
7856
7857     buf += 8;
7858     size -= 8;
7859
7860     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
7861         GST_FOURCC_ARGS (type));
7862
7863     switch (type) {
7864       case FOURCC_tCtH:
7865         buffer = gst_buffer_new_and_alloc (size);
7866         gst_buffer_fill (buffer, 0, buf, size);
7867         stream->buffers = g_slist_append (stream->buffers, buffer);
7868         GST_LOG_OBJECT (qtdemux, "parsing theora header");
7869         break;
7870       case FOURCC_tCt_:
7871         buffer = gst_buffer_new_and_alloc (size);
7872         gst_buffer_fill (buffer, 0, buf, size);
7873         stream->buffers = g_slist_append (stream->buffers, buffer);
7874         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
7875         break;
7876       case FOURCC_tCtC:
7877         buffer = gst_buffer_new_and_alloc (size);
7878         gst_buffer_fill (buffer, 0, buf, size);
7879         stream->buffers = g_slist_append (stream->buffers, buffer);
7880         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
7881         break;
7882       default:
7883         GST_WARNING_OBJECT (qtdemux,
7884             "unknown theora cookie %" GST_FOURCC_FORMAT,
7885             GST_FOURCC_ARGS (type));
7886         break;
7887     }
7888     buf += size;
7889   }
7890   return TRUE;
7891 }
7892
7893 static gboolean
7894 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
7895     guint length)
7896 {
7897   guint32 fourcc = 0;
7898   guint32 node_length = 0;
7899   const QtNodeType *type;
7900   const guint8 *end;
7901
7902   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
7903
7904   if (G_UNLIKELY (length < 8))
7905     goto not_enough_data;
7906
7907   node_length = QT_UINT32 (buffer);
7908   fourcc = QT_FOURCC (buffer + 4);
7909
7910   /* ignore empty nodes */
7911   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
7912     return TRUE;
7913
7914   type = qtdemux_type_get (fourcc);
7915
7916   end = buffer + length;
7917
7918   GST_LOG_OBJECT (qtdemux,
7919       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
7920       GST_FOURCC_ARGS (fourcc), node_length, type->name);
7921
7922   if (node_length > length)
7923     goto broken_atom_size;
7924
7925   if (type->flags & QT_FLAG_CONTAINER) {
7926     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
7927   } else {
7928     switch (fourcc) {
7929       case FOURCC_stsd:
7930       {
7931         if (node_length < 20) {
7932           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
7933           break;
7934         }
7935         GST_DEBUG_OBJECT (qtdemux,
7936             "parsing stsd (sample table, sample description) atom");
7937         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
7938         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7939         break;
7940       }
7941       case FOURCC_mp4a:
7942       case FOURCC_alac:
7943       case FOURCC_fLaC:
7944       {
7945         guint32 version;
7946         guint32 offset;
7947         guint min_size;
7948
7949         /* also read alac (or whatever) in stead of mp4a in the following,
7950          * since a similar layout is used in other cases as well */
7951         if (fourcc == FOURCC_mp4a)
7952           min_size = 20;
7953         else if (fourcc == FOURCC_fLaC)
7954           min_size = 86;
7955         else
7956           min_size = 40;
7957
7958         /* There are two things we might encounter here: a true mp4a atom, and
7959            an mp4a entry in an stsd atom. The latter is what we're interested
7960            in, and it looks like an atom, but isn't really one. The true mp4a
7961            atom is short, so we detect it based on length here. */
7962         if (length < min_size) {
7963           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
7964               GST_FOURCC_ARGS (fourcc));
7965           break;
7966         }
7967
7968         /* 'version' here is the sound sample description version. Types 0 and
7969            1 are documented in the QTFF reference, but type 2 is not: it's
7970            described in Apple header files instead (struct SoundDescriptionV2
7971            in Movies.h) */
7972         version = QT_UINT16 (buffer + 16);
7973
7974         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7975             GST_FOURCC_ARGS (fourcc), version);
7976
7977         /* parse any esds descriptors */
7978         switch (version) {
7979           case 0:
7980             offset = 0x24;
7981             break;
7982           case 1:
7983             offset = 0x34;
7984             break;
7985           case 2:
7986             offset = 0x48;
7987             break;
7988           default:
7989             GST_WARNING_OBJECT (qtdemux,
7990                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7991                 GST_FOURCC_ARGS (fourcc), version);
7992             offset = 0;
7993             break;
7994         }
7995         if (offset)
7996           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7997         break;
7998       }
7999       case FOURCC_mp4v:
8000       case FOURCC_MP4V:
8001       case FOURCC_fmp4:
8002       case FOURCC_FMP4:
8003       case FOURCC_apcs:
8004       case FOURCC_apch:
8005       case FOURCC_apcn:
8006       case FOURCC_apco:
8007       case FOURCC_ap4h:
8008       case FOURCC_xvid:
8009       case FOURCC_XVID:
8010       case FOURCC_H264:
8011       case FOURCC_avc1:
8012       case FOURCC_avc3:
8013       case FOURCC_H265:
8014       case FOURCC_hvc1:
8015       case FOURCC_hev1:
8016       case FOURCC_mjp2:
8017       case FOURCC_encv:
8018       {
8019         guint32 version;
8020         guint32 str_len;
8021
8022         /* codec_data is contained inside these atoms, which all have
8023          * the same format. */
8024         /* video sample description size is 86 bytes without extension.
8025          * node_length have to be bigger than 86 bytes because video sample
8026          * description can include extenstions such as esds, fiel, glbl, etc. */
8027         if (node_length < 86) {
8028           GST_WARNING_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT
8029               " sample description length too short (%u < 86)",
8030               GST_FOURCC_ARGS (fourcc), node_length);
8031           break;
8032         }
8033
8034         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
8035             GST_FOURCC_ARGS (fourcc));
8036
8037         /* version (2 bytes) : this is set to 0, unless a compressor has changed
8038          *              its data format.
8039          * revision level (2 bytes) : must be set to 0. */
8040         version = QT_UINT32 (buffer + 16);
8041         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
8042
8043         /* compressor name : PASCAL string and informative purposes
8044          * first byte : the number of bytes to be displayed.
8045          *              it has to be less than 32 because it is reserved
8046          *              space of 32 bytes total including itself. */
8047         str_len = QT_UINT8 (buffer + 50);
8048         if (str_len < 32)
8049           GST_DEBUG_OBJECT (qtdemux, "compressorname = %.*s", str_len,
8050               (char *) buffer + 51);
8051         else
8052           GST_WARNING_OBJECT (qtdemux,
8053               "compressorname length too big (%u > 31)", str_len);
8054
8055         GST_MEMDUMP_OBJECT (qtdemux, "video sample description", buffer,
8056             end - buffer);
8057         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
8058         break;
8059       }
8060       case FOURCC_meta:
8061       {
8062         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
8063         qtdemux_parse_container (qtdemux, node, buffer + 12, end);
8064         break;
8065       }
8066       case FOURCC_mp4s:
8067       {
8068         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
8069         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
8070         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
8071         break;
8072       }
8073       case FOURCC_XiTh:
8074       {
8075         guint32 version;
8076         guint32 offset;
8077
8078         if (length < 16) {
8079           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
8080               GST_FOURCC_ARGS (fourcc));
8081           break;
8082         }
8083
8084         version = QT_UINT32 (buffer + 12);
8085         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
8086
8087         switch (version) {
8088           case 0x00000001:
8089             offset = 0x62;
8090             break;
8091           default:
8092             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
8093             offset = 0;
8094             break;
8095         }
8096         if (offset) {
8097           if (length < offset) {
8098             GST_WARNING_OBJECT (qtdemux,
8099                 "skipping too small %" GST_FOURCC_FORMAT " box",
8100                 GST_FOURCC_ARGS (fourcc));
8101             break;
8102           }
8103           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
8104         }
8105         break;
8106       }
8107       case FOURCC_in24:
8108       {
8109         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
8110         break;
8111       }
8112       case FOURCC_uuid:
8113       {
8114         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
8115         break;
8116       }
8117       case FOURCC_enca:
8118       {
8119         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
8120         break;
8121       }
8122 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
8123       case FOURCC_SA3D:
8124       {
8125         qtdemux_parse_SA3D (qtdemux, buffer, end - buffer);
8126         break;
8127       }
8128 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
8129       default:
8130         if (!strcmp (type->name, "unknown"))
8131           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
8132         break;
8133     }
8134   }
8135   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
8136       GST_FOURCC_ARGS (fourcc));
8137   return TRUE;
8138
8139 /* ERRORS */
8140 not_enough_data:
8141   {
8142     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8143         (_("This file is corrupt and cannot be played.")),
8144         ("Not enough data for an atom header, got only %u bytes", length));
8145     return FALSE;
8146   }
8147 broken_atom_size:
8148   {
8149     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8150         (_("This file is corrupt and cannot be played.")),
8151         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
8152             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
8153             length));
8154     return FALSE;
8155   }
8156 }
8157
8158 static GNode *
8159 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
8160 {
8161   GNode *child;
8162   guint8 *buffer;
8163   guint32 child_fourcc;
8164
8165   for (child = g_node_first_child (node); child;
8166       child = g_node_next_sibling (child)) {
8167     buffer = (guint8 *) child->data;
8168
8169     child_fourcc = QT_FOURCC (buffer + 4);
8170
8171     if (G_UNLIKELY (child_fourcc == fourcc)) {
8172       return child;
8173     }
8174   }
8175   return NULL;
8176 }
8177
8178 static GNode *
8179 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
8180     GstByteReader * parser)
8181 {
8182   GNode *child;
8183   guint8 *buffer;
8184   guint32 child_fourcc, child_len;
8185
8186   for (child = g_node_first_child (node); child;
8187       child = g_node_next_sibling (child)) {
8188     buffer = (guint8 *) child->data;
8189
8190     child_len = QT_UINT32 (buffer);
8191     child_fourcc = QT_FOURCC (buffer + 4);
8192
8193     if (G_UNLIKELY (child_fourcc == fourcc)) {
8194       if (G_UNLIKELY (child_len < (4 + 4)))
8195         return NULL;
8196       /* FIXME: must verify if atom length < parent atom length */
8197       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8198       return child;
8199     }
8200   }
8201   return NULL;
8202 }
8203
8204 static GNode *
8205 qtdemux_tree_get_child_by_index (GNode * node, guint index)
8206 {
8207   return g_node_nth_child (node, index);
8208 }
8209
8210 static GNode *
8211 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
8212     GstByteReader * parser)
8213 {
8214   GNode *child;
8215   guint8 *buffer;
8216   guint32 child_fourcc, child_len;
8217
8218   for (child = g_node_next_sibling (node); child;
8219       child = g_node_next_sibling (child)) {
8220     buffer = (guint8 *) child->data;
8221
8222     child_fourcc = QT_FOURCC (buffer + 4);
8223
8224     if (child_fourcc == fourcc) {
8225       if (parser) {
8226         child_len = QT_UINT32 (buffer);
8227         if (G_UNLIKELY (child_len < (4 + 4)))
8228           return NULL;
8229         /* FIXME: must verify if atom length < parent atom length */
8230         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
8231       }
8232       return child;
8233     }
8234   }
8235   return NULL;
8236 }
8237
8238 static GNode *
8239 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
8240 {
8241   return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
8242 }
8243
8244 static void
8245 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
8246 {
8247 /* FIXME: This can only reliably work if demuxers have a
8248  * separate streaming thread per srcpad. This should be
8249  * done in a demuxer base class, which integrates parts
8250  * of multiqueue
8251  *
8252  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
8253  */
8254 #if 0
8255   GstQuery *query;
8256
8257   query = gst_query_new_allocation (stream->caps, FALSE);
8258
8259   if (!gst_pad_peer_query (stream->pad, query)) {
8260     /* not a problem, just debug a little */
8261     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
8262   }
8263
8264   if (stream->allocator)
8265     gst_object_unref (stream->allocator);
8266
8267   if (gst_query_get_n_allocation_params (query) > 0) {
8268     /* try the allocator */
8269     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
8270         &stream->params);
8271     stream->use_allocator = TRUE;
8272   } else {
8273     stream->allocator = NULL;
8274     gst_allocation_params_init (&stream->params);
8275     stream->use_allocator = FALSE;
8276   }
8277   gst_query_unref (query);
8278 #endif
8279 }
8280
8281 static gboolean
8282 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
8283     QtDemuxStream * stream)
8284 {
8285   GstStructure *s;
8286   const gchar *selected_system;
8287
8288   g_return_val_if_fail (qtdemux != NULL, FALSE);
8289   g_return_val_if_fail (stream != NULL, FALSE);
8290   g_return_val_if_fail (gst_caps_get_size (CUR_STREAM (stream)->caps) == 1,
8291       FALSE);
8292
8293   if (stream->protection_scheme_type != FOURCC_cenc) {
8294     GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
8295     return FALSE;
8296   }
8297   if (qtdemux->protection_system_ids == NULL) {
8298     GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
8299         "cenc protection system information has been found");
8300     return FALSE;
8301   }
8302   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
8303   selected_system = gst_protection_select_system ((const gchar **)
8304       qtdemux->protection_system_ids->pdata);
8305   g_ptr_array_remove_index (qtdemux->protection_system_ids,
8306       qtdemux->protection_system_ids->len - 1);
8307   if (!selected_system) {
8308     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
8309         "suitable decryptor element has been found");
8310     return FALSE;
8311   }
8312
8313   s = gst_caps_get_structure (CUR_STREAM (stream)->caps, 0);
8314   if (!gst_structure_has_name (s, "application/x-cenc")) {
8315     gst_structure_set (s,
8316         "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
8317         GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
8318         NULL);
8319     gst_structure_set_name (s, "application/x-cenc");
8320   }
8321   return TRUE;
8322 }
8323
8324 static gboolean
8325 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
8326 {
8327   if (stream->subtype == FOURCC_vide) {
8328     /* fps is calculated base on the duration of the average framerate since
8329      * qt does not have a fixed framerate. */
8330     gboolean fps_available = TRUE;
8331
8332     if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
8333       /* still frame */
8334       CUR_STREAM (stream)->fps_n = 0;
8335       CUR_STREAM (stream)->fps_d = 1;
8336     } else {
8337       if (stream->duration == 0 || stream->n_samples < 2) {
8338         CUR_STREAM (stream)->fps_n = stream->timescale;
8339         CUR_STREAM (stream)->fps_d = 1;
8340         fps_available = FALSE;
8341       } else {
8342         GstClockTime avg_duration;
8343         guint64 duration;
8344         guint32 n_samples;
8345
8346         /* duration and n_samples can be updated for fragmented format
8347          * so, framerate of fragmented format is calculated using data in a moof */
8348         if (qtdemux->fragmented && stream->n_samples_moof > 0
8349             && stream->duration_moof > 0) {
8350           n_samples = stream->n_samples_moof;
8351           duration = stream->duration_moof;
8352         } else {
8353           n_samples = stream->n_samples;
8354           duration = stream->duration;
8355         }
8356
8357         /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
8358         /* stream->duration is guint64, timescale, n_samples are guint32 */
8359         avg_duration =
8360             gst_util_uint64_scale_round (duration -
8361             stream->first_duration, GST_SECOND,
8362             (guint64) (stream->timescale) * (n_samples - 1));
8363
8364         GST_LOG_OBJECT (qtdemux,
8365             "Calculating avg sample duration based on stream (or moof) duration %"
8366             G_GUINT64_FORMAT
8367             " minus first sample %u, leaving %d samples gives %"
8368             GST_TIME_FORMAT, duration, stream->first_duration,
8369             n_samples - 1, GST_TIME_ARGS (avg_duration));
8370
8371         gst_video_guess_framerate (avg_duration, &CUR_STREAM (stream)->fps_n,
8372             &CUR_STREAM (stream)->fps_d);
8373
8374         GST_DEBUG_OBJECT (qtdemux,
8375             "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
8376             stream->timescale, CUR_STREAM (stream)->fps_n,
8377             CUR_STREAM (stream)->fps_d);
8378       }
8379     }
8380
8381     if (CUR_STREAM (stream)->caps) {
8382       CUR_STREAM (stream)->caps =
8383           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8384
8385       gst_caps_set_simple (CUR_STREAM (stream)->caps,
8386           "width", G_TYPE_INT, CUR_STREAM (stream)->width,
8387           "height", G_TYPE_INT, CUR_STREAM (stream)->height, NULL);
8388
8389       /* set framerate if calculated framerate is reliable */
8390       if (fps_available) {
8391         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8392             "framerate", GST_TYPE_FRACTION, CUR_STREAM (stream)->fps_n,
8393             CUR_STREAM (stream)->fps_d, NULL);
8394       }
8395
8396       /* calculate pixel-aspect-ratio using display width and height */
8397       GST_DEBUG_OBJECT (qtdemux,
8398           "video size %dx%d, target display size %dx%d",
8399           CUR_STREAM (stream)->width, CUR_STREAM (stream)->height,
8400           stream->display_width, stream->display_height);
8401       /* qt file might have pasp atom */
8402       if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8403         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", CUR_STREAM (stream)->par_w,
8404             CUR_STREAM (stream)->par_h);
8405         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8406             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8407             CUR_STREAM (stream)->par_h, NULL);
8408       } else if (stream->display_width > 0 && stream->display_height > 0
8409           && CUR_STREAM (stream)->width > 0
8410           && CUR_STREAM (stream)->height > 0) {
8411         gint n, d;
8412
8413         /* calculate the pixel aspect ratio using the display and pixel w/h */
8414         n = stream->display_width * CUR_STREAM (stream)->height;
8415         d = stream->display_height * CUR_STREAM (stream)->width;
8416         if (n == d)
8417           n = d = 1;
8418         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
8419         CUR_STREAM (stream)->par_w = n;
8420         CUR_STREAM (stream)->par_h = d;
8421         gst_caps_set_simple (CUR_STREAM (stream)->caps, "pixel-aspect-ratio",
8422             GST_TYPE_FRACTION, CUR_STREAM (stream)->par_w,
8423             CUR_STREAM (stream)->par_h, NULL);
8424       }
8425
8426       if (CUR_STREAM (stream)->interlace_mode > 0) {
8427         if (CUR_STREAM (stream)->interlace_mode == 1) {
8428           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8429               G_TYPE_STRING, "progressive", NULL);
8430         } else if (CUR_STREAM (stream)->interlace_mode == 2) {
8431           gst_caps_set_simple (CUR_STREAM (stream)->caps, "interlace-mode",
8432               G_TYPE_STRING, "interleaved", NULL);
8433           if (CUR_STREAM (stream)->field_order == 9) {
8434             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8435                 G_TYPE_STRING, "top-field-first", NULL);
8436           } else if (CUR_STREAM (stream)->field_order == 14) {
8437             gst_caps_set_simple (CUR_STREAM (stream)->caps, "field-order",
8438                 G_TYPE_STRING, "bottom-field-first", NULL);
8439           }
8440         }
8441       }
8442
8443       /* Create incomplete colorimetry here if needed */
8444       if (CUR_STREAM (stream)->colorimetry.range ||
8445           CUR_STREAM (stream)->colorimetry.matrix ||
8446           CUR_STREAM (stream)->colorimetry.transfer
8447           || CUR_STREAM (stream)->colorimetry.primaries) {
8448         gchar *colorimetry =
8449             gst_video_colorimetry_to_string (&CUR_STREAM (stream)->colorimetry);
8450         gst_caps_set_simple (CUR_STREAM (stream)->caps, "colorimetry",
8451             G_TYPE_STRING, colorimetry, NULL);
8452         g_free (colorimetry);
8453       }
8454
8455       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
8456         guint par_w = 1, par_h = 1;
8457
8458         if (CUR_STREAM (stream)->par_w > 0 && CUR_STREAM (stream)->par_h > 0) {
8459           par_w = CUR_STREAM (stream)->par_w;
8460           par_h = CUR_STREAM (stream)->par_h;
8461         }
8462
8463         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
8464                 CUR_STREAM (stream)->width, CUR_STREAM (stream)->height, par_w,
8465                 par_h)) {
8466           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
8467         }
8468
8469         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8470             "multiview-mode", G_TYPE_STRING,
8471             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
8472             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
8473             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
8474       }
8475     }
8476   }
8477
8478   else if (stream->subtype == FOURCC_soun) {
8479     if (CUR_STREAM (stream)->caps) {
8480       CUR_STREAM (stream)->caps =
8481           gst_caps_make_writable (CUR_STREAM (stream)->caps);
8482       if (CUR_STREAM (stream)->rate > 0)
8483         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8484             "rate", G_TYPE_INT, (int) CUR_STREAM (stream)->rate, NULL);
8485       if (CUR_STREAM (stream)->n_channels > 0)
8486         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8487             "channels", G_TYPE_INT, CUR_STREAM (stream)->n_channels, NULL);
8488       if (CUR_STREAM (stream)->n_channels > 2) {
8489         /* FIXME: Need to parse the 'chan' atom to get channel layouts
8490          * correctly; this is just the minimum we can do - assume
8491          * we don't actually have any channel positions. */
8492         gst_caps_set_simple (CUR_STREAM (stream)->caps,
8493             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
8494       }
8495     }
8496   }
8497
8498   if (stream->pad) {
8499     GstCaps *prev_caps = NULL;
8500
8501     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
8502     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
8503     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
8504     gst_pad_set_active (stream->pad, TRUE);
8505
8506     gst_pad_use_fixed_caps (stream->pad);
8507
8508     if (stream->protected) {
8509       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
8510         GST_ERROR_OBJECT (qtdemux,
8511             "Failed to configure protected stream caps.");
8512         return FALSE;
8513       }
8514     }
8515
8516     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8517         CUR_STREAM (stream)->caps);
8518     if (stream->new_stream) {
8519       gchar *stream_id;
8520       GstEvent *event;
8521       GstStreamFlags stream_flags = GST_STREAM_FLAG_NONE;
8522
8523       event =
8524           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
8525           0);
8526       if (event) {
8527         gst_event_parse_stream_flags (event, &stream_flags);
8528         if (gst_event_parse_group_id (event, &qtdemux->group_id))
8529           qtdemux->have_group_id = TRUE;
8530         else
8531           qtdemux->have_group_id = FALSE;
8532         gst_event_unref (event);
8533       } else if (!qtdemux->have_group_id) {
8534         qtdemux->have_group_id = TRUE;
8535         qtdemux->group_id = gst_util_group_id_next ();
8536       }
8537
8538       stream->new_stream = FALSE;
8539       stream_id =
8540           gst_pad_create_stream_id_printf (stream->pad,
8541           GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
8542       event = gst_event_new_stream_start (stream_id);
8543       if (qtdemux->have_group_id)
8544         gst_event_set_group_id (event, qtdemux->group_id);
8545       if (stream->disabled)
8546         stream_flags |= GST_STREAM_FLAG_UNSELECT;
8547       if (CUR_STREAM (stream)->sparse) {
8548         stream_flags |= GST_STREAM_FLAG_SPARSE;
8549       } else {
8550         stream_flags &= ~GST_STREAM_FLAG_SPARSE;
8551       }
8552       gst_event_set_stream_flags (event, stream_flags);
8553       gst_pad_push_event (stream->pad, event);
8554       g_free (stream_id);
8555     }
8556
8557     prev_caps = gst_pad_get_current_caps (stream->pad);
8558
8559     if (CUR_STREAM (stream)->caps) {
8560       if (!prev_caps
8561           || !gst_caps_is_equal_fixed (prev_caps, CUR_STREAM (stream)->caps)) {
8562         GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT,
8563             CUR_STREAM (stream)->caps);
8564         gst_pad_set_caps (stream->pad, CUR_STREAM (stream)->caps);
8565       } else {
8566         GST_DEBUG_OBJECT (qtdemux, "ignore duplicated caps");
8567       }
8568     } else {
8569       GST_WARNING_OBJECT (qtdemux, "stream without caps");
8570     }
8571
8572     if (prev_caps)
8573       gst_caps_unref (prev_caps);
8574     stream->new_caps = FALSE;
8575   }
8576   return TRUE;
8577 }
8578
8579 static void
8580 gst_qtdemux_stream_check_and_change_stsd_index (GstQTDemux * demux,
8581     QtDemuxStream * stream)
8582 {
8583   if (stream->cur_stsd_entry_index == stream->stsd_sample_description_id)
8584     return;
8585
8586   GST_DEBUG_OBJECT (stream->pad, "Changing stsd index from '%u' to '%u'",
8587       stream->cur_stsd_entry_index, stream->stsd_sample_description_id);
8588   if (G_UNLIKELY (stream->stsd_sample_description_id >=
8589           stream->stsd_entries_length)) {
8590     GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
8591         (_("This file is invalid and cannot be played.")),
8592         ("New sample description id is out of bounds (%d >= %d)",
8593             stream->stsd_sample_description_id, stream->stsd_entries_length));
8594   } else {
8595     stream->cur_stsd_entry_index = stream->stsd_sample_description_id;
8596     stream->new_caps = TRUE;
8597   }
8598 }
8599
8600 static gboolean
8601 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
8602     QtDemuxStream * stream, GstTagList * list)
8603 {
8604   gboolean ret = TRUE;
8605   /* consistent default for push based mode */
8606   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
8607
8608   if (stream->subtype == FOURCC_vide) {
8609     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8610
8611     stream->pad =
8612         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8613     g_free (name);
8614
8615     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8616       gst_object_unref (stream->pad);
8617       stream->pad = NULL;
8618       ret = FALSE;
8619       goto done;
8620     }
8621
8622     qtdemux->n_video_streams++;
8623   } else if (stream->subtype == FOURCC_soun) {
8624     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
8625
8626     stream->pad =
8627         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
8628     g_free (name);
8629     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8630       gst_object_unref (stream->pad);
8631       stream->pad = NULL;
8632       ret = FALSE;
8633       goto done;
8634     }
8635     qtdemux->n_audio_streams++;
8636   } else if (stream->subtype == FOURCC_strm) {
8637     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
8638   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
8639       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
8640     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
8641
8642     stream->pad =
8643         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
8644     g_free (name);
8645     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8646       gst_object_unref (stream->pad);
8647       stream->pad = NULL;
8648       ret = FALSE;
8649       goto done;
8650     }
8651     qtdemux->n_sub_streams++;
8652   } else if (CUR_STREAM (stream)->caps) {
8653     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
8654
8655     stream->pad =
8656         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
8657     g_free (name);
8658     if (!gst_qtdemux_configure_stream (qtdemux, stream)) {
8659       gst_object_unref (stream->pad);
8660       stream->pad = NULL;
8661       ret = FALSE;
8662       goto done;
8663     }
8664     qtdemux->n_video_streams++;
8665   } else {
8666     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
8667     goto done;
8668   }
8669
8670   if (stream->pad) {
8671     GList *l;
8672
8673     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
8674         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
8675     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
8676     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
8677
8678     if (stream->stream_tags)
8679       gst_tag_list_unref (stream->stream_tags);
8680     stream->stream_tags = list;
8681     list = NULL;
8682     /* global tags go on each pad anyway */
8683     stream->send_global_tags = TRUE;
8684     /* send upstream GST_EVENT_PROTECTION events that were received before
8685        this source pad was created */
8686     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
8687       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
8688   }
8689 done:
8690   if (list)
8691     gst_tag_list_unref (list);
8692   return ret;
8693 }
8694
8695 /* find next atom with @fourcc starting at @offset */
8696 static GstFlowReturn
8697 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
8698     guint64 * length, guint32 fourcc)
8699 {
8700   GstFlowReturn ret;
8701   guint32 lfourcc;
8702   GstBuffer *buf;
8703
8704   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
8705       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
8706
8707   while (TRUE) {
8708     GstMapInfo map;
8709
8710     buf = NULL;
8711     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
8712     if (G_UNLIKELY (ret != GST_FLOW_OK))
8713       goto locate_failed;
8714     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
8715       /* likely EOF */
8716       ret = GST_FLOW_EOS;
8717       gst_buffer_unref (buf);
8718       goto locate_failed;
8719     }
8720     gst_buffer_map (buf, &map, GST_MAP_READ);
8721     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
8722     gst_buffer_unmap (buf, &map);
8723     gst_buffer_unref (buf);
8724
8725     if (G_UNLIKELY (*length == 0)) {
8726       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
8727       ret = GST_FLOW_ERROR;
8728       goto locate_failed;
8729     }
8730
8731     if (lfourcc == fourcc) {
8732       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
8733           *offset);
8734       break;
8735     } else {
8736       GST_LOG_OBJECT (qtdemux,
8737           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
8738           GST_FOURCC_ARGS (fourcc), *offset);
8739       *offset += *length;
8740     }
8741   }
8742
8743   return GST_FLOW_OK;
8744
8745 locate_failed:
8746   {
8747     /* might simply have had last one */
8748     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
8749     return ret;
8750   }
8751 }
8752
8753 /* should only do something in pull mode */
8754 /* call with OBJECT lock */
8755 static GstFlowReturn
8756 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
8757 {
8758   guint64 length, offset;
8759   GstBuffer *buf = NULL;
8760   GstFlowReturn ret = GST_FLOW_OK;
8761   GstFlowReturn res = GST_FLOW_OK;
8762   GstMapInfo map;
8763
8764   offset = qtdemux->moof_offset;
8765   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
8766
8767   if (!offset) {
8768     GST_DEBUG_OBJECT (qtdemux, "no next moof");
8769     return GST_FLOW_EOS;
8770   }
8771
8772   /* best not do pull etc with lock held */
8773   GST_OBJECT_UNLOCK (qtdemux);
8774
8775   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8776   if (ret != GST_FLOW_OK)
8777     goto flow_failed;
8778
8779   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
8780   if (G_UNLIKELY (ret != GST_FLOW_OK))
8781     goto flow_failed;
8782   gst_buffer_map (buf, &map, GST_MAP_READ);
8783   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
8784     gst_buffer_unmap (buf, &map);
8785     gst_buffer_unref (buf);
8786     buf = NULL;
8787     goto parse_failed;
8788   }
8789
8790   gst_buffer_unmap (buf, &map);
8791   gst_buffer_unref (buf);
8792   buf = NULL;
8793
8794   offset += length;
8795   /* look for next moof */
8796   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
8797   if (G_UNLIKELY (ret != GST_FLOW_OK))
8798     goto flow_failed;
8799
8800 exit:
8801   GST_OBJECT_LOCK (qtdemux);
8802
8803   qtdemux->moof_offset = offset;
8804
8805   return res;
8806
8807 parse_failed:
8808   {
8809     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
8810     offset = 0;
8811     res = GST_FLOW_ERROR;
8812     goto exit;
8813   }
8814 flow_failed:
8815   {
8816     /* maybe upstream temporarily flushing */
8817     if (ret != GST_FLOW_FLUSHING) {
8818       GST_DEBUG_OBJECT (qtdemux, "no next moof");
8819       offset = 0;
8820     } else {
8821       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
8822       /* resume at current position next time */
8823     }
8824     res = ret;
8825     goto exit;
8826   }
8827 }
8828
8829 /* initialise bytereaders for stbl sub-atoms */
8830 static gboolean
8831 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
8832 {
8833   stream->stbl_index = -1;      /* no samples have yet been parsed */
8834   stream->sample_index = -1;
8835
8836   /* time-to-sample atom */
8837   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
8838     goto corrupt_file;
8839
8840   /* copy atom data into a new buffer for later use */
8841   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
8842
8843   /* skip version + flags */
8844   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
8845       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
8846     goto corrupt_file;
8847   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
8848
8849   /* make sure there's enough data */
8850   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
8851     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
8852     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
8853         stream->n_sample_times);
8854     if (!stream->n_sample_times)
8855       goto corrupt_file;
8856   }
8857
8858   /* sync sample atom */
8859   stream->stps_present = FALSE;
8860   if ((stream->stss_present =
8861           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
8862               &stream->stss) ? TRUE : FALSE) == TRUE) {
8863     /* copy atom data into a new buffer for later use */
8864     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
8865
8866     /* skip version + flags */
8867     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
8868         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
8869       goto corrupt_file;
8870
8871     if (stream->n_sample_syncs) {
8872       /* make sure there's enough data */
8873       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
8874         goto corrupt_file;
8875     }
8876
8877     /* partial sync sample atom */
8878     if ((stream->stps_present =
8879             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
8880                 &stream->stps) ? TRUE : FALSE) == TRUE) {
8881       /* copy atom data into a new buffer for later use */
8882       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
8883
8884       /* skip version + flags */
8885       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
8886           !gst_byte_reader_get_uint32_be (&stream->stps,
8887               &stream->n_sample_partial_syncs))
8888         goto corrupt_file;
8889
8890       /* if there are no entries, the stss table contains the real
8891        * sync samples */
8892       if (stream->n_sample_partial_syncs) {
8893         /* make sure there's enough data */
8894         if (!qt_atom_parser_has_chunks (&stream->stps,
8895                 stream->n_sample_partial_syncs, 4))
8896           goto corrupt_file;
8897       }
8898     }
8899   }
8900
8901   /* sample size */
8902   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
8903     goto no_samples;
8904
8905   /* copy atom data into a new buffer for later use */
8906   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
8907
8908   /* skip version + flags */
8909   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
8910       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
8911     goto corrupt_file;
8912
8913   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
8914     goto corrupt_file;
8915
8916   if (!stream->n_samples)
8917     goto no_samples;
8918
8919   /* sample-to-chunk atom */
8920   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
8921     goto corrupt_file;
8922
8923   /* copy atom data into a new buffer for later use */
8924   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
8925
8926   /* skip version + flags */
8927   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
8928       !gst_byte_reader_get_uint32_be (&stream->stsc,
8929           &stream->n_samples_per_chunk))
8930     goto corrupt_file;
8931
8932   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
8933       stream->n_samples_per_chunk);
8934
8935   /* make sure there's enough data */
8936   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
8937           12))
8938     goto corrupt_file;
8939
8940
8941   /* chunk offset */
8942   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
8943     stream->co_size = sizeof (guint32);
8944   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
8945           &stream->stco))
8946     stream->co_size = sizeof (guint64);
8947   else
8948     goto corrupt_file;
8949
8950   /* copy atom data into a new buffer for later use */
8951   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
8952
8953   /* skip version + flags */
8954   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
8955     goto corrupt_file;
8956
8957   /* chunks_are_samples == TRUE means treat chunks as samples */
8958   stream->chunks_are_samples = stream->sample_size
8959       && !CUR_STREAM (stream)->sampled;
8960   if (stream->chunks_are_samples) {
8961     /* treat chunks as samples */
8962     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
8963       goto corrupt_file;
8964   } else {
8965     /* skip number of entries */
8966     if (!gst_byte_reader_skip (&stream->stco, 4))
8967       goto corrupt_file;
8968
8969     /* make sure there are enough data in the stsz atom */
8970     if (!stream->sample_size) {
8971       /* different sizes for each sample */
8972       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
8973         goto corrupt_file;
8974     }
8975   }
8976
8977   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
8978       stream->n_samples, (guint) sizeof (QtDemuxSample),
8979       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
8980
8981   if (stream->n_samples >=
8982       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
8983     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
8984         "be larger than %uMB (broken file?)", stream->n_samples,
8985         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
8986     return FALSE;
8987   }
8988
8989   g_assert (stream->samples == NULL);
8990   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
8991   if (!stream->samples) {
8992     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
8993         stream->n_samples);
8994     return FALSE;
8995   }
8996
8997   /* composition time-to-sample */
8998   if ((stream->ctts_present =
8999           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
9000               &stream->ctts) ? TRUE : FALSE) == TRUE) {
9001     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
9002
9003     /* copy atom data into a new buffer for later use */
9004     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
9005
9006     /* skip version + flags */
9007     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
9008         || !gst_byte_reader_get_uint32_be (&stream->ctts,
9009             &stream->n_composition_times))
9010       goto corrupt_file;
9011
9012     /* make sure there's enough data */
9013     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
9014             4 + 4))
9015       goto corrupt_file;
9016
9017     /* This is optional, if missing we iterate the ctts */
9018     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
9019       if (!gst_byte_reader_skip (&cslg, 1 + 3)
9020           || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
9021         g_free ((gpointer) cslg.data);
9022         goto corrupt_file;
9023       }
9024     } else {
9025       gint32 cslg_least = 0;
9026       guint num_entries, pos;
9027       gint i;
9028
9029       pos = gst_byte_reader_get_pos (&stream->ctts);
9030       num_entries = stream->n_composition_times;
9031
9032       stream->cslg_shift = 0;
9033
9034       for (i = 0; i < num_entries; i++) {
9035         gint32 offset;
9036
9037         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
9038         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9039
9040         if (offset < cslg_least)
9041           cslg_least = offset;
9042       }
9043
9044       if (cslg_least < 0)
9045         stream->cslg_shift = ABS (cslg_least);
9046       else
9047         stream->cslg_shift = 0;
9048
9049       /* reset the reader so we can generate sample table */
9050       gst_byte_reader_set_pos (&stream->ctts, pos);
9051     }
9052   } else {
9053     /* Ensure the cslg_shift value is consistent so we can use it
9054      * unconditionnally to produce TS and Segment */
9055     stream->cslg_shift = 0;
9056   }
9057
9058   return TRUE;
9059
9060 corrupt_file:
9061   {
9062     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9063         (_("This file is corrupt and cannot be played.")), (NULL));
9064     return FALSE;
9065   }
9066 no_samples:
9067   {
9068     gst_qtdemux_stbl_free (stream);
9069     if (!qtdemux->fragmented) {
9070       /* not quite good */
9071       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
9072       return FALSE;
9073     } else {
9074       /* may pick up samples elsewhere */
9075       return TRUE;
9076     }
9077   }
9078 }
9079
9080 /* collect samples from the next sample to be parsed up to sample @n for @stream
9081  * by reading the info from @stbl
9082  *
9083  * This code can be executed from both the streaming thread and the seeking
9084  * thread so it takes the object lock to protect itself
9085  */
9086 static gboolean
9087 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
9088 {
9089   gint i, j, k;
9090   QtDemuxSample *samples, *first, *cur, *last;
9091   guint32 n_samples_per_chunk;
9092   guint32 n_samples;
9093
9094   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
9095       GST_FOURCC_FORMAT ", pad %s",
9096       GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc),
9097       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
9098
9099   n_samples = stream->n_samples;
9100
9101   if (n >= n_samples)
9102     goto out_of_samples;
9103
9104   GST_OBJECT_LOCK (qtdemux);
9105   if (n <= stream->stbl_index)
9106     goto already_parsed;
9107
9108   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
9109
9110   if (!stream->stsz.data) {
9111     /* so we already parsed and passed all the moov samples;
9112      * onto fragmented ones */
9113     g_assert (qtdemux->fragmented);
9114     goto done;
9115   }
9116
9117   /* pointer to the sample table */
9118   samples = stream->samples;
9119
9120   /* starts from -1, moves to the next sample index to parse */
9121   stream->stbl_index++;
9122
9123   /* keep track of the first and last sample to fill */
9124   first = &samples[stream->stbl_index];
9125   last = &samples[n];
9126
9127   if (!stream->chunks_are_samples) {
9128     /* set the sample sizes */
9129     if (stream->sample_size == 0) {
9130       /* different sizes for each sample */
9131       for (cur = first; cur <= last; cur++) {
9132         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
9133         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
9134             (guint) (cur - samples), cur->size);
9135       }
9136     } else {
9137       /* samples have the same size */
9138       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
9139       for (cur = first; cur <= last; cur++)
9140         cur->size = stream->sample_size;
9141     }
9142   }
9143
9144   n_samples_per_chunk = stream->n_samples_per_chunk;
9145   cur = first;
9146
9147   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
9148     guint32 last_chunk;
9149
9150     if (stream->stsc_chunk_index >= stream->last_chunk
9151         || stream->stsc_chunk_index < stream->first_chunk) {
9152       stream->first_chunk =
9153           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9154       stream->samples_per_chunk =
9155           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
9156       /* starts from 1 */
9157       stream->stsd_sample_description_id =
9158           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc) - 1;
9159
9160       /* chunk numbers are counted from 1 it seems */
9161       if (G_UNLIKELY (stream->first_chunk == 0))
9162         goto corrupt_file;
9163
9164       --stream->first_chunk;
9165
9166       /* the last chunk of each entry is calculated by taking the first chunk
9167        * of the next entry; except if there is no next, where we fake it with
9168        * INT_MAX */
9169       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
9170         stream->last_chunk = G_MAXUINT32;
9171       } else {
9172         stream->last_chunk =
9173             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
9174         if (G_UNLIKELY (stream->last_chunk == 0))
9175           goto corrupt_file;
9176
9177         --stream->last_chunk;
9178       }
9179
9180       GST_LOG_OBJECT (qtdemux,
9181           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d"
9182           "sample desc ID: %d", i, stream->first_chunk, stream->last_chunk,
9183           stream->samples_per_chunk, stream->stsd_sample_description_id);
9184
9185       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
9186         goto corrupt_file;
9187
9188       if (stream->last_chunk != G_MAXUINT32) {
9189         if (!qt_atom_parser_peek_sub (&stream->stco,
9190                 stream->first_chunk * stream->co_size,
9191                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
9192                 &stream->co_chunk))
9193           goto corrupt_file;
9194
9195       } else {
9196         stream->co_chunk = stream->stco;
9197         if (!gst_byte_reader_skip (&stream->co_chunk,
9198                 stream->first_chunk * stream->co_size))
9199           goto corrupt_file;
9200       }
9201
9202       stream->stsc_chunk_index = stream->first_chunk;
9203     }
9204
9205     last_chunk = stream->last_chunk;
9206
9207     if (stream->chunks_are_samples) {
9208       cur = &samples[stream->stsc_chunk_index];
9209
9210       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9211         if (j > n) {
9212           /* save state */
9213           stream->stsc_chunk_index = j;
9214           goto done;
9215         }
9216
9217         cur->offset =
9218             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
9219             stream->co_size);
9220
9221         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
9222             "%" G_GUINT64_FORMAT, j, cur->offset);
9223
9224         if (CUR_STREAM (stream)->samples_per_frame > 0 &&
9225             CUR_STREAM (stream)->bytes_per_frame > 0) {
9226           cur->size =
9227               (stream->samples_per_chunk * CUR_STREAM (stream)->n_channels) /
9228               CUR_STREAM (stream)->samples_per_frame *
9229               CUR_STREAM (stream)->bytes_per_frame;
9230         } else {
9231           cur->size = stream->samples_per_chunk;
9232         }
9233
9234         GST_DEBUG_OBJECT (qtdemux,
9235             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
9236             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
9237                     stream->stco_sample_index)), cur->size);
9238
9239         cur->timestamp = stream->stco_sample_index;
9240         cur->duration = stream->samples_per_chunk;
9241         cur->keyframe = TRUE;
9242         cur++;
9243
9244         stream->stco_sample_index += stream->samples_per_chunk;
9245       }
9246       stream->stsc_chunk_index = j;
9247     } else {
9248       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
9249         guint32 samples_per_chunk;
9250         guint64 chunk_offset;
9251
9252         if (!stream->stsc_sample_index
9253             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
9254                 &stream->chunk_offset))
9255           goto corrupt_file;
9256
9257         samples_per_chunk = stream->samples_per_chunk;
9258         chunk_offset = stream->chunk_offset;
9259
9260         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
9261           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
9262               G_GUINT64_FORMAT " and size %d",
9263               (guint) (cur - samples), chunk_offset, cur->size);
9264
9265           cur->offset = chunk_offset;
9266           chunk_offset += cur->size;
9267           cur++;
9268
9269           if (G_UNLIKELY (cur > last)) {
9270             /* save state */
9271             stream->stsc_sample_index = k + 1;
9272             stream->chunk_offset = chunk_offset;
9273             stream->stsc_chunk_index = j;
9274             goto done2;
9275           }
9276         }
9277         stream->stsc_sample_index = 0;
9278       }
9279       stream->stsc_chunk_index = j;
9280     }
9281     stream->stsc_index++;
9282   }
9283
9284   if (stream->chunks_are_samples)
9285     goto ctts;
9286 done2:
9287   {
9288     guint32 n_sample_times;
9289
9290     n_sample_times = stream->n_sample_times;
9291     cur = first;
9292
9293     for (i = stream->stts_index; i < n_sample_times; i++) {
9294       guint32 stts_samples;
9295       gint32 stts_duration;
9296       gint64 stts_time;
9297
9298       if (stream->stts_sample_index >= stream->stts_samples
9299           || !stream->stts_sample_index) {
9300
9301         stream->stts_samples =
9302             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9303         stream->stts_duration =
9304             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
9305
9306         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
9307             i, stream->stts_samples, stream->stts_duration);
9308
9309         stream->stts_sample_index = 0;
9310       }
9311
9312       stts_samples = stream->stts_samples;
9313       stts_duration = stream->stts_duration;
9314       stts_time = stream->stts_time;
9315
9316       for (j = stream->stts_sample_index; j < stts_samples; j++) {
9317         GST_DEBUG_OBJECT (qtdemux,
9318             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
9319             (guint) (cur - samples), j,
9320             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
9321
9322         cur->timestamp = stts_time;
9323         cur->duration = stts_duration;
9324
9325         /* avoid 32-bit wrap-around,
9326          * but still mind possible 'negative' duration */
9327         stts_time += (gint64) stts_duration;
9328         cur++;
9329
9330         if (G_UNLIKELY (cur > last)) {
9331           /* save values */
9332           stream->stts_time = stts_time;
9333           stream->stts_sample_index = j + 1;
9334           if (stream->stts_sample_index >= stream->stts_samples)
9335             stream->stts_index++;
9336           goto done3;
9337         }
9338       }
9339       stream->stts_sample_index = 0;
9340       stream->stts_time = stts_time;
9341       stream->stts_index++;
9342     }
9343     /* fill up empty timestamps with the last timestamp, this can happen when
9344      * the last samples do not decode and so we don't have timestamps for them.
9345      * We however look at the last timestamp to estimate the track length so we
9346      * need something in here. */
9347     for (; cur < last; cur++) {
9348       GST_DEBUG_OBJECT (qtdemux,
9349           "fill sample %d: timestamp %" GST_TIME_FORMAT,
9350           (guint) (cur - samples),
9351           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
9352       cur->timestamp = stream->stts_time;
9353       cur->duration = -1;
9354     }
9355   }
9356 done3:
9357   {
9358     /* sample sync, can be NULL */
9359     if (stream->stss_present == TRUE) {
9360       guint32 n_sample_syncs;
9361
9362       n_sample_syncs = stream->n_sample_syncs;
9363
9364       if (!n_sample_syncs) {
9365         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
9366         stream->all_keyframe = TRUE;
9367       } else {
9368         for (i = stream->stss_index; i < n_sample_syncs; i++) {
9369           /* note that the first sample is index 1, not 0 */
9370           guint32 index;
9371
9372           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
9373
9374           if (G_LIKELY (index > 0 && index <= n_samples)) {
9375             index -= 1;
9376             samples[index].keyframe = TRUE;
9377             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9378             /* and exit if we have enough samples */
9379             if (G_UNLIKELY (index >= n)) {
9380               i++;
9381               break;
9382             }
9383           }
9384         }
9385         /* save state */
9386         stream->stss_index = i;
9387       }
9388
9389       /* stps marks partial sync frames like open GOP I-Frames */
9390       if (stream->stps_present == TRUE) {
9391         guint32 n_sample_partial_syncs;
9392
9393         n_sample_partial_syncs = stream->n_sample_partial_syncs;
9394
9395         /* if there are no entries, the stss table contains the real
9396          * sync samples */
9397         if (n_sample_partial_syncs) {
9398           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
9399             /* note that the first sample is index 1, not 0 */
9400             guint32 index;
9401
9402             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
9403
9404             if (G_LIKELY (index > 0 && index <= n_samples)) {
9405               index -= 1;
9406               samples[index].keyframe = TRUE;
9407               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
9408               /* and exit if we have enough samples */
9409               if (G_UNLIKELY (index >= n)) {
9410                 i++;
9411                 break;
9412               }
9413             }
9414           }
9415           /* save state */
9416           stream->stps_index = i;
9417         }
9418       }
9419     } else {
9420       /* no stss, all samples are keyframes */
9421       stream->all_keyframe = TRUE;
9422       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
9423     }
9424   }
9425
9426 ctts:
9427   /* composition time to sample */
9428   if (stream->ctts_present == TRUE) {
9429     guint32 n_composition_times;
9430     guint32 ctts_count;
9431     gint32 ctts_soffset;
9432
9433     /* Fill in the pts_offsets */
9434     cur = first;
9435     n_composition_times = stream->n_composition_times;
9436
9437     for (i = stream->ctts_index; i < n_composition_times; i++) {
9438       if (stream->ctts_sample_index >= stream->ctts_count
9439           || !stream->ctts_sample_index) {
9440         stream->ctts_count =
9441             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
9442         stream->ctts_soffset =
9443             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
9444         stream->ctts_sample_index = 0;
9445       }
9446
9447       ctts_count = stream->ctts_count;
9448       ctts_soffset = stream->ctts_soffset;
9449
9450       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
9451         cur->pts_offset = ctts_soffset;
9452         cur++;
9453
9454         if (G_UNLIKELY (cur > last)) {
9455           /* save state */
9456           stream->ctts_sample_index = j + 1;
9457           goto done;
9458         }
9459       }
9460       stream->ctts_sample_index = 0;
9461       stream->ctts_index++;
9462     }
9463   }
9464 done:
9465   stream->stbl_index = n;
9466   /* if index has been completely parsed, free data that is no-longer needed */
9467   if (n + 1 == stream->n_samples) {
9468     gst_qtdemux_stbl_free (stream);
9469     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
9470     if (qtdemux->pullbased) {
9471       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
9472       while (n + 1 == stream->n_samples)
9473         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
9474           break;
9475     }
9476   }
9477   GST_OBJECT_UNLOCK (qtdemux);
9478
9479   return TRUE;
9480
9481   /* SUCCESS */
9482 already_parsed:
9483   {
9484     GST_LOG_OBJECT (qtdemux,
9485         "Tried to parse up to sample %u but this sample has already been parsed",
9486         n);
9487     /* if fragmented, there may be more */
9488     if (qtdemux->fragmented && n == stream->stbl_index)
9489       goto done;
9490     GST_OBJECT_UNLOCK (qtdemux);
9491     return TRUE;
9492   }
9493   /* ERRORS */
9494 out_of_samples:
9495   {
9496     GST_LOG_OBJECT (qtdemux,
9497         "Tried to parse up to sample %u but there are only %u samples", n + 1,
9498         stream->n_samples);
9499     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9500         (_("This file is corrupt and cannot be played.")), (NULL));
9501     return FALSE;
9502   }
9503 corrupt_file:
9504   {
9505     GST_OBJECT_UNLOCK (qtdemux);
9506     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9507         (_("This file is corrupt and cannot be played.")), (NULL));
9508     return FALSE;
9509   }
9510 }
9511
9512 /* collect all segment info for @stream.
9513  */
9514 static gboolean
9515 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
9516     GNode * trak)
9517 {
9518   GNode *edts;
9519   /* accept edts if they contain gaps at start and there is only
9520    * one media segment */
9521   gboolean allow_pushbased_edts = TRUE;
9522   gint media_segments_count = 0;
9523
9524   /* parse and prepare segment info from the edit list */
9525   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
9526   stream->n_segments = 0;
9527   stream->segments = NULL;
9528   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
9529     GNode *elst;
9530     gint n_segments;
9531     gint i, count, entry_size;
9532     guint64 time;
9533     GstClockTime stime;
9534     const guint8 *buffer;
9535     guint8 version;
9536     guint32 size;
9537
9538     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
9539     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
9540       goto done;
9541
9542     buffer = elst->data;
9543
9544     size = QT_UINT32 (buffer);
9545     /* version, flags, n_segments */
9546     if (size < 16) {
9547       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9548       goto done;
9549     }
9550     version = QT_UINT8 (buffer + 8);
9551     entry_size = (version == 1) ? 20 : 12;
9552
9553     n_segments = QT_UINT32 (buffer + 12);
9554
9555     if (n_segments > 100000 || size < 16 + n_segments * entry_size) {
9556       GST_WARNING_OBJECT (qtdemux, "Invalid edit list");
9557       goto done;
9558     }
9559
9560     /* we might allocate a bit too much, at least allocate 1 segment */
9561     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
9562
9563     /* segments always start from 0 */
9564     time = 0;
9565     stime = 0;
9566     count = 0;
9567     buffer += 16;
9568     for (i = 0; i < n_segments; i++) {
9569       guint64 duration;
9570       guint64 media_time;
9571       gboolean time_valid = TRUE;
9572       QtDemuxSegment *segment;
9573       guint32 rate_int;
9574       GstClockTime media_start = GST_CLOCK_TIME_NONE;
9575
9576       if (version == 1) {
9577         media_time = QT_UINT64 (buffer + 8);
9578         duration = QT_UINT64 (buffer);
9579         if (media_time == G_MAXUINT64)
9580           time_valid = FALSE;
9581       } else {
9582         media_time = QT_UINT32 (buffer + 4);
9583         duration = QT_UINT32 (buffer);
9584         if (media_time == G_MAXUINT32)
9585           time_valid = FALSE;
9586       }
9587
9588       if (time_valid)
9589         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
9590
9591       segment = &stream->segments[count++];
9592
9593       /* time and duration expressed in global timescale */
9594       segment->time = stime;
9595       /* add non scaled values so we don't cause roundoff errors */
9596       if (duration || media_start == GST_CLOCK_TIME_NONE) {
9597         time += duration;
9598         stime = QTTIME_TO_GSTTIME (qtdemux, time);
9599         segment->duration = stime - segment->time;
9600       } else {
9601         /* zero duration does not imply media_start == media_stop
9602          * but, only specify media_start.*/
9603         stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
9604         if (GST_CLOCK_TIME_IS_VALID (stime) && time_valid
9605             && stime >= media_start) {
9606           segment->duration = stime - media_start;
9607         } else {
9608           segment->duration = GST_CLOCK_TIME_NONE;
9609         }
9610       }
9611       segment->stop_time = stime;
9612
9613       segment->trak_media_start = media_time;
9614       /* media_time expressed in stream timescale */
9615       if (time_valid) {
9616         segment->media_start = media_start;
9617         segment->media_stop = segment->media_start + segment->duration;
9618         media_segments_count++;
9619       } else {
9620         segment->media_start = GST_CLOCK_TIME_NONE;
9621         segment->media_stop = GST_CLOCK_TIME_NONE;
9622       }
9623       rate_int = QT_UINT32 (buffer + ((version == 1) ? 16 : 8));
9624
9625       if (rate_int <= 1) {
9626         /* 0 is not allowed, some programs write 1 instead of the floating point
9627          * value */
9628         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
9629             rate_int);
9630         segment->rate = 1;
9631       } else {
9632         segment->rate = rate_int / 65536.0;
9633       }
9634
9635       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
9636           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
9637           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
9638           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
9639           i, GST_TIME_ARGS (segment->time),
9640           GST_TIME_ARGS (segment->duration),
9641           GST_TIME_ARGS (segment->media_start), media_time,
9642           GST_TIME_ARGS (segment->media_stop),
9643           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
9644           stream->timescale);
9645       if (segment->stop_time > qtdemux->segment.stop) {
9646         GST_WARNING_OBJECT (qtdemux, "Segment %d "
9647             " extends to %" GST_TIME_FORMAT
9648             " past the end of the file duration %" GST_TIME_FORMAT
9649             " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
9650             GST_TIME_ARGS (qtdemux->segment.stop));
9651         qtdemux->segment.stop = segment->stop_time;
9652       }
9653
9654       buffer += entry_size;
9655     }
9656     GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
9657     stream->n_segments = count;
9658     if (media_segments_count != 1)
9659       allow_pushbased_edts = FALSE;
9660   }
9661 done:
9662
9663   /* push based does not handle segments, so act accordingly here,
9664    * and warn if applicable */
9665   if (!qtdemux->pullbased && !allow_pushbased_edts) {
9666     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
9667     /* remove and use default one below, we stream like it anyway */
9668     g_free (stream->segments);
9669     stream->segments = NULL;
9670     stream->n_segments = 0;
9671   }
9672
9673   /* no segments, create one to play the complete trak */
9674   if (stream->n_segments == 0) {
9675     GstClockTime stream_duration =
9676         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
9677
9678     if (stream->segments == NULL)
9679       stream->segments = g_new (QtDemuxSegment, 1);
9680
9681     /* represent unknown our way */
9682     if (stream_duration == 0)
9683       stream_duration = GST_CLOCK_TIME_NONE;
9684
9685     stream->segments[0].time = 0;
9686     stream->segments[0].stop_time = stream_duration;
9687     stream->segments[0].duration = stream_duration;
9688     stream->segments[0].media_start = 0;
9689     stream->segments[0].media_stop = stream_duration;
9690     stream->segments[0].rate = 1.0;
9691     stream->segments[0].trak_media_start = 0;
9692
9693     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
9694         GST_TIME_ARGS (stream_duration));
9695     stream->n_segments = 1;
9696     stream->dummy_segment = TRUE;
9697   }
9698   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
9699
9700   return TRUE;
9701 }
9702
9703 /*
9704  * Parses the stsd atom of a svq3 trak looking for
9705  * the SMI and gama atoms.
9706  */
9707 static void
9708 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux,
9709     const guint8 * stsd_entry_data, const guint8 ** gamma, GstBuffer ** seqh)
9710 {
9711   const guint8 *_gamma = NULL;
9712   GstBuffer *_seqh = NULL;
9713   const guint8 *stsd_data = stsd_entry_data;
9714   guint32 length = QT_UINT32 (stsd_data);
9715   guint16 version;
9716
9717   if (length < 32) {
9718     GST_WARNING_OBJECT (qtdemux, "stsd too short");
9719     goto end;
9720   }
9721
9722   stsd_data += 16;
9723   length -= 16;
9724   version = QT_UINT16 (stsd_data);
9725   if (version == 3) {
9726     if (length >= 70) {
9727       length -= 70;
9728       stsd_data += 70;
9729       while (length > 8) {
9730         guint32 fourcc, size;
9731         const guint8 *data;
9732         size = QT_UINT32 (stsd_data);
9733         fourcc = QT_FOURCC (stsd_data + 4);
9734         data = stsd_data + 8;
9735
9736         if (size == 0) {
9737           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
9738               "svq3 atom parsing");
9739           goto end;
9740         }
9741
9742         switch (fourcc) {
9743           case FOURCC_gama:{
9744             if (size == 12) {
9745               _gamma = data;
9746             } else {
9747               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
9748                   " for gama atom, expected 12", size);
9749             }
9750             break;
9751           }
9752           case FOURCC_SMI_:{
9753             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
9754               guint32 seqh_size;
9755               if (_seqh != NULL) {
9756                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
9757                     " found, ignoring");
9758               } else {
9759                 seqh_size = QT_UINT32 (data + 4);
9760                 if (seqh_size > 0) {
9761                   _seqh = gst_buffer_new_and_alloc (seqh_size);
9762                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
9763                 }
9764               }
9765             }
9766             break;
9767           }
9768           default:{
9769             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
9770                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
9771           }
9772         }
9773
9774         if (size <= length) {
9775           length -= size;
9776           stsd_data += size;
9777         }
9778       }
9779     } else {
9780       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
9781     }
9782   } else {
9783     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
9784         G_GUINT16_FORMAT, version);
9785     goto end;
9786   }
9787
9788 end:
9789   if (gamma) {
9790     *gamma = _gamma;
9791   }
9792   if (seqh) {
9793     *seqh = _seqh;
9794   } else if (_seqh) {
9795     gst_buffer_unref (_seqh);
9796   }
9797 }
9798
9799 static gchar *
9800 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
9801 {
9802   GNode *dinf;
9803   GstByteReader dref;
9804   gchar *uri = NULL;
9805
9806   /*
9807    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
9808    * atom that might contain a 'data' atom with the rtsp uri.
9809    * This case was reported in bug #597497, some info about
9810    * the hndl atom can be found in TN1195
9811    */
9812   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
9813   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
9814
9815   if (dinf) {
9816     guint32 dref_num_entries = 0;
9817     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
9818         gst_byte_reader_skip (&dref, 4) &&
9819         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
9820       gint i;
9821
9822       /* search dref entries for hndl atom */
9823       for (i = 0; i < dref_num_entries; i++) {
9824         guint32 size = 0, type;
9825         guint8 string_len = 0;
9826         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
9827             qt_atom_parser_get_fourcc (&dref, &type)) {
9828           if (type == FOURCC_hndl) {
9829             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
9830
9831             /* skip data reference handle bytes and the
9832              * following pascal string and some extra 4
9833              * bytes I have no idea what are */
9834             if (!gst_byte_reader_skip (&dref, 4) ||
9835                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
9836                 !gst_byte_reader_skip (&dref, string_len + 4)) {
9837               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
9838               break;
9839             }
9840
9841             /* iterate over the atoms to find the data atom */
9842             while (gst_byte_reader_get_remaining (&dref) >= 8) {
9843               guint32 atom_size;
9844               guint32 atom_type;
9845
9846               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
9847                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
9848                 if (atom_type == FOURCC_data) {
9849                   const guint8 *uri_aux = NULL;
9850
9851                   /* found the data atom that might contain the rtsp uri */
9852                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
9853                       "hndl atom, interpreting it as an URI");
9854                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
9855                           &uri_aux)) {
9856                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
9857                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
9858                     else
9859                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
9860                           "didn't contain a rtsp address");
9861                   } else {
9862                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
9863                         "atom contents");
9864                   }
9865                   break;
9866                 }
9867                 /* skipping to the next entry */
9868                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
9869                   break;
9870               } else {
9871                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
9872                     "atom header");
9873                 break;
9874               }
9875             }
9876             break;
9877           }
9878           /* skip to the next entry */
9879           if (!gst_byte_reader_skip (&dref, size - 8))
9880             break;
9881         } else {
9882           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
9883         }
9884       }
9885       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
9886     }
9887   }
9888   return uri;
9889 }
9890
9891 #define AMR_NB_ALL_MODES        0x81ff
9892 #define AMR_WB_ALL_MODES        0x83ff
9893 static guint
9894 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
9895 {
9896   /* The 'damr' atom is of the form:
9897    *
9898    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
9899    *    32 b       8 b          16 b           8 b                 8 b
9900    *
9901    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
9902    * represents the highest mode used in the stream (and thus the maximum
9903    * bitrate), with a couple of special cases as seen below.
9904    */
9905
9906   /* Map of frame type ID -> bitrate */
9907   static const guint nb_bitrates[] = {
9908     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
9909   };
9910   static const guint wb_bitrates[] = {
9911     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
9912   };
9913   GstMapInfo map;
9914   gsize max_mode;
9915   guint16 mode_set;
9916
9917   gst_buffer_map (buf, &map, GST_MAP_READ);
9918
9919   if (map.size != 0x11) {
9920     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
9921     goto bad_data;
9922   }
9923
9924   if (QT_FOURCC (map.data + 4) != FOURCC_damr) {
9925     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
9926         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
9927     goto bad_data;
9928   }
9929
9930   mode_set = QT_UINT16 (map.data + 13);
9931
9932   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
9933     max_mode = 7 + (wb ? 1 : 0);
9934   else
9935     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
9936     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
9937
9938   if (max_mode == -1) {
9939     GST_DEBUG ("No mode indication was found (mode set) = %x",
9940         (guint) mode_set);
9941     goto bad_data;
9942   }
9943
9944   gst_buffer_unmap (buf, &map);
9945   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
9946
9947 bad_data:
9948   gst_buffer_unmap (buf, &map);
9949   return 0;
9950 }
9951
9952 static gboolean
9953 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
9954     GstByteReader * reader, guint32 * matrix, const gchar * atom)
9955 {
9956   /*
9957    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
9958    * [0 1 2]
9959    * [3 4 5]
9960    * [6 7 8]
9961    */
9962
9963   if (gst_byte_reader_get_remaining (reader) < 36)
9964     return FALSE;
9965
9966   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
9967   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
9968   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
9969   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
9970   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
9971   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
9972   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
9973   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
9974   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
9975
9976   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
9977   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
9978       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
9979       matrix[2] & 0xFF);
9980   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
9981       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
9982       matrix[5] & 0xFF);
9983   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
9984       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
9985       matrix[8] & 0xFF);
9986
9987   return TRUE;
9988 }
9989
9990 static void
9991 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
9992     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
9993 {
9994
9995 /* [a b c]
9996  * [d e f]
9997  * [g h i]
9998  *
9999  * This macro will only compare value abdegh, it expects cfi to have already
10000  * been checked
10001  */
10002 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
10003                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
10004
10005   /* only handle the cases where the last column has standard values */
10006   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
10007     const gchar *rotation_tag = NULL;
10008
10009     /* no rotation needed */
10010     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
10011       /* NOP */
10012     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
10013       rotation_tag = "rotate-90";
10014     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
10015       rotation_tag = "rotate-180";
10016     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
10017       rotation_tag = "rotate-270";
10018     } else {
10019       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10020     }
10021
10022     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
10023         rotation_tag);
10024     if (rotation_tag != NULL) {
10025       if (*taglist == NULL)
10026         *taglist = gst_tag_list_new_empty ();
10027       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
10028           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
10029     }
10030   } else {
10031     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
10032   }
10033 }
10034
10035 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
10036  * protected streams (sinf, frma, schm and schi); if the protection scheme is
10037  * Common Encryption (cenc), the function will also parse the tenc box (defined
10038  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
10039  * (typically an enc[v|a|t|s] sample entry); the function will set
10040  * @original_fmt to the fourcc of the original unencrypted stream format.
10041  * Returns TRUE if successful; FALSE otherwise. */
10042 static gboolean
10043 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
10044     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
10045 {
10046   GNode *sinf;
10047   GNode *frma;
10048   GNode *schm;
10049   GNode *schi;
10050
10051   g_return_val_if_fail (qtdemux != NULL, FALSE);
10052   g_return_val_if_fail (stream != NULL, FALSE);
10053   g_return_val_if_fail (container != NULL, FALSE);
10054   g_return_val_if_fail (original_fmt != NULL, FALSE);
10055
10056   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
10057   if (G_UNLIKELY (!sinf)) {
10058     if (stream->protection_scheme_type == FOURCC_cenc) {
10059       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
10060           "mandatory for Common Encryption");
10061       return FALSE;
10062     }
10063     return TRUE;
10064   }
10065
10066   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
10067   if (G_UNLIKELY (!frma)) {
10068     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
10069     return FALSE;
10070   }
10071
10072   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
10073   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
10074       GST_FOURCC_ARGS (*original_fmt));
10075
10076   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
10077   if (!schm) {
10078     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
10079     return FALSE;
10080   }
10081   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
10082   stream->protection_scheme_version =
10083       QT_UINT32 ((const guint8 *) schm->data + 16);
10084
10085   GST_DEBUG_OBJECT (qtdemux,
10086       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
10087       "protection_scheme_version: %#010x",
10088       GST_FOURCC_ARGS (stream->protection_scheme_type),
10089       stream->protection_scheme_version);
10090
10091   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
10092   if (!schi) {
10093     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
10094     return FALSE;
10095   }
10096   if (stream->protection_scheme_type == FOURCC_cenc) {
10097     QtDemuxCencSampleSetInfo *info;
10098     GNode *tenc;
10099     const guint8 *tenc_data;
10100     guint32 isEncrypted;
10101     guint8 iv_size;
10102     const guint8 *default_kid;
10103     GstBuffer *kid_buf;
10104
10105     if (G_UNLIKELY (!stream->protection_scheme_info))
10106       stream->protection_scheme_info =
10107           g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
10108
10109     info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
10110
10111     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
10112     if (!tenc) {
10113       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
10114           "which is mandatory for Common Encryption");
10115       return FALSE;
10116     }
10117     tenc_data = (const guint8 *) tenc->data + 12;
10118     isEncrypted = QT_UINT24 (tenc_data);
10119     iv_size = QT_UINT8 (tenc_data + 3);
10120     default_kid = (tenc_data + 4);
10121     kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
10122     gst_buffer_fill (kid_buf, 0, default_kid, 16);
10123     if (info->default_properties)
10124       gst_structure_free (info->default_properties);
10125     info->default_properties =
10126         gst_structure_new ("application/x-cenc",
10127         "iv_size", G_TYPE_UINT, iv_size,
10128         "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
10129         "kid", GST_TYPE_BUFFER, kid_buf, NULL);
10130     GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
10131         "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
10132     gst_buffer_unref (kid_buf);
10133   }
10134   return TRUE;
10135 }
10136
10137 /* parse the traks.
10138  * With each track we associate a new QtDemuxStream that contains all the info
10139  * about the trak.
10140  * traks that do not decode to something (like strm traks) will not have a pad.
10141  */
10142 static gboolean
10143 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
10144 {
10145   GstByteReader tkhd;
10146   int offset;
10147   GNode *mdia;
10148   GNode *mdhd;
10149   GNode *hdlr;
10150   GNode *minf;
10151   GNode *stbl;
10152   GNode *stsd;
10153   GNode *mp4a;
10154   GNode *mp4v;
10155   GNode *wave;
10156   GNode *esds;
10157   GNode *pasp;
10158   GNode *colr;
10159   GNode *tref;
10160   GNode *udta;
10161   GNode *svmi;
10162   GNode *fiel;
10163
10164   QtDemuxStream *stream = NULL;
10165   gboolean new_stream = FALSE;
10166   gchar *codec = NULL;
10167   const guint8 *stsd_data;
10168   const guint8 *stsd_entry_data;
10169   guint remaining_stsd_len;
10170   guint stsd_entry_count;
10171   guint stsd_index;
10172   guint16 lang_code;            /* quicktime lang code or packed iso code */
10173   guint32 version;
10174   guint32 tkhd_flags = 0;
10175   guint8 tkhd_version = 0;
10176   guint32 w = 0, h = 0;
10177   guint32 fourcc;
10178   guint value_size, stsd_len, len;
10179   guint32 track_id;
10180   guint32 dummy;
10181
10182   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
10183
10184   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
10185       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
10186       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
10187     goto corrupt_file;
10188
10189   /* pick between 64 or 32 bits */
10190   value_size = tkhd_version == 1 ? 8 : 4;
10191   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
10192       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
10193     goto corrupt_file;
10194
10195   if (!qtdemux->got_moov) {
10196     if (qtdemux_find_stream (qtdemux, track_id))
10197       goto existing_stream;
10198     stream = _create_stream ();
10199     stream->track_id = track_id;
10200     new_stream = TRUE;
10201   } else {
10202     stream = qtdemux_find_stream (qtdemux, track_id);
10203     if (!stream) {
10204       GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
10205       goto skip_track;
10206     }
10207
10208     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
10209
10210     /* flush samples data from this track from previous moov */
10211     gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
10212     gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
10213   }
10214   /* need defaults for fragments */
10215   qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10216
10217   if ((tkhd_flags & 1) == 0)
10218     stream->disabled = TRUE;
10219
10220   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
10221       tkhd_version, tkhd_flags, stream->track_id);
10222
10223   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
10224     goto corrupt_file;
10225
10226   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
10227     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
10228     if (qtdemux->major_brand != FOURCC_mjp2 ||
10229         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
10230       goto corrupt_file;
10231   }
10232
10233   len = QT_UINT32 ((guint8 *) mdhd->data);
10234   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
10235   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
10236   if (version == 0x01000000) {
10237     if (len < 38)
10238       goto corrupt_file;
10239     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
10240     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
10241     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
10242   } else {
10243     if (len < 30)
10244       goto corrupt_file;
10245     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
10246     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
10247     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
10248   }
10249
10250   if (lang_code < 0x400) {
10251     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
10252   } else if (lang_code == 0x7fff) {
10253     stream->lang_id[0] = 0;     /* unspecified */
10254   } else {
10255     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
10256     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
10257     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
10258     stream->lang_id[3] = 0;
10259   }
10260
10261   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
10262       stream->timescale);
10263   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
10264       stream->duration);
10265   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
10266       lang_code, stream->lang_id);
10267
10268   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
10269     goto corrupt_file;
10270
10271   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
10272     /* chapters track reference */
10273     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
10274     if (chap) {
10275       gsize length = GST_READ_UINT32_BE (chap->data);
10276       if (qtdemux->chapters_track_id)
10277         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
10278
10279       if (length >= 12) {
10280         qtdemux->chapters_track_id =
10281             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
10282       }
10283     }
10284   }
10285
10286   /* fragmented files may have bogus duration in moov */
10287   if (!qtdemux->fragmented &&
10288       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
10289     guint64 tdur1, tdur2;
10290
10291     /* don't overflow */
10292     tdur1 = stream->timescale * (guint64) qtdemux->duration;
10293     tdur2 = qtdemux->timescale * (guint64) stream->duration;
10294
10295     /* HACK:
10296      * some of those trailers, nowadays, have prologue images that are
10297      * themselves video tracks as well. I haven't really found a way to
10298      * identify those yet, except for just looking at their duration. */
10299     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
10300       GST_WARNING_OBJECT (qtdemux,
10301           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
10302           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
10303           "found, assuming preview image or something; skipping track",
10304           stream->duration, stream->timescale, qtdemux->duration,
10305           qtdemux->timescale);
10306       if (new_stream)
10307         gst_qtdemux_stream_free (qtdemux, stream);
10308       return TRUE;
10309     }
10310   }
10311
10312   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
10313     goto corrupt_file;
10314
10315   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
10316       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
10317
10318   len = QT_UINT32 ((guint8 *) hdlr->data);
10319   if (len >= 20)
10320     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
10321   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
10322       GST_FOURCC_ARGS (stream->subtype));
10323
10324   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
10325     goto corrupt_file;
10326
10327   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
10328     goto corrupt_file;
10329
10330   /*parse svmi header if existing */
10331   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
10332   if (svmi) {
10333     len = QT_UINT32 ((guint8 *) svmi->data);
10334     version = QT_UINT32 ((guint8 *) svmi->data + 8);
10335     if (!version) {
10336       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
10337       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
10338       guint8 frame_type, frame_layout;
10339
10340       /* MPEG-A stereo video */
10341       if (qtdemux->major_brand == FOURCC_ss02)
10342         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
10343
10344       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
10345       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
10346       switch (frame_type) {
10347         case 0:
10348           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
10349           break;
10350         case 1:
10351           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
10352           break;
10353         case 2:
10354           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
10355           break;
10356         case 3:
10357           /* mode 3 is primary/secondary view sequence, ie
10358            * left/right views in separate tracks. See section 7.2
10359            * of ISO/IEC 23000-11:2009 */
10360           GST_FIXME_OBJECT (qtdemux,
10361               "Implement stereo video in separate streams");
10362       }
10363
10364       if ((frame_layout & 0x1) == 0)
10365         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
10366
10367       GST_LOG_OBJECT (qtdemux,
10368           "StereoVideo: composition type: %u, is_left_first: %u",
10369           frame_type, frame_layout);
10370       stream->multiview_mode = mode;
10371       stream->multiview_flags = flags;
10372     }
10373   }
10374
10375   /* parse rest of tkhd */
10376   if (stream->subtype == FOURCC_vide) {
10377     guint32 matrix[9];
10378
10379     /* version 1 uses some 64-bit ints */
10380     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
10381       goto corrupt_file;
10382
10383     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
10384       goto corrupt_file;
10385
10386     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
10387         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
10388       goto corrupt_file;
10389
10390     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
10391         &stream->stream_tags);
10392   }
10393
10394   /* parse stsd */
10395   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
10396     goto corrupt_file;
10397   stsd_data = (const guint8 *) stsd->data;
10398
10399   /* stsd should at least have one entry */
10400   stsd_len = QT_UINT32 (stsd_data);
10401   if (stsd_len < 24) {
10402     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
10403     if (stream->subtype == FOURCC_vivo) {
10404       if (new_stream)
10405         gst_qtdemux_stream_free (qtdemux, stream);
10406       return TRUE;
10407     } else {
10408       goto corrupt_file;
10409     }
10410   }
10411
10412   stream->stsd_entries_length = stsd_entry_count = QT_UINT32 (stsd_data + 12);
10413   stream->stsd_entries = g_new0 (QtDemuxStreamStsdEntry, stsd_entry_count);
10414   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
10415   GST_LOG_OBJECT (qtdemux, "stsd entry count:   %u", stsd_entry_count);
10416
10417   stsd_entry_data = stsd_data + 16;
10418   remaining_stsd_len = stsd_len - 16;
10419   for (stsd_index = 0; stsd_index < stsd_entry_count; stsd_index++) {
10420     QtDemuxStreamStsdEntry *entry = &stream->stsd_entries[stsd_index];
10421
10422     /* and that entry should fit within stsd */
10423     len = QT_UINT32 (stsd_entry_data);
10424     if (len > remaining_stsd_len)
10425       goto corrupt_file;
10426
10427     entry->fourcc = fourcc = QT_FOURCC (stsd_entry_data + 4);
10428     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
10429         GST_FOURCC_ARGS (entry->fourcc));
10430     GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
10431
10432     if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
10433       goto error_encrypted;
10434
10435     if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
10436       /* FIXME this looks wrong, there might be multiple children
10437        * with the same type */
10438       GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
10439       stream->protected = TRUE;
10440       if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
10441         GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
10442     }
10443
10444     if (stream->subtype == FOURCC_vide) {
10445       gboolean gray;
10446       gint depth, palette_size, palette_count;
10447       guint32 *palette_data = NULL;
10448
10449       entry->sampled = TRUE;
10450
10451       stream->display_width = w >> 16;
10452       stream->display_height = h >> 16;
10453
10454       offset = 16;
10455       if (len < 86)             /* TODO verify */
10456         goto corrupt_file;
10457
10458       entry->width = QT_UINT16 (stsd_entry_data + offset + 16);
10459       entry->height = QT_UINT16 (stsd_entry_data + offset + 18);
10460       entry->fps_n = 0;         /* this is filled in later */
10461       entry->fps_d = 0;         /* this is filled in later */
10462       entry->bits_per_sample = QT_UINT16 (stsd_entry_data + offset + 66);
10463       entry->color_table_id = QT_UINT16 (stsd_entry_data + offset + 68);
10464
10465       /* if color_table_id is 0, ctab atom must follow; however some files
10466        * produced by TMPEGEnc have color_table_id = 0 and no ctab atom, so
10467        * if color table is not present we'll correct the value */
10468       if (entry->color_table_id == 0 &&
10469           (len < 90
10470               || QT_FOURCC (stsd_entry_data + offset + 70) != FOURCC_ctab)) {
10471         entry->color_table_id = -1;
10472       }
10473
10474       GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
10475           entry->width, entry->height, entry->bits_per_sample,
10476           entry->color_table_id);
10477
10478       depth = entry->bits_per_sample;
10479
10480       /* more than 32 bits means grayscale */
10481       gray = (depth > 32);
10482       /* low 32 bits specify the depth  */
10483       depth &= 0x1F;
10484
10485       /* different number of palette entries is determined by depth. */
10486       palette_count = 0;
10487       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
10488         palette_count = (1 << depth);
10489       palette_size = palette_count * 4;
10490
10491       if (entry->color_table_id) {
10492         switch (palette_count) {
10493           case 0:
10494             break;
10495           case 2:
10496             palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
10497             break;
10498           case 4:
10499             palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
10500             break;
10501           case 16:
10502             if (gray)
10503               palette_data =
10504                   g_memdup (ff_qt_grayscale_palette_16, palette_size);
10505             else
10506               palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
10507             break;
10508           case 256:
10509             if (gray)
10510               palette_data =
10511                   g_memdup (ff_qt_grayscale_palette_256, palette_size);
10512             else
10513               palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
10514             break;
10515           default:
10516             GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10517                 (_("The video in this file might not play correctly.")),
10518                 ("unsupported palette depth %d", depth));
10519             break;
10520         }
10521       } else {
10522         gint i, j, start, end;
10523
10524         if (len < 94)
10525           goto corrupt_file;
10526
10527         /* read table */
10528         start = QT_UINT32 (stsd_entry_data + offset + 70);
10529         palette_count = QT_UINT16 (stsd_entry_data + offset + 74);
10530         end = QT_UINT16 (stsd_entry_data + offset + 76);
10531
10532         GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
10533             start, end, palette_count);
10534
10535         if (end > 255)
10536           end = 255;
10537         if (start > end)
10538           start = end;
10539
10540         if (len < 94 + (end - start) * 8)
10541           goto corrupt_file;
10542
10543         /* palette is always the same size */
10544         palette_data = g_malloc0 (256 * 4);
10545         palette_size = 256 * 4;
10546
10547         for (j = 0, i = start; i <= end; j++, i++) {
10548           guint32 a, r, g, b;
10549
10550           a = QT_UINT16 (stsd_entry_data + offset + 78 + (j * 8));
10551           r = QT_UINT16 (stsd_entry_data + offset + 80 + (j * 8));
10552           g = QT_UINT16 (stsd_entry_data + offset + 82 + (j * 8));
10553           b = QT_UINT16 (stsd_entry_data + offset + 84 + (j * 8));
10554
10555           palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
10556               (g & 0xff00) | (b >> 8);
10557         }
10558       }
10559
10560       if (entry->caps)
10561         gst_caps_unref (entry->caps);
10562
10563       entry->caps =
10564           qtdemux_video_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
10565           &codec);
10566       if (G_UNLIKELY (!entry->caps)) {
10567         g_free (palette_data);
10568         goto unknown_stream;
10569       }
10570
10571       if (codec) {
10572         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
10573             GST_TAG_VIDEO_CODEC, codec, NULL);
10574         g_free (codec);
10575         codec = NULL;
10576       }
10577
10578       if (palette_data) {
10579         GstStructure *s;
10580
10581         if (entry->rgb8_palette)
10582           gst_memory_unref (entry->rgb8_palette);
10583         entry->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
10584             palette_data, palette_size, 0, palette_size, palette_data, g_free);
10585
10586         s = gst_caps_get_structure (entry->caps, 0);
10587
10588         /* non-raw video has a palette_data property. raw video has the palette as
10589          * an extra plane that we append to the output buffers before we push
10590          * them*/
10591         if (!gst_structure_has_name (s, "video/x-raw")) {
10592           GstBuffer *palette;
10593
10594           palette = gst_buffer_new ();
10595           gst_buffer_append_memory (palette, entry->rgb8_palette);
10596           entry->rgb8_palette = NULL;
10597
10598           gst_caps_set_simple (entry->caps, "palette_data",
10599               GST_TYPE_BUFFER, palette, NULL);
10600           gst_buffer_unref (palette);
10601         }
10602       } else if (palette_count != 0) {
10603         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
10604             (NULL), ("Unsupported palette depth %d", depth));
10605       }
10606
10607       GST_LOG_OBJECT (qtdemux, "frame count:   %u",
10608           QT_UINT16 (stsd_entry_data + offset + 32));
10609
10610       esds = NULL;
10611       pasp = NULL;
10612       colr = NULL;
10613       fiel = NULL;
10614       /* pick 'the' stsd child */
10615       mp4v = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10616       if (!stream->protected) {
10617         if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != fourcc) {
10618           mp4v = NULL;
10619         }
10620       } else {
10621         if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
10622           mp4v = NULL;
10623         }
10624       }
10625
10626       if (mp4v) {
10627         esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
10628         pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
10629         colr = qtdemux_tree_get_child_by_type (mp4v, FOURCC_colr);
10630         fiel = qtdemux_tree_get_child_by_type (mp4v, FOURCC_fiel);
10631       }
10632
10633       if (pasp) {
10634         const guint8 *pasp_data = (const guint8 *) pasp->data;
10635         gint len = QT_UINT32 (pasp_data);
10636
10637         if (len == 16) {
10638           CUR_STREAM (stream)->par_w = QT_UINT32 (pasp_data + 8);
10639           CUR_STREAM (stream)->par_h = QT_UINT32 (pasp_data + 12);
10640         } else {
10641           CUR_STREAM (stream)->par_w = 0;
10642           CUR_STREAM (stream)->par_h = 0;
10643         }
10644       } else {
10645         CUR_STREAM (stream)->par_w = 0;
10646         CUR_STREAM (stream)->par_h = 0;
10647       }
10648
10649       if (fiel) {
10650         const guint8 *fiel_data = (const guint8 *) fiel->data;
10651         gint len = QT_UINT32 (fiel_data);
10652
10653         if (len == 10) {
10654           CUR_STREAM (stream)->interlace_mode = GST_READ_UINT8 (fiel_data + 8);
10655           CUR_STREAM (stream)->field_order = GST_READ_UINT8 (fiel_data + 9);
10656         }
10657       }
10658
10659       if (colr) {
10660         const guint8 *colr_data = (const guint8 *) colr->data;
10661         gint len = QT_UINT32 (colr_data);
10662
10663         if (len == 19 || len == 18) {
10664           guint32 color_type = GST_READ_UINT32_LE (colr_data + 8);
10665
10666           if (color_type == FOURCC_nclx || color_type == FOURCC_nclc) {
10667             guint16 primaries = GST_READ_UINT16_BE (colr_data + 12);
10668             guint16 transfer_function = GST_READ_UINT16_BE (colr_data + 14);
10669             guint16 matrix = GST_READ_UINT16_BE (colr_data + 16);
10670             gboolean full_range = len == 19 ? colr_data[17] >> 7 : FALSE;
10671
10672             switch (primaries) {
10673               case 1:
10674                 CUR_STREAM (stream)->colorimetry.primaries =
10675                     GST_VIDEO_COLOR_PRIMARIES_BT709;
10676                 break;
10677               case 5:
10678                 CUR_STREAM (stream)->colorimetry.primaries =
10679                     GST_VIDEO_COLOR_PRIMARIES_BT470BG;
10680                 break;
10681               case 6:
10682                 CUR_STREAM (stream)->colorimetry.primaries =
10683                     GST_VIDEO_COLOR_PRIMARIES_SMPTE170M;
10684                 break;
10685               case 9:
10686                 CUR_STREAM (stream)->colorimetry.primaries =
10687                     GST_VIDEO_COLOR_PRIMARIES_BT2020;
10688                 break;
10689               default:
10690                 break;
10691             }
10692
10693             switch (transfer_function) {
10694               case 1:
10695                 CUR_STREAM (stream)->colorimetry.transfer =
10696                     GST_VIDEO_TRANSFER_BT709;
10697                 break;
10698               case 7:
10699                 CUR_STREAM (stream)->colorimetry.transfer =
10700                     GST_VIDEO_TRANSFER_SMPTE240M;
10701                 break;
10702               default:
10703                 break;
10704             }
10705
10706             switch (matrix) {
10707               case 1:
10708                 CUR_STREAM (stream)->colorimetry.matrix =
10709                     GST_VIDEO_COLOR_MATRIX_BT709;
10710                 break;
10711               case 6:
10712                 CUR_STREAM (stream)->colorimetry.matrix =
10713                     GST_VIDEO_COLOR_MATRIX_BT601;
10714                 break;
10715               case 7:
10716                 CUR_STREAM (stream)->colorimetry.matrix =
10717                     GST_VIDEO_COLOR_MATRIX_SMPTE240M;
10718                 break;
10719               case 9:
10720                 CUR_STREAM (stream)->colorimetry.matrix =
10721                     GST_VIDEO_COLOR_MATRIX_BT2020;
10722                 break;
10723               default:
10724                 break;
10725             }
10726
10727             CUR_STREAM (stream)->colorimetry.range =
10728                 full_range ? GST_VIDEO_COLOR_RANGE_0_255 :
10729                 GST_VIDEO_COLOR_RANGE_16_235;
10730           } else {
10731             GST_DEBUG_OBJECT (qtdemux, "Unsupported color type");
10732           }
10733         } else {
10734           GST_WARNING_OBJECT (qtdemux, "Invalid colr atom size");
10735         }
10736       }
10737
10738       if (esds) {
10739         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
10740             stream->stream_tags);
10741       } else {
10742         switch (fourcc) {
10743           case FOURCC_H264:
10744           case FOURCC_avc1:
10745           case FOURCC_avc3:
10746           {
10747             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10748             const guint8 *avc_data = stsd_entry_data + 0x56;
10749
10750             /* find avcC */
10751             while (len >= 0x8) {
10752               gint size;
10753
10754               if (QT_UINT32 (avc_data) <= len)
10755                 size = QT_UINT32 (avc_data) - 0x8;
10756               else
10757                 size = len - 0x8;
10758
10759               if (size < 1)
10760                 /* No real data, so break out */
10761                 break;
10762
10763               switch (QT_FOURCC (avc_data + 0x4)) {
10764                 case FOURCC_avcC:
10765                 {
10766                   /* parse, if found */
10767                   GstBuffer *buf;
10768
10769                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10770
10771                   /* First 4 bytes are the length of the atom, the next 4 bytes
10772                    * are the fourcc, the next 1 byte is the version, and the
10773                    * subsequent bytes are profile_tier_level structure like data. */
10774                   gst_codec_utils_h264_caps_set_level_and_profile (entry->caps,
10775                       avc_data + 8 + 1, size - 1);
10776                   buf = gst_buffer_new_and_alloc (size);
10777                   gst_buffer_fill (buf, 0, avc_data + 0x8, size);
10778                   gst_caps_set_simple (entry->caps,
10779                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
10780                   gst_buffer_unref (buf);
10781
10782                   break;
10783                 }
10784                 case FOURCC_strf:
10785                 {
10786                   GstBuffer *buf;
10787
10788                   GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
10789
10790                   /* First 4 bytes are the length of the atom, the next 4 bytes
10791                    * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
10792                    * next 1 byte is the version, and the
10793                    * subsequent bytes are sequence parameter set like data. */
10794
10795                   size -= 40;   /* we'll be skipping BITMAPINFOHEADER */
10796                   if (size > 1) {
10797                     gst_codec_utils_h264_caps_set_level_and_profile
10798                         (entry->caps, avc_data + 8 + 40 + 1, size - 1);
10799
10800                     buf = gst_buffer_new_and_alloc (size);
10801                     gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
10802                     gst_caps_set_simple (entry->caps,
10803                         "codec_data", GST_TYPE_BUFFER, buf, NULL);
10804                     gst_buffer_unref (buf);
10805                   }
10806                   break;
10807                 }
10808                 case FOURCC_btrt:
10809                 {
10810                   guint avg_bitrate, max_bitrate;
10811
10812                   /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
10813                   if (size < 12)
10814                     break;
10815
10816                   max_bitrate = QT_UINT32 (avc_data + 0xc);
10817                   avg_bitrate = QT_UINT32 (avc_data + 0x10);
10818
10819                   if (!max_bitrate && !avg_bitrate)
10820                     break;
10821
10822                   /* Some muxers seem to swap the average and maximum bitrates
10823                    * (I'm looking at you, YouTube), so we swap for sanity. */
10824                   if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
10825                     guint temp = avg_bitrate;
10826
10827                     avg_bitrate = max_bitrate;
10828                     max_bitrate = temp;
10829                   }
10830
10831                   if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10832                     gst_tag_list_add (stream->stream_tags,
10833                         GST_TAG_MERGE_REPLACE, GST_TAG_MAXIMUM_BITRATE,
10834                         max_bitrate, NULL);
10835                   }
10836                   if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10837                     gst_tag_list_add (stream->stream_tags,
10838                         GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE, avg_bitrate,
10839                         NULL);
10840                   }
10841
10842                   break;
10843                 }
10844
10845                 default:
10846                   break;
10847               }
10848
10849               len -= size + 8;
10850               avc_data += size + 8;
10851             }
10852
10853             break;
10854           }
10855           case FOURCC_H265:
10856           case FOURCC_hvc1:
10857           case FOURCC_hev1:
10858           {
10859             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
10860             const guint8 *hevc_data = stsd_entry_data + 0x56;
10861
10862             /* find hevc */
10863             while (len >= 0x8) {
10864               gint size;
10865
10866               if (QT_UINT32 (hevc_data) <= len)
10867                 size = QT_UINT32 (hevc_data) - 0x8;
10868               else
10869                 size = len - 0x8;
10870
10871               if (size < 1)
10872                 /* No real data, so break out */
10873                 break;
10874
10875               switch (QT_FOURCC (hevc_data + 0x4)) {
10876                 case FOURCC_hvcC:
10877                 {
10878                   /* parse, if found */
10879                   GstBuffer *buf;
10880
10881                   GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
10882
10883                   /* First 4 bytes are the length of the atom, the next 4 bytes
10884                    * are the fourcc, the next 1 byte is the version, and the
10885                    * subsequent bytes are sequence parameter set like data. */
10886                   gst_codec_utils_h265_caps_set_level_tier_and_profile
10887                       (entry->caps, hevc_data + 8 + 1, size - 1);
10888
10889                   buf = gst_buffer_new_and_alloc (size);
10890                   gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
10891                   gst_caps_set_simple (entry->caps,
10892                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
10893                   gst_buffer_unref (buf);
10894                   break;
10895                 }
10896                 default:
10897                   break;
10898               }
10899               len -= size + 8;
10900               hevc_data += size + 8;
10901             }
10902             break;
10903           }
10904           case FOURCC_mp4v:
10905           case FOURCC_MP4V:
10906           case FOURCC_fmp4:
10907           case FOURCC_FMP4:
10908           case FOURCC_xvid:
10909           case FOURCC_XVID:
10910           {
10911             GNode *glbl;
10912
10913             GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
10914                 GST_FOURCC_ARGS (fourcc));
10915
10916             /* codec data might be in glbl extension atom */
10917             glbl = mp4v ?
10918                 qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
10919             if (glbl) {
10920               guint8 *data;
10921               GstBuffer *buf;
10922               gint len;
10923
10924               GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
10925               data = glbl->data;
10926               len = QT_UINT32 (data);
10927               if (len > 0x8) {
10928                 len -= 0x8;
10929                 buf = gst_buffer_new_and_alloc (len);
10930                 gst_buffer_fill (buf, 0, data + 8, len);
10931                 gst_caps_set_simple (entry->caps,
10932                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
10933                 gst_buffer_unref (buf);
10934               }
10935             }
10936             break;
10937           }
10938           case FOURCC_mjp2:
10939           {
10940             /* see annex I of the jpeg2000 spec */
10941             GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
10942             const guint8 *data;
10943             const gchar *colorspace = NULL;
10944             gint ncomp = 0;
10945             guint32 ncomp_map = 0;
10946             gint32 *comp_map = NULL;
10947             guint32 nchan_def = 0;
10948             gint32 *chan_def = NULL;
10949
10950             GST_DEBUG_OBJECT (qtdemux, "found mjp2");
10951             /* some required atoms */
10952             mjp2 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
10953             if (!mjp2)
10954               break;
10955             jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
10956             if (!jp2h)
10957               break;
10958
10959             /* number of components; redundant with info in codestream, but useful
10960                to a muxer */
10961             ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
10962             if (!ihdr || QT_UINT32 (ihdr->data) != 22)
10963               break;
10964             ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
10965
10966             colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
10967             if (!colr)
10968               break;
10969             GST_DEBUG_OBJECT (qtdemux, "found colr");
10970             /* extract colour space info */
10971             if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
10972               switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
10973                 case 16:
10974                   colorspace = "sRGB";
10975                   break;
10976                 case 17:
10977                   colorspace = "GRAY";
10978                   break;
10979                 case 18:
10980                   colorspace = "sYUV";
10981                   break;
10982                 default:
10983                   colorspace = NULL;
10984                   break;
10985               }
10986             }
10987             if (!colorspace)
10988               /* colr is required, and only values 16, 17, and 18 are specified,
10989                  so error if we have no colorspace */
10990               break;
10991
10992             /* extract component mapping */
10993             cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
10994             if (cmap) {
10995               guint32 cmap_len = 0;
10996               int i;
10997               cmap_len = QT_UINT32 (cmap->data);
10998               if (cmap_len >= 8) {
10999                 /* normal box, subtract off header */
11000                 cmap_len -= 8;
11001                 /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
11002                 if (cmap_len % 4 == 0) {
11003                   ncomp_map = (cmap_len / 4);
11004                   comp_map = g_new0 (gint32, ncomp_map);
11005                   for (i = 0; i < ncomp_map; i++) {
11006                     guint16 cmp;
11007                     guint8 mtyp, pcol;
11008                     cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
11009                     mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
11010                     pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
11011                     comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
11012                   }
11013                 }
11014               }
11015             }
11016             /* extract channel definitions */
11017             cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
11018             if (cdef) {
11019               guint32 cdef_len = 0;
11020               int i;
11021               cdef_len = QT_UINT32 (cdef->data);
11022               if (cdef_len >= 10) {
11023                 /* normal box, subtract off header and len */
11024                 cdef_len -= 10;
11025                 /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
11026                 if (cdef_len % 6 == 0) {
11027                   nchan_def = (cdef_len / 6);
11028                   chan_def = g_new0 (gint32, nchan_def);
11029                   for (i = 0; i < nchan_def; i++)
11030                     chan_def[i] = -1;
11031                   for (i = 0; i < nchan_def; i++) {
11032                     guint16 cn, typ, asoc;
11033                     cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
11034                     typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
11035                     asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
11036                     if (cn < nchan_def) {
11037                       switch (typ) {
11038                         case 0:
11039                           chan_def[cn] = asoc;
11040                           break;
11041                         case 1:
11042                           chan_def[cn] = 0;     /* alpha */
11043                           break;
11044                         default:
11045                           chan_def[cn] = -typ;
11046                       }
11047                     }
11048                   }
11049                 }
11050               }
11051             }
11052
11053             gst_caps_set_simple (entry->caps,
11054                 "num-components", G_TYPE_INT, ncomp, NULL);
11055             gst_caps_set_simple (entry->caps,
11056                 "colorspace", G_TYPE_STRING, colorspace, NULL);
11057
11058             if (comp_map) {
11059               GValue arr = { 0, };
11060               GValue elt = { 0, };
11061               int i;
11062               g_value_init (&arr, GST_TYPE_ARRAY);
11063               g_value_init (&elt, G_TYPE_INT);
11064               for (i = 0; i < ncomp_map; i++) {
11065                 g_value_set_int (&elt, comp_map[i]);
11066                 gst_value_array_append_value (&arr, &elt);
11067               }
11068               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11069                   "component-map", &arr);
11070               g_value_unset (&elt);
11071               g_value_unset (&arr);
11072               g_free (comp_map);
11073             }
11074
11075             if (chan_def) {
11076               GValue arr = { 0, };
11077               GValue elt = { 0, };
11078               int i;
11079               g_value_init (&arr, GST_TYPE_ARRAY);
11080               g_value_init (&elt, G_TYPE_INT);
11081               for (i = 0; i < nchan_def; i++) {
11082                 g_value_set_int (&elt, chan_def[i]);
11083                 gst_value_array_append_value (&arr, &elt);
11084               }
11085               gst_structure_set_value (gst_caps_get_structure (entry->caps, 0),
11086                   "channel-definitions", &arr);
11087               g_value_unset (&elt);
11088               g_value_unset (&arr);
11089               g_free (chan_def);
11090             }
11091
11092             /* some optional atoms */
11093             field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
11094             prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
11095
11096             /* indicate possible fields in caps */
11097             if (field) {
11098               data = (guint8 *) field->data + 8;
11099               if (*data != 1)
11100                 gst_caps_set_simple (entry->caps, "fields", G_TYPE_INT,
11101                     (gint) * data, NULL);
11102             }
11103             /* add codec_data if provided */
11104             if (prefix) {
11105               GstBuffer *buf;
11106               gint len;
11107
11108               GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
11109               data = prefix->data;
11110               len = QT_UINT32 (data);
11111               if (len > 0x8) {
11112                 len -= 0x8;
11113                 buf = gst_buffer_new_and_alloc (len);
11114                 gst_buffer_fill (buf, 0, data + 8, len);
11115                 gst_caps_set_simple (entry->caps,
11116                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11117                 gst_buffer_unref (buf);
11118               }
11119             }
11120             break;
11121           }
11122           case FOURCC_SVQ3:
11123           case FOURCC_VP31:
11124           {
11125             GstBuffer *buf;
11126             GstBuffer *seqh = NULL;
11127             const guint8 *gamma_data = NULL;
11128             gint len = QT_UINT32 (stsd_data);   /* FIXME review - why put the whole stsd in codec data? */
11129
11130             qtdemux_parse_svq3_stsd_data (qtdemux, stsd_entry_data, &gamma_data,
11131                 &seqh);
11132             if (gamma_data) {
11133               gst_caps_set_simple (entry->caps, "applied-gamma", G_TYPE_DOUBLE,
11134                   QT_FP32 (gamma_data), NULL);
11135             }
11136             if (seqh) {
11137               /* sorry for the bad name, but we don't know what this is, other
11138                * than its own fourcc */
11139               gst_caps_set_simple (entry->caps, "seqh", GST_TYPE_BUFFER, seqh,
11140                   NULL);
11141               gst_buffer_unref (seqh);
11142             }
11143
11144             GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
11145             buf = gst_buffer_new_and_alloc (len);
11146             gst_buffer_fill (buf, 0, stsd_data, len);
11147             gst_caps_set_simple (entry->caps,
11148                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11149             gst_buffer_unref (buf);
11150             break;
11151           }
11152           case FOURCC_jpeg:
11153           {
11154             /* https://developer.apple.com/standards/qtff-2001.pdf,
11155              * page 92, "Video Sample Description", under table 3.1 */
11156             GstByteReader br;
11157
11158             const gint compressor_offset =
11159                 16 + 4 + 4 * 3 + 2 * 2 + 2 * 4 + 4 + 2;
11160             const gint min_size = compressor_offset + 32 + 2 + 2;
11161             GNode *jpeg;
11162             guint32 len;
11163             guint16 color_table_id = 0;
11164             gboolean ok;
11165
11166             GST_DEBUG_OBJECT (qtdemux, "found jpeg");
11167
11168             /* recover information on interlaced/progressive */
11169             jpeg = qtdemux_tree_get_child_by_type (stsd, FOURCC_jpeg);
11170             if (!jpeg)
11171               break;
11172
11173             len = QT_UINT32 (jpeg->data);
11174             GST_DEBUG_OBJECT (qtdemux, "Found jpeg: len %u, need %d", len,
11175                 min_size);
11176             if (len >= min_size) {
11177               gst_byte_reader_init (&br, jpeg->data, len);
11178
11179               gst_byte_reader_skip (&br, compressor_offset + 32 + 2);
11180               gst_byte_reader_get_uint16_le (&br, &color_table_id);
11181               if (color_table_id != 0) {
11182                 /* the spec says there can be concatenated chunks in the data, and we want
11183                  * to find one called field. Walk through them. */
11184                 gint offset = min_size;
11185                 while (offset + 8 < len) {
11186                   guint32 size = 0, tag;
11187                   ok = gst_byte_reader_get_uint32_le (&br, &size);
11188                   ok &= gst_byte_reader_get_uint32_le (&br, &tag);
11189                   if (!ok || size < 8) {
11190                     GST_WARNING_OBJECT (qtdemux,
11191                         "Failed to walk optional chunk list");
11192                     break;
11193                   }
11194                   GST_DEBUG_OBJECT (qtdemux,
11195                       "Found optional %4.4s chunk, size %u",
11196                       (const char *) &tag, size);
11197                   if (tag == FOURCC_fiel) {
11198                     guint8 n_fields = 0, ordering = 0;
11199                     gst_byte_reader_get_uint8 (&br, &n_fields);
11200                     gst_byte_reader_get_uint8 (&br, &ordering);
11201                     if (n_fields == 1 || n_fields == 2) {
11202                       GST_DEBUG_OBJECT (qtdemux,
11203                           "Found fiel tag with %u fields, ordering %u",
11204                           n_fields, ordering);
11205                       if (n_fields == 2)
11206                         gst_caps_set_simple (CUR_STREAM (stream)->caps,
11207                             "interlace-mode", G_TYPE_STRING, "interleaved",
11208                             NULL);
11209                     } else {
11210                       GST_WARNING_OBJECT (qtdemux,
11211                           "Found fiel tag with invalid fields (%u)", n_fields);
11212                     }
11213                   }
11214                   offset += size;
11215                 }
11216               } else {
11217                 GST_DEBUG_OBJECT (qtdemux,
11218                     "Color table ID is 0, not trying to get interlacedness");
11219               }
11220             } else {
11221               GST_WARNING_OBJECT (qtdemux,
11222                   "Length of jpeg chunk is too small, not trying to get interlacedness");
11223             }
11224
11225             break;
11226           }
11227           case FOURCC_rle_:
11228           case FOURCC_WRLE:
11229           {
11230             gst_caps_set_simple (entry->caps,
11231                 "depth", G_TYPE_INT, QT_UINT16 (stsd_entry_data + offset + 66),
11232                 NULL);
11233             break;
11234           }
11235           case FOURCC_XiTh:
11236           {
11237             GNode *xith, *xdxt;
11238
11239             GST_DEBUG_OBJECT (qtdemux, "found XiTh");
11240             xith = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11241             if (!xith)
11242               break;
11243
11244             xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
11245             if (!xdxt)
11246               break;
11247
11248             GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
11249             /* collect the headers and store them in a stream list so that we can
11250              * send them out first */
11251             qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
11252             break;
11253           }
11254           case FOURCC_ovc1:
11255           {
11256             GNode *ovc1;
11257             guint8 *ovc1_data;
11258             guint ovc1_len;
11259             GstBuffer *buf;
11260
11261             GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
11262             ovc1 = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11263             if (!ovc1)
11264               break;
11265             ovc1_data = ovc1->data;
11266             ovc1_len = QT_UINT32 (ovc1_data);
11267             if (ovc1_len <= 198) {
11268               GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
11269               break;
11270             }
11271             buf = gst_buffer_new_and_alloc (ovc1_len - 198);
11272             gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
11273             gst_caps_set_simple (entry->caps,
11274                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
11275             gst_buffer_unref (buf);
11276             break;
11277           }
11278           case FOURCC_vc_1:
11279           {
11280             gint len = QT_UINT32 (stsd_entry_data) - 0x56;
11281             const guint8 *vc1_data = stsd_entry_data + 0x56;
11282
11283             /* find dvc1 */
11284             while (len >= 8) {
11285               gint size;
11286
11287               if (QT_UINT32 (vc1_data) <= len)
11288                 size = QT_UINT32 (vc1_data) - 8;
11289               else
11290                 size = len - 8;
11291
11292               if (size < 1)
11293                 /* No real data, so break out */
11294                 break;
11295
11296               switch (QT_FOURCC (vc1_data + 0x4)) {
11297                 case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
11298                 {
11299                   GstBuffer *buf;
11300
11301                   GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
11302                   buf = gst_buffer_new_and_alloc (size);
11303                   gst_buffer_fill (buf, 0, vc1_data + 8, size);
11304                   gst_caps_set_simple (entry->caps,
11305                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11306                   gst_buffer_unref (buf);
11307                   break;
11308                 }
11309                 default:
11310                   break;
11311               }
11312               len -= size + 8;
11313               vc1_data += size + 8;
11314             }
11315             break;
11316           }
11317           default:
11318             break;
11319         }
11320       }
11321
11322       GST_INFO_OBJECT (qtdemux,
11323           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
11324           GST_FOURCC_ARGS (fourcc), entry->caps);
11325
11326     } else if (stream->subtype == FOURCC_soun) {
11327       int version, samplesize;
11328       guint16 compression_id;
11329       gboolean amrwb = FALSE;
11330
11331       offset = 16;
11332       /* sample description entry (16) + sound sample description v0 (20) */
11333       if (len < 36)
11334         goto corrupt_file;
11335
11336       version = QT_UINT32 (stsd_entry_data + offset);
11337       entry->n_channels = QT_UINT16 (stsd_entry_data + offset + 8);
11338       samplesize = QT_UINT16 (stsd_entry_data + offset + 10);
11339       compression_id = QT_UINT16 (stsd_entry_data + offset + 12);
11340       entry->rate = QT_FP32 (stsd_entry_data + offset + 16);
11341
11342       GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
11343       GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
11344           QT_UINT32 (stsd_entry_data + offset + 4));
11345       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", entry->n_channels);
11346       GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
11347       GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
11348       GST_LOG_OBJECT (qtdemux, "packet size:      %d",
11349           QT_UINT16 (stsd_entry_data + offset + 14));
11350       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", entry->rate);
11351
11352       if (compression_id == 0xfffe)
11353         entry->sampled = TRUE;
11354
11355       /* first assume uncompressed audio */
11356       entry->bytes_per_sample = samplesize / 8;
11357       entry->samples_per_frame = entry->n_channels;
11358       entry->bytes_per_frame = entry->n_channels * entry->bytes_per_sample;
11359       entry->samples_per_packet = entry->samples_per_frame;
11360       entry->bytes_per_packet = entry->bytes_per_sample;
11361
11362       offset = 36;
11363       switch (fourcc) {
11364           /* Yes, these have to be hard-coded */
11365         case FOURCC_MAC6:
11366         {
11367           entry->samples_per_packet = 6;
11368           entry->bytes_per_packet = 1;
11369           entry->bytes_per_frame = 1 * entry->n_channels;
11370           entry->bytes_per_sample = 1;
11371           entry->samples_per_frame = 6 * entry->n_channels;
11372           break;
11373         }
11374         case FOURCC_MAC3:
11375         {
11376           entry->samples_per_packet = 3;
11377           entry->bytes_per_packet = 1;
11378           entry->bytes_per_frame = 1 * entry->n_channels;
11379           entry->bytes_per_sample = 1;
11380           entry->samples_per_frame = 3 * entry->n_channels;
11381           break;
11382         }
11383         case FOURCC_ima4:
11384         {
11385           entry->samples_per_packet = 64;
11386           entry->bytes_per_packet = 34;
11387           entry->bytes_per_frame = 34 * entry->n_channels;
11388           entry->bytes_per_sample = 2;
11389           entry->samples_per_frame = 64 * entry->n_channels;
11390           break;
11391         }
11392         case FOURCC_ulaw:
11393         case FOURCC_alaw:
11394         {
11395           entry->samples_per_packet = 1;
11396           entry->bytes_per_packet = 1;
11397           entry->bytes_per_frame = 1 * entry->n_channels;
11398           entry->bytes_per_sample = 1;
11399           entry->samples_per_frame = 1 * entry->n_channels;
11400           break;
11401         }
11402         case FOURCC_agsm:
11403         {
11404           entry->samples_per_packet = 160;
11405           entry->bytes_per_packet = 33;
11406           entry->bytes_per_frame = 33 * entry->n_channels;
11407           entry->bytes_per_sample = 2;
11408           entry->samples_per_frame = 160 * entry->n_channels;
11409           break;
11410         }
11411         default:
11412           break;
11413       }
11414
11415       if (version == 0x00010000) {
11416         /* sample description entry (16) + sound sample description v1 (20+16) */
11417         if (len < 52)
11418           goto corrupt_file;
11419
11420         switch (fourcc) {
11421           case FOURCC_twos:
11422           case FOURCC_sowt:
11423           case FOURCC_raw_:
11424             break;
11425           default:
11426           {
11427             /* only parse extra decoding config for non-pcm audio */
11428             entry->samples_per_packet = QT_UINT32 (stsd_entry_data + offset);
11429             entry->bytes_per_packet = QT_UINT32 (stsd_entry_data + offset + 4);
11430             entry->bytes_per_frame = QT_UINT32 (stsd_entry_data + offset + 8);
11431             entry->bytes_per_sample = QT_UINT32 (stsd_entry_data + offset + 12);
11432
11433             GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
11434                 entry->samples_per_packet);
11435             GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
11436                 entry->bytes_per_packet);
11437             GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
11438                 entry->bytes_per_frame);
11439             GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
11440                 entry->bytes_per_sample);
11441
11442             if (!entry->sampled && entry->bytes_per_packet) {
11443               entry->samples_per_frame = (entry->bytes_per_frame /
11444                   entry->bytes_per_packet) * entry->samples_per_packet;
11445               GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
11446                   entry->samples_per_frame);
11447             }
11448             break;
11449           }
11450         }
11451       } else if (version == 0x00020000) {
11452         union
11453         {
11454           gdouble fp;
11455           guint64 val;
11456         } qtfp;
11457
11458         /* sample description entry (16) + sound sample description v2 (56) */
11459         if (len < 72)
11460           goto corrupt_file;
11461
11462         qtfp.val = QT_UINT64 (stsd_entry_data + offset + 4);
11463         entry->rate = qtfp.fp;
11464         entry->n_channels = QT_UINT32 (stsd_entry_data + offset + 12);
11465
11466         GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
11467         GST_LOG_OBJECT (qtdemux, "sample rate:        %g", entry->rate);
11468         GST_LOG_OBJECT (qtdemux, "n_channels:         %d", entry->n_channels);
11469         GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
11470             QT_UINT32 (stsd_entry_data + offset + 20));
11471         GST_LOG_OBJECT (qtdemux, "format flags:       %X",
11472             QT_UINT32 (stsd_entry_data + offset + 24));
11473         GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
11474             QT_UINT32 (stsd_entry_data + offset + 28));
11475         GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
11476             QT_UINT32 (stsd_entry_data + offset + 32));
11477       } else if (version != 0x00000) {
11478         GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x",
11479             version);
11480       }
11481
11482       if (entry->caps)
11483         gst_caps_unref (entry->caps);
11484
11485       entry->caps = qtdemux_audio_caps (qtdemux, stream, entry, fourcc,
11486           stsd_entry_data + 32, len - 16, &codec);
11487
11488       switch (fourcc) {
11489         case FOURCC_in24:
11490         {
11491           GNode *enda;
11492           GNode *in24;
11493
11494           in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
11495
11496           enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
11497           if (!enda) {
11498             wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
11499             if (wave)
11500               enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
11501           }
11502           if (enda) {
11503             int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
11504             gst_caps_set_simple (entry->caps,
11505                 "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE",
11506                 NULL);
11507           }
11508           break;
11509         }
11510         case FOURCC_owma:
11511         {
11512           const guint8 *owma_data;
11513           const gchar *codec_name = NULL;
11514           guint owma_len;
11515           GstBuffer *buf;
11516           gint version = 1;
11517           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11518           /* FIXME this should also be gst_riff_strf_auds,
11519            * but the latter one is actually missing bits-per-sample :( */
11520           typedef struct
11521           {
11522             gint16 wFormatTag;
11523             gint16 nChannels;
11524             gint32 nSamplesPerSec;
11525             gint32 nAvgBytesPerSec;
11526             gint16 nBlockAlign;
11527             gint16 wBitsPerSample;
11528             gint16 cbSize;
11529           } WAVEFORMATEX;
11530           WAVEFORMATEX *wfex;
11531
11532           GST_DEBUG_OBJECT (qtdemux, "parse owma");
11533           owma_data = stsd_entry_data;
11534           owma_len = QT_UINT32 (owma_data);
11535           if (owma_len <= 54) {
11536             GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
11537             break;
11538           }
11539           wfex = (WAVEFORMATEX *) (owma_data + 36);
11540           buf = gst_buffer_new_and_alloc (owma_len - 54);
11541           gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
11542           if (wfex->wFormatTag == 0x0161) {
11543             codec_name = "Windows Media Audio";
11544             version = 2;
11545           } else if (wfex->wFormatTag == 0x0162) {
11546             codec_name = "Windows Media Audio 9 Pro";
11547             version = 3;
11548           } else if (wfex->wFormatTag == 0x0163) {
11549             codec_name = "Windows Media Audio 9 Lossless";
11550             /* is that correct? gstffmpegcodecmap.c is missing it, but
11551              * fluendo codec seems to support it */
11552             version = 4;
11553           }
11554
11555           gst_caps_set_simple (entry->caps,
11556               "codec_data", GST_TYPE_BUFFER, buf,
11557               "wmaversion", G_TYPE_INT, version,
11558               "block_align", G_TYPE_INT,
11559               GST_READ_UINT16_LE (&wfex->nBlockAlign), "bitrate", G_TYPE_INT,
11560               GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec), "width", G_TYPE_INT,
11561               GST_READ_UINT16_LE (&wfex->wBitsPerSample), "depth", G_TYPE_INT,
11562               GST_READ_UINT16_LE (&wfex->wBitsPerSample), NULL);
11563           gst_buffer_unref (buf);
11564
11565           if (codec_name) {
11566             g_free (codec);
11567             codec = g_strdup (codec_name);
11568           }
11569           break;
11570         }
11571         case FOURCC_wma_:
11572         {
11573           gint len = QT_UINT32 (stsd_entry_data) - offset;
11574           const guint8 *wfex_data = stsd_entry_data + offset;
11575           const gchar *codec_name = NULL;
11576           gint version = 1;
11577           /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
11578           /* FIXME this should also be gst_riff_strf_auds,
11579            * but the latter one is actually missing bits-per-sample :( */
11580           typedef struct
11581           {
11582             gint16 wFormatTag;
11583             gint16 nChannels;
11584             gint32 nSamplesPerSec;
11585             gint32 nAvgBytesPerSec;
11586             gint16 nBlockAlign;
11587             gint16 wBitsPerSample;
11588             gint16 cbSize;
11589           } WAVEFORMATEX;
11590           WAVEFORMATEX wfex;
11591
11592           /* FIXME: unify with similar wavformatex parsing code above */
11593           GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
11594
11595           /* find wfex */
11596           while (len >= 8) {
11597             gint size;
11598
11599             if (QT_UINT32 (wfex_data) <= len)
11600               size = QT_UINT32 (wfex_data) - 8;
11601             else
11602               size = len - 8;
11603
11604             if (size < 1)
11605               /* No real data, so break out */
11606               break;
11607
11608             switch (QT_FOURCC (wfex_data + 4)) {
11609               case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
11610               {
11611                 GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
11612
11613                 if (size < 8 + 18)
11614                   break;
11615
11616                 wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
11617                 wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
11618                 wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
11619                 wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
11620                 wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
11621                 wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
11622                 wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
11623
11624                 GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
11625                 GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
11626                     "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
11627                     "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
11628                     wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
11629                     wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
11630
11631                 if (wfex.wFormatTag == 0x0161) {
11632                   codec_name = "Windows Media Audio";
11633                   version = 2;
11634                 } else if (wfex.wFormatTag == 0x0162) {
11635                   codec_name = "Windows Media Audio 9 Pro";
11636                   version = 3;
11637                 } else if (wfex.wFormatTag == 0x0163) {
11638                   codec_name = "Windows Media Audio 9 Lossless";
11639                   /* is that correct? gstffmpegcodecmap.c is missing it, but
11640                    * fluendo codec seems to support it */
11641                   version = 4;
11642                 }
11643
11644                 gst_caps_set_simple (entry->caps,
11645                     "wmaversion", G_TYPE_INT, version,
11646                     "block_align", G_TYPE_INT, wfex.nBlockAlign,
11647                     "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
11648                     "width", G_TYPE_INT, wfex.wBitsPerSample,
11649                     "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
11650
11651                 if (size > wfex.cbSize) {
11652                   GstBuffer *buf;
11653
11654                   buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
11655                   gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
11656                       size - wfex.cbSize);
11657                   gst_caps_set_simple (entry->caps,
11658                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
11659                   gst_buffer_unref (buf);
11660                 } else {
11661                   GST_WARNING_OBJECT (qtdemux, "no codec data");
11662                 }
11663
11664                 if (codec_name) {
11665                   g_free (codec);
11666                   codec = g_strdup (codec_name);
11667                 }
11668                 break;
11669               }
11670               default:
11671                 break;
11672             }
11673             len -= size + 8;
11674             wfex_data += size + 8;
11675           }
11676           break;
11677         }
11678         case FOURCC_opus:
11679         {
11680           const guint8 *opus_data;
11681           guint8 *channel_mapping = NULL;
11682           guint32 rate;
11683           guint8 channels;
11684           guint8 channel_mapping_family;
11685           guint8 stream_count;
11686           guint8 coupled_count;
11687           guint8 i;
11688
11689           opus_data = stsd_entry_data;
11690
11691           channels = GST_READ_UINT8 (opus_data + 45);
11692           rate = GST_READ_UINT32_LE (opus_data + 48);
11693           channel_mapping_family = GST_READ_UINT8 (opus_data + 54);
11694           stream_count = GST_READ_UINT8 (opus_data + 55);
11695           coupled_count = GST_READ_UINT8 (opus_data + 56);
11696
11697           if (channels > 0) {
11698             channel_mapping = g_malloc (channels * sizeof (guint8));
11699             for (i = 0; i < channels; i++)
11700               channel_mapping[i] = GST_READ_UINT8 (opus_data + i + 57);
11701           }
11702
11703           entry->caps = gst_codec_utils_opus_create_caps (rate, channels,
11704               channel_mapping_family, stream_count, coupled_count,
11705               channel_mapping);
11706           break;
11707         }
11708         default:
11709           break;
11710       }
11711
11712       if (codec) {
11713         GstStructure *s;
11714         gint bitrate = 0;
11715
11716         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11717             GST_TAG_AUDIO_CODEC, codec, NULL);
11718         g_free (codec);
11719         codec = NULL;
11720
11721         /* some bitrate info may have ended up in caps */
11722         s = gst_caps_get_structure (entry->caps, 0);
11723         gst_structure_get_int (s, "bitrate", &bitrate);
11724         if (bitrate > 0)
11725           gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
11726               GST_TAG_BITRATE, bitrate, NULL);
11727       }
11728
11729       mp4a = qtdemux_tree_get_child_by_index (stsd, stsd_index);
11730       if (!stream->protected) {
11731       } else {
11732         if (QTDEMUX_TREE_NODE_FOURCC (mp4v) != FOURCC_encv) {
11733           mp4v = NULL;
11734         }
11735       }
11736       if (stream->protected && fourcc == FOURCC_mp4a) {
11737         if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_enca) {
11738           mp4a = NULL;
11739         }
11740       } else {
11741         if (QTDEMUX_TREE_NODE_FOURCC (mp4a) != FOURCC_mp4a) {
11742           mp4a = NULL;
11743         }
11744       }
11745
11746       wave = NULL;
11747       esds = NULL;
11748       if (mp4a) {
11749         wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
11750         if (wave)
11751           esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
11752         if (!esds)
11753           esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
11754       }
11755
11756
11757       /* If the fourcc's bottom 16 bits gives 'sm', then the top
11758          16 bits is a byte-swapped wave-style codec identifier,
11759          and we can find a WAVE header internally to a 'wave' atom here.
11760          This can more clearly be thought of as 'ms' as the top 16 bits, and a
11761          codec id as the bottom 16 bits - but byte-swapped to store in QT (which
11762          is big-endian).
11763        */
11764       if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
11765         if (len < offset + 20) {
11766           GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
11767         } else {
11768           guint32 datalen = QT_UINT32 (stsd_entry_data + offset + 16);
11769           const guint8 *data = stsd_entry_data + offset + 16;
11770           GNode *wavenode;
11771           GNode *waveheadernode;
11772
11773           wavenode = g_node_new ((guint8 *) data);
11774           if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
11775             const guint8 *waveheader;
11776             guint32 headerlen;
11777
11778             waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
11779             if (waveheadernode) {
11780               waveheader = (const guint8 *) waveheadernode->data;
11781               headerlen = QT_UINT32 (waveheader);
11782
11783               if (headerlen > 8) {
11784                 gst_riff_strf_auds *header = NULL;
11785                 GstBuffer *headerbuf;
11786                 GstBuffer *extra;
11787
11788                 waveheader += 8;
11789                 headerlen -= 8;
11790
11791                 headerbuf = gst_buffer_new_and_alloc (headerlen);
11792                 gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
11793
11794                 if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
11795                         headerbuf, &header, &extra)) {
11796                   gst_caps_unref (entry->caps);
11797                   /* FIXME: Need to do something with the channel reorder map */
11798                   entry->caps =
11799                       gst_riff_create_audio_caps (header->format, NULL, header,
11800                       extra, NULL, NULL, NULL);
11801
11802                   if (extra)
11803                     gst_buffer_unref (extra);
11804                   g_free (header);
11805                 }
11806               }
11807             } else
11808               GST_DEBUG ("Didn't find waveheadernode for this codec");
11809           }
11810           g_node_destroy (wavenode);
11811         }
11812       } else if (esds) {
11813         gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
11814             stream->stream_tags);
11815       } else {
11816         switch (fourcc) {
11817 #if 0
11818             /* FIXME: what is in the chunk? */
11819           case FOURCC_QDMC:
11820           {
11821             gint len = QT_UINT32 (stsd_data);
11822
11823             /* seems to be always = 116 = 0x74 */
11824             break;
11825           }
11826 #endif
11827           case FOURCC_QDM2:
11828           {
11829             gint len = QT_UINT32 (stsd_entry_data);
11830
11831             if (len > 0x3C) {
11832               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x3C);
11833
11834               gst_buffer_fill (buf, 0, stsd_entry_data + 0x3C, len - 0x3C);
11835               gst_caps_set_simple (entry->caps,
11836                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
11837               gst_buffer_unref (buf);
11838             }
11839             gst_caps_set_simple (entry->caps,
11840                 "samplesize", G_TYPE_INT, samplesize, NULL);
11841             break;
11842           }
11843           case FOURCC_alac:
11844           {
11845             GNode *alac, *wave = NULL;
11846
11847             /* apparently, m4a has this atom appended directly in the stsd entry,
11848              * while mov has it in a wave atom */
11849             alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
11850             if (alac) {
11851               /* alac now refers to stsd entry atom */
11852               wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
11853               if (wave)
11854                 alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
11855               else
11856                 alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
11857             }
11858             if (alac) {
11859               const guint8 *alac_data = alac->data;
11860               gint len = QT_UINT32 (alac->data);
11861               GstBuffer *buf;
11862
11863               if (len < 36) {
11864                 GST_DEBUG_OBJECT (qtdemux,
11865                     "discarding alac atom with unexpected len %d", len);
11866               } else {
11867                 /* codec-data contains alac atom size and prefix,
11868                  * ffmpeg likes it that way, not quite gst-ish though ...*/
11869                 buf = gst_buffer_new_and_alloc (len);
11870                 gst_buffer_fill (buf, 0, alac->data, len);
11871                 gst_caps_set_simple (entry->caps,
11872                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
11873                 gst_buffer_unref (buf);
11874
11875                 entry->bytes_per_frame = QT_UINT32 (alac_data + 12);
11876                 entry->n_channels = QT_UINT8 (alac_data + 21);
11877                 entry->rate = QT_UINT32 (alac_data + 32);
11878               }
11879             }
11880             gst_caps_set_simple (entry->caps,
11881                 "samplesize", G_TYPE_INT, samplesize, NULL);
11882             break;
11883           }
11884           case FOURCC_fLaC:
11885           {
11886             /* The codingname of the sample entry is 'fLaC' */
11887             GNode *flac = qtdemux_tree_get_child_by_type (stsd, FOURCC_fLaC);
11888
11889             if (flac) {
11890               /* The 'dfLa' box is added to the sample entry to convey
11891                  initializing information for the decoder. */
11892               const GNode *dfla =
11893                   qtdemux_tree_get_child_by_type (flac, FOURCC_dfLa);
11894
11895               if (dfla) {
11896                 const guint32 len = QT_UINT32 (dfla->data);
11897
11898                 /* Must contain at least dfLa box header (12),
11899                  * METADATA_BLOCK_HEADER (4), METADATA_BLOCK_STREAMINFO (34) */
11900                 if (len < 50) {
11901                   GST_DEBUG_OBJECT (qtdemux,
11902                       "discarding dfla atom with unexpected len %d", len);
11903                 } else {
11904                   /* skip dfLa header to get the METADATA_BLOCKs */
11905                   const guint8 *metadata_blocks = (guint8 *) dfla->data + 12;
11906                   const guint32 metadata_blocks_len = len - 12;
11907
11908                   gchar *stream_marker = g_strdup ("fLaC");
11909                   GstBuffer *block = gst_buffer_new_wrapped (stream_marker,
11910                       strlen (stream_marker));
11911
11912                   guint32 index = 0;
11913                   guint32 remainder = 0;
11914                   guint32 block_size = 0;
11915                   gboolean is_last = FALSE;
11916
11917                   GValue array = G_VALUE_INIT;
11918                   GValue value = G_VALUE_INIT;
11919
11920                   g_value_init (&array, GST_TYPE_ARRAY);
11921                   g_value_init (&value, GST_TYPE_BUFFER);
11922
11923                   gst_value_set_buffer (&value, block);
11924                   gst_value_array_append_value (&array, &value);
11925                   g_value_reset (&value);
11926
11927                   gst_buffer_unref (block);
11928
11929                   /* check there's at least one METADATA_BLOCK_HEADER's worth
11930                    * of data, and we haven't already finished parsing */
11931                   while (!is_last && ((index + 3) < metadata_blocks_len)) {
11932                     remainder = metadata_blocks_len - index;
11933
11934                     /* add the METADATA_BLOCK_HEADER size to the signalled size */
11935                     block_size = 4 +
11936                         (metadata_blocks[index + 1] << 16) +
11937                         (metadata_blocks[index + 2] << 8) +
11938                         metadata_blocks[index + 3];
11939
11940                     /* be careful not to read off end of box */
11941                     if (block_size > remainder) {
11942                       break;
11943                     }
11944
11945                     is_last = metadata_blocks[index] >> 7;
11946
11947                     block = gst_buffer_new_and_alloc (block_size);
11948
11949                     gst_buffer_fill (block, 0, &metadata_blocks[index],
11950                         block_size);
11951
11952                     gst_value_set_buffer (&value, block);
11953                     gst_value_array_append_value (&array, &value);
11954                     g_value_reset (&value);
11955
11956                     gst_buffer_unref (block);
11957
11958                     index += block_size;
11959                   }
11960
11961                   /* only append the metadata if we successfully read all of it */
11962                   if (is_last) {
11963                     gst_structure_set_value (gst_caps_get_structure (CUR_STREAM
11964                             (stream)->caps, 0), "streamheader", &array);
11965                   } else {
11966                     GST_WARNING_OBJECT (qtdemux,
11967                         "discarding all METADATA_BLOCKs due to invalid "
11968                         "block_size %d at idx %d, rem %d", block_size, index,
11969                         remainder);
11970                   }
11971
11972                   g_value_unset (&value);
11973                   g_value_unset (&array);
11974
11975                   /* The sample rate obtained from the stsd may not be accurate
11976                    * since it cannot represent rates greater than 65535Hz, so
11977                    * override that value with the sample rate from the
11978                    * METADATA_BLOCK_STREAMINFO block */
11979                   CUR_STREAM (stream)->rate =
11980                       (QT_UINT32 (metadata_blocks + 14) >> 12) & 0xFFFFF;
11981                 }
11982               }
11983             }
11984             break;
11985           }
11986           case FOURCC_sawb:
11987             /* Fallthrough! */
11988             amrwb = TRUE;
11989           case FOURCC_samr:
11990           {
11991             gint len = QT_UINT32 (stsd_entry_data);
11992
11993             if (len > 0x24) {
11994               GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x24);
11995               guint bitrate;
11996
11997               gst_buffer_fill (buf, 0, stsd_entry_data + 0x24, len - 0x24);
11998
11999               /* If we have enough data, let's try to get the 'damr' atom. See
12000                * the 3GPP container spec (26.244) for more details. */
12001               if ((len - 0x34) > 8 &&
12002                   (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
12003                 gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12004                     GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
12005               }
12006
12007               gst_caps_set_simple (entry->caps,
12008                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
12009               gst_buffer_unref (buf);
12010             }
12011             break;
12012           }
12013           case FOURCC_mp4a:
12014           {
12015             /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
12016             gint len = QT_UINT32 (stsd_entry_data);
12017
12018             if (len >= 34) {
12019               guint16 sound_version = QT_UINT16 (stsd_entry_data + 16);
12020
12021               if (sound_version == 1) {
12022                 guint16 channels = QT_UINT16 (stsd_entry_data + 24);
12023                 guint32 time_scale = QT_UINT32 (stsd_entry_data + 30);
12024                 guint8 codec_data[2];
12025                 GstBuffer *buf;
12026                 gint profile = 2;       /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
12027
12028                 gint sample_rate_index =
12029                     gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
12030
12031                 /* build AAC codec data */
12032                 codec_data[0] = profile << 3;
12033                 codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
12034                 codec_data[1] = (sample_rate_index & 0x01) << 7;
12035                 codec_data[1] |= (channels & 0xF) << 3;
12036
12037                 buf = gst_buffer_new_and_alloc (2);
12038                 gst_buffer_fill (buf, 0, codec_data, 2);
12039                 gst_caps_set_simple (entry->caps,
12040                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
12041                 gst_buffer_unref (buf);
12042               }
12043             }
12044             break;
12045           }
12046           default:
12047             GST_INFO_OBJECT (qtdemux,
12048                 "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12049             break;
12050         }
12051       }
12052       GST_INFO_OBJECT (qtdemux,
12053           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12054           GST_FOURCC_ARGS (fourcc), entry->caps);
12055
12056     } else if (stream->subtype == FOURCC_strm) {
12057       if (fourcc == FOURCC_rtsp) {
12058         stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
12059       } else {
12060         GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
12061             GST_FOURCC_ARGS (fourcc));
12062         goto unknown_stream;
12063       }
12064       entry->sampled = TRUE;
12065     } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
12066         || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
12067
12068       entry->sampled = TRUE;
12069       entry->sparse = TRUE;
12070
12071       entry->caps =
12072           qtdemux_sub_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12073           &codec);
12074       if (codec) {
12075         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12076             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12077         g_free (codec);
12078         codec = NULL;
12079       }
12080
12081       /* hunt for sort-of codec data */
12082       switch (fourcc) {
12083         case FOURCC_mp4s:
12084         {
12085           GNode *mp4s = NULL;
12086           GNode *esds = NULL;
12087
12088           /* look for palette in a stsd->mp4s->esds sub-atom */
12089           mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
12090           if (mp4s)
12091             esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
12092           if (esds == NULL) {
12093             /* Invalid STSD */
12094             GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
12095             break;
12096           }
12097
12098           gst_qtdemux_handle_esds (qtdemux, stream, entry, esds,
12099               stream->stream_tags);
12100           break;
12101         }
12102         default:
12103           GST_INFO_OBJECT (qtdemux,
12104               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12105           break;
12106       }
12107       GST_INFO_OBJECT (qtdemux,
12108           "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
12109           GST_FOURCC_ARGS (fourcc), entry->caps);
12110     } else {
12111       /* everything in 1 sample */
12112       entry->sampled = TRUE;
12113
12114       entry->caps =
12115           qtdemux_generic_caps (qtdemux, stream, entry, fourcc, stsd_entry_data,
12116           &codec);
12117
12118       if (entry->caps == NULL)
12119         goto unknown_stream;
12120
12121       if (codec) {
12122         gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12123             GST_TAG_SUBTITLE_CODEC, codec, NULL);
12124         g_free (codec);
12125         codec = NULL;
12126       }
12127     }
12128
12129     /* promote to sampled format */
12130     if (entry->fourcc == FOURCC_samr) {
12131       /* force mono 8000 Hz for AMR */
12132       entry->sampled = TRUE;
12133       entry->n_channels = 1;
12134       entry->rate = 8000;
12135     } else if (entry->fourcc == FOURCC_sawb) {
12136       /* force mono 16000 Hz for AMR-WB */
12137       entry->sampled = TRUE;
12138       entry->n_channels = 1;
12139       entry->rate = 16000;
12140     } else if (entry->fourcc == FOURCC_mp4a) {
12141       entry->sampled = TRUE;
12142     }
12143
12144
12145     stsd_entry_data += len;
12146     remaining_stsd_len -= len;
12147
12148   }
12149
12150   /* collect sample information */
12151   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
12152     goto samples_failed;
12153
12154   if (qtdemux->fragmented) {
12155     guint64 offset;
12156
12157     /* need all moov samples as basis; probably not many if any at all */
12158     /* prevent moof parsing taking of at this time */
12159     offset = qtdemux->moof_offset;
12160     qtdemux->moof_offset = 0;
12161     if (stream->n_samples &&
12162         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
12163       qtdemux->moof_offset = offset;
12164       goto samples_failed;
12165     }
12166     qtdemux->moof_offset = 0;
12167     /* movie duration more reliable in this case (e.g. mehd) */
12168     if (qtdemux->segment.duration &&
12169         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
12170       stream->duration =
12171           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
12172   }
12173
12174   /* configure segments */
12175   if (!qtdemux_parse_segments (qtdemux, stream, trak))
12176     goto segments_failed;
12177
12178   /* add some language tag, if useful */
12179   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
12180       strcmp (stream->lang_id, "und")) {
12181     const gchar *lang_code;
12182
12183     /* convert ISO 639-2 code to ISO 639-1 */
12184     lang_code = gst_tag_get_language_code (stream->lang_id);
12185     gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12186         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
12187   }
12188
12189   /* Check for UDTA tags */
12190   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
12191     qtdemux_parse_udta (qtdemux, stream->stream_tags, udta);
12192   }
12193
12194   /* now we are ready to add the stream */
12195   if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
12196     goto too_many_streams;
12197
12198   if (!qtdemux->got_moov) {
12199     qtdemux->streams[qtdemux->n_streams] = stream;
12200     qtdemux->n_streams++;
12201     GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
12202   }
12203
12204   return TRUE;
12205
12206 /* ERRORS */
12207 skip_track:
12208   {
12209     GST_INFO_OBJECT (qtdemux, "skip disabled track");
12210     if (new_stream)
12211       gst_qtdemux_stream_free (qtdemux, stream);
12212     return TRUE;
12213   }
12214 corrupt_file:
12215   {
12216     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
12217         (_("This file is corrupt and cannot be played.")), (NULL));
12218     if (new_stream)
12219       gst_qtdemux_stream_free (qtdemux, stream);
12220     return FALSE;
12221   }
12222 error_encrypted:
12223   {
12224     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
12225     if (new_stream)
12226       gst_qtdemux_stream_free (qtdemux, stream);
12227     return FALSE;
12228   }
12229 samples_failed:
12230 segments_failed:
12231   {
12232     /* we posted an error already */
12233     /* free stbl sub-atoms */
12234     gst_qtdemux_stbl_free (stream);
12235     if (new_stream)
12236       gst_qtdemux_stream_free (qtdemux, stream);
12237     return FALSE;
12238   }
12239 existing_stream:
12240   {
12241     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
12242         track_id);
12243     if (new_stream)
12244       gst_qtdemux_stream_free (qtdemux, stream);
12245     return TRUE;
12246   }
12247 unknown_stream:
12248   {
12249     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
12250         GST_FOURCC_ARGS (stream->subtype));
12251     if (new_stream)
12252       gst_qtdemux_stream_free (qtdemux, stream);
12253     return TRUE;
12254   }
12255 too_many_streams:
12256   {
12257     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
12258         (_("This file contains too many streams. Only playing first %d"),
12259             GST_QTDEMUX_MAX_STREAMS), (NULL));
12260     return TRUE;
12261   }
12262 }
12263
12264 /* If we can estimate the overall bitrate, and don't have information about the
12265  * stream bitrate for exactly one stream, this guesses the stream bitrate as
12266  * the overall bitrate minus the sum of the bitrates of all other streams. This
12267  * should be useful for the common case where we have one audio and one video
12268  * stream and can estimate the bitrate of one, but not the other. */
12269 static void
12270 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
12271 {
12272   QtDemuxStream *stream = NULL;
12273   gint64 size, sys_bitrate, sum_bitrate = 0;
12274   GstClockTime duration;
12275   gint i;
12276   guint bitrate;
12277
12278   if (qtdemux->fragmented)
12279     return;
12280
12281   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
12282
12283   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
12284       || size <= 0) {
12285     GST_DEBUG_OBJECT (qtdemux,
12286         "Size in bytes of the stream not known - bailing");
12287     return;
12288   }
12289
12290   /* Subtract the header size */
12291   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
12292       size, qtdemux->header_size);
12293
12294   if (size < qtdemux->header_size)
12295     return;
12296
12297   size = size - qtdemux->header_size;
12298
12299   if (!gst_qtdemux_get_duration (qtdemux, &duration)) {
12300     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
12301     return;
12302   }
12303
12304   for (i = 0; i < qtdemux->n_streams; i++) {
12305     switch (qtdemux->streams[i]->subtype) {
12306       case FOURCC_soun:
12307       case FOURCC_vide:
12308         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
12309             CUR_STREAM (qtdemux->streams[i])->caps);
12310         /* retrieve bitrate, prefer avg then max */
12311         bitrate = 0;
12312         if (qtdemux->streams[i]->stream_tags) {
12313           gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
12314               GST_TAG_MAXIMUM_BITRATE, &bitrate);
12315           GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
12316           gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
12317               GST_TAG_NOMINAL_BITRATE, &bitrate);
12318           GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
12319           gst_tag_list_get_uint (qtdemux->streams[i]->stream_tags,
12320               GST_TAG_BITRATE, &bitrate);
12321           GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
12322         }
12323         if (bitrate)
12324           sum_bitrate += bitrate;
12325         else {
12326           if (stream) {
12327             GST_DEBUG_OBJECT (qtdemux,
12328                 ">1 stream with unknown bitrate - bailing");
12329             return;
12330           } else
12331             stream = qtdemux->streams[i];
12332         }
12333
12334       default:
12335         /* For other subtypes, we assume no significant impact on bitrate */
12336         break;
12337     }
12338   }
12339
12340   if (!stream) {
12341     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
12342     return;
12343   }
12344
12345   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
12346
12347   if (sys_bitrate < sum_bitrate) {
12348     /* This can happen, since sum_bitrate might be derived from maximum
12349      * bitrates and not average bitrates */
12350     GST_DEBUG_OBJECT (qtdemux,
12351         "System bitrate less than sum bitrate - bailing");
12352     return;
12353   }
12354
12355   bitrate = sys_bitrate - sum_bitrate;
12356   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
12357       ", Stream bitrate = %u", sys_bitrate, bitrate);
12358
12359   if (!stream->stream_tags)
12360     stream->stream_tags = gst_tag_list_new_empty ();
12361   else
12362     stream->stream_tags = gst_tag_list_make_writable (stream->stream_tags);
12363
12364   gst_tag_list_add (stream->stream_tags, GST_TAG_MERGE_REPLACE,
12365       GST_TAG_BITRATE, bitrate, NULL);
12366 }
12367
12368 static GstFlowReturn
12369 qtdemux_prepare_streams (GstQTDemux * qtdemux)
12370 {
12371   gint i;
12372   GstFlowReturn ret = GST_FLOW_OK;
12373
12374   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
12375
12376   for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
12377     QtDemuxStream *stream = qtdemux->streams[i];
12378     guint32 sample_num = 0;
12379
12380     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
12381         i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12382
12383     if (qtdemux->fragmented) {
12384       /* need all moov samples first */
12385       GST_OBJECT_LOCK (qtdemux);
12386       while (stream->n_samples == 0)
12387         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
12388           break;
12389       GST_OBJECT_UNLOCK (qtdemux);
12390     } else {
12391       /* discard any stray moof */
12392       qtdemux->moof_offset = 0;
12393     }
12394
12395     /* prepare braking */
12396     if (ret != GST_FLOW_ERROR)
12397       ret = GST_FLOW_OK;
12398
12399     /* in pull mode, we should have parsed some sample info by now;
12400      * and quite some code will not handle no samples.
12401      * in push mode, we'll just have to deal with it */
12402     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
12403       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
12404       gst_qtdemux_remove_stream (qtdemux, i);
12405       i--;
12406       continue;
12407     }
12408
12409     /* parse the initial sample for use in setting the frame rate cap */
12410     while (sample_num == 0 && sample_num < stream->n_samples) {
12411       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
12412         break;
12413       ++sample_num;
12414     }
12415     if (stream->n_samples > 0 && stream->stbl_index >= 0) {
12416       stream->first_duration = stream->samples[0].duration;
12417       GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
12418           stream->track_id, stream->first_duration);
12419     }
12420   }
12421
12422   return ret;
12423 }
12424
12425 static GstFlowReturn
12426 qtdemux_expose_streams (GstQTDemux * qtdemux)
12427 {
12428   gint i;
12429   GSList *oldpads = NULL;
12430   GSList *iter;
12431
12432   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
12433
12434   for (i = 0; i < qtdemux->n_streams; i++) {
12435     QtDemuxStream *stream = qtdemux->streams[i];
12436     GstPad *oldpad = stream->pad;
12437     GstTagList *list;
12438
12439     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
12440         i, stream->track_id, GST_FOURCC_ARGS (CUR_STREAM (stream)->fourcc));
12441
12442     if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
12443         stream->track_id == qtdemux->chapters_track_id) {
12444       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
12445          so that it doesn't look like a subtitle track */
12446       gst_qtdemux_remove_stream (qtdemux, i);
12447       i--;
12448       continue;
12449     }
12450
12451     /* now we have all info and can expose */
12452     list = stream->stream_tags;
12453     stream->stream_tags = NULL;
12454     if (oldpad)
12455       oldpads = g_slist_prepend (oldpads, oldpad);
12456     if (!gst_qtdemux_add_stream (qtdemux, stream, list))
12457       return GST_FLOW_ERROR;
12458   }
12459
12460   gst_qtdemux_guess_bitrate (qtdemux);
12461
12462   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
12463
12464   for (iter = oldpads; iter; iter = g_slist_next (iter)) {
12465     GstPad *oldpad = iter->data;
12466     GstEvent *event;
12467
12468     event = gst_event_new_eos ();
12469     if (qtdemux->segment_seqnum)
12470       gst_event_set_seqnum (event, qtdemux->segment_seqnum);
12471
12472     gst_pad_push_event (oldpad, event);
12473     gst_pad_set_active (oldpad, FALSE);
12474     gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
12475     gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
12476     gst_object_unref (oldpad);
12477   }
12478
12479   /* check if we should post a redirect in case there is a single trak
12480    * and it is a redirecting trak */
12481   if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
12482     GstMessage *m;
12483
12484     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
12485         "an external content");
12486     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
12487         gst_structure_new ("redirect",
12488             "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
12489             NULL));
12490     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
12491     qtdemux->posted_redirect = TRUE;
12492   }
12493
12494   for (i = 0; i < qtdemux->n_streams; i++) {
12495     QtDemuxStream *stream = qtdemux->streams[i];
12496
12497     qtdemux_do_allocation (qtdemux, stream);
12498   }
12499
12500   qtdemux->exposed = TRUE;
12501   return GST_FLOW_OK;
12502 }
12503
12504 /* check if major or compatible brand is 3GP */
12505 static inline gboolean
12506 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
12507 {
12508   if (major) {
12509     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12510         FOURCC_3g__);
12511   } else if (qtdemux->comp_brands != NULL) {
12512     GstMapInfo map;
12513     guint8 *data;
12514     gsize size;
12515     gboolean res = FALSE;
12516
12517     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
12518     data = map.data;
12519     size = map.size;
12520     while (size >= 4) {
12521       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
12522           FOURCC_3g__);
12523       data += 4;
12524       size -= 4;
12525     }
12526     gst_buffer_unmap (qtdemux->comp_brands, &map);
12527     return res;
12528   } else {
12529     return FALSE;
12530   }
12531 }
12532
12533 /* check if tag is a spec'ed 3GP tag keyword storing a string */
12534 static inline gboolean
12535 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
12536 {
12537   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
12538       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
12539       || fourcc == FOURCC_albm;
12540 }
12541
12542 static void
12543 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
12544     const char *tag, const char *dummy, GNode * node)
12545 {
12546   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12547   int offset;
12548   char *name;
12549   gchar *data;
12550   gdouble longitude, latitude, altitude;
12551   gint len;
12552
12553   len = QT_UINT32 (node->data);
12554   if (len <= 14)
12555     goto short_read;
12556
12557   data = node->data;
12558   offset = 14;
12559
12560   /* TODO: language code skipped */
12561
12562   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
12563
12564   if (!name) {
12565     /* do not alarm in trivial case, but bail out otherwise */
12566     if (*(data + offset) != 0) {
12567       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
12568           "giving up", tag);
12569     }
12570   } else {
12571     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12572         GST_TAG_GEO_LOCATION_NAME, name, NULL);
12573     offset += strlen (name);
12574     g_free (name);
12575   }
12576
12577   if (len < offset + 2 + 4 + 4 + 4)
12578     goto short_read;
12579
12580   /* +1 +1 = skip null-terminator and location role byte */
12581   offset += 1 + 1;
12582   /* table in spec says unsigned, semantics say negative has meaning ... */
12583   longitude = QT_SFP32 (data + offset);
12584
12585   offset += 4;
12586   latitude = QT_SFP32 (data + offset);
12587
12588   offset += 4;
12589   altitude = QT_SFP32 (data + offset);
12590
12591   /* one invalid means all are invalid */
12592   if (longitude >= -180.0 && longitude <= 180.0 &&
12593       latitude >= -90.0 && latitude <= 90.0) {
12594     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
12595         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
12596         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
12597         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
12598   }
12599
12600   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
12601
12602   return;
12603
12604   /* ERRORS */
12605 short_read:
12606   {
12607     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
12608     return;
12609   }
12610 }
12611
12612
12613 static void
12614 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
12615     const char *tag, const char *dummy, GNode * node)
12616 {
12617   guint16 y;
12618   GDate *date;
12619   gint len;
12620
12621   len = QT_UINT32 (node->data);
12622   if (len < 14)
12623     return;
12624
12625   y = QT_UINT16 ((guint8 *) node->data + 12);
12626   if (y == 0) {
12627     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
12628     return;
12629   }
12630   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
12631
12632   date = g_date_new_dmy (1, 1, y);
12633   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
12634   g_date_free (date);
12635 }
12636
12637 static void
12638 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
12639     const char *tag, const char *dummy, GNode * node)
12640 {
12641   int offset;
12642   char *tag_str = NULL;
12643   guint8 *entity;
12644   guint16 table;
12645   gint len;
12646
12647   len = QT_UINT32 (node->data);
12648   if (len <= 20)
12649     goto short_read;
12650
12651   offset = 12;
12652   entity = (guint8 *) node->data + offset;
12653   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
12654     GST_DEBUG_OBJECT (qtdemux,
12655         "classification info: %c%c%c%c invalid classification entity",
12656         entity[0], entity[1], entity[2], entity[3]);
12657     return;
12658   }
12659
12660   offset += 4;
12661   table = QT_UINT16 ((guint8 *) node->data + offset);
12662
12663   /* Language code skipped */
12664
12665   offset += 4;
12666
12667   /* Tag format: "XXXX://Y[YYYY]/classification info string"
12668    * XXXX: classification entity, fixed length 4 chars.
12669    * Y[YYYY]: classification table, max 5 chars.
12670    */
12671   tag_str = g_strdup_printf ("----://%u/%s",
12672       table, (char *) node->data + offset);
12673
12674   /* memcpy To be sure we're preserving byte order */
12675   memcpy (tag_str, entity, 4);
12676   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
12677
12678   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
12679
12680   g_free (tag_str);
12681
12682   return;
12683
12684   /* ERRORS */
12685 short_read:
12686   {
12687     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
12688     return;
12689   }
12690 }
12691
12692 static gboolean
12693 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
12694     const char *tag, const char *dummy, GNode * node)
12695 {
12696   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12697   GNode *data;
12698   char *s;
12699   int len;
12700   guint32 type;
12701   int offset;
12702   gboolean ret = TRUE;
12703   const gchar *charset = NULL;
12704
12705   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12706   if (data) {
12707     len = QT_UINT32 (data->data);
12708     type = QT_UINT32 ((guint8 *) data->data + 8);
12709     if (type == 0x00000001 && len > 16) {
12710       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
12711           env_vars);
12712       if (s) {
12713         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12714         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12715         g_free (s);
12716       } else {
12717         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12718       }
12719     }
12720   } else {
12721     len = QT_UINT32 (node->data);
12722     type = QT_UINT32 ((guint8 *) node->data + 4);
12723     if ((type >> 24) == 0xa9 && len > 8 + 4) {
12724       gint str_len;
12725       gint lang_code;
12726
12727       /* Type starts with the (C) symbol, so the next data is a list
12728        * of (string size(16), language code(16), string) */
12729
12730       str_len = QT_UINT16 ((guint8 *) node->data + 8);
12731       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
12732
12733       /* the string + fourcc + size + 2 16bit fields,
12734        * means that there are more tags in this atom */
12735       if (len > str_len + 8 + 4) {
12736         /* TODO how to represent the same tag in different languages? */
12737         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
12738             "text alternatives, reading only first one");
12739       }
12740
12741       offset = 12;
12742       len = MIN (len, str_len + 8 + 4); /* remove trailing strings that we don't use */
12743       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
12744
12745       if (lang_code < 0x800) {  /* MAC encoded string */
12746         charset = "mac";
12747       }
12748     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
12749             QT_FOURCC ((guint8 *) node->data + 4))) {
12750       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
12751
12752       /* we go for 3GP style encoding if major brands claims so,
12753        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
12754       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
12755           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
12756               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
12757         offset = 14;
12758         /* 16-bit Language code is ignored here as well */
12759         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
12760       } else {
12761         goto normal;
12762       }
12763     } else {
12764     normal:
12765       offset = 8;
12766       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
12767       ret = FALSE;              /* may have to fallback */
12768     }
12769     if (charset) {
12770       GError *err = NULL;
12771
12772       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
12773           charset, NULL, NULL, &err);
12774       if (err) {
12775         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
12776             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
12777             err->message);
12778         g_error_free (err);
12779       }
12780     } else {
12781       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12782           len - offset, env_vars);
12783     }
12784     if (s) {
12785       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
12786       gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
12787       g_free (s);
12788       ret = TRUE;
12789     } else {
12790       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
12791     }
12792   }
12793   return ret;
12794 }
12795
12796 static void
12797 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
12798     const char *tag, const char *dummy, GNode * node)
12799 {
12800   qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
12801 }
12802
12803 static void
12804 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
12805     const char *tag, const char *dummy, GNode * node)
12806 {
12807   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
12808   guint8 *data;
12809   char *s, *t, *k = NULL;
12810   int len;
12811   int offset;
12812   int count;
12813
12814   /* first try normal string tag if major brand not 3GP */
12815   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
12816     if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
12817       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
12818        * let's try it 3gpp way after minor safety check */
12819       data = node->data;
12820       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
12821         return;
12822     } else
12823       return;
12824   }
12825
12826   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
12827
12828   data = node->data;
12829
12830   len = QT_UINT32 (data);
12831   if (len < 15)
12832     goto short_read;
12833
12834   count = QT_UINT8 (data + 14);
12835   offset = 15;
12836   for (; count; count--) {
12837     gint slen;
12838
12839     if (offset + 1 > len)
12840       goto short_read;
12841     slen = QT_UINT8 (data + offset);
12842     offset += 1;
12843     if (offset + slen > len)
12844       goto short_read;
12845     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
12846         slen, env_vars);
12847     if (s) {
12848       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
12849       if (k) {
12850         t = g_strjoin (",", k, s, NULL);
12851         g_free (s);
12852         g_free (k);
12853         k = t;
12854       } else {
12855         k = s;
12856       }
12857     } else {
12858       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
12859     }
12860     offset += slen;
12861   }
12862
12863 done:
12864   if (k) {
12865     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
12866     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
12867   }
12868   g_free (k);
12869
12870   return;
12871
12872   /* ERRORS */
12873 short_read:
12874   {
12875     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
12876     goto done;
12877   }
12878 }
12879
12880 static void
12881 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
12882     const char *tag1, const char *tag2, GNode * node)
12883 {
12884   GNode *data;
12885   int len;
12886   int type;
12887   int n1, n2;
12888
12889   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12890   if (data) {
12891     len = QT_UINT32 (data->data);
12892     type = QT_UINT32 ((guint8 *) data->data + 8);
12893     if (type == 0x00000000 && len >= 22) {
12894       n1 = QT_UINT16 ((guint8 *) data->data + 18);
12895       n2 = QT_UINT16 ((guint8 *) data->data + 20);
12896       if (n1 > 0) {
12897         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
12898         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
12899       }
12900       if (n2 > 0) {
12901         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
12902         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
12903       }
12904     }
12905   }
12906 }
12907
12908 static void
12909 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
12910     const char *tag1, const char *dummy, GNode * node)
12911 {
12912   GNode *data;
12913   int len;
12914   int type;
12915   int n1;
12916
12917   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12918   if (data) {
12919     len = QT_UINT32 (data->data);
12920     type = QT_UINT32 ((guint8 *) data->data + 8);
12921     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
12922     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12923     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
12924       n1 = QT_UINT16 ((guint8 *) data->data + 16);
12925       if (n1) {
12926         /* do not add bpm=0 */
12927         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
12928         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
12929             NULL);
12930       }
12931     }
12932   }
12933 }
12934
12935 static void
12936 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
12937     const char *tag1, const char *dummy, GNode * node)
12938 {
12939   GNode *data;
12940   int len;
12941   int type;
12942   guint32 num;
12943
12944   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12945   if (data) {
12946     len = QT_UINT32 (data->data);
12947     type = QT_UINT32 ((guint8 *) data->data + 8);
12948     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
12949     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
12950     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
12951       num = QT_UINT32 ((guint8 *) data->data + 16);
12952       if (num) {
12953         /* do not add num=0 */
12954         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
12955         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
12956       }
12957     }
12958   }
12959 }
12960
12961 static void
12962 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
12963     const char *tag1, const char *dummy, GNode * node)
12964 {
12965   GNode *data;
12966   int len;
12967   int type;
12968   GstSample *sample;
12969
12970   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
12971   if (data) {
12972     len = QT_UINT32 (data->data);
12973     type = QT_UINT32 ((guint8 *) data->data + 8);
12974     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
12975     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
12976       GstTagImageType image_type;
12977
12978       if (gst_tag_list_get_tag_size (taglist, GST_TAG_IMAGE) == 0)
12979         image_type = GST_TAG_IMAGE_TYPE_FRONT_COVER;
12980       else
12981         image_type = GST_TAG_IMAGE_TYPE_NONE;
12982
12983       if ((sample =
12984               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
12985                   len - 16, image_type))) {
12986         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
12987         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
12988         gst_sample_unref (sample);
12989       }
12990     }
12991   }
12992 }
12993
12994 static void
12995 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
12996     const char *tag, const char *dummy, GNode * node)
12997 {
12998   GNode *data;
12999   char *s;
13000   int len;
13001   int type;
13002
13003   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13004   if (data) {
13005     len = QT_UINT32 (data->data);
13006     type = QT_UINT32 ((guint8 *) data->data + 8);
13007     if (type == 0x00000001 && len > 16) {
13008       guint y, m = 1, d = 1;
13009       gint ret;
13010
13011       s = g_strndup ((char *) data->data + 16, len - 16);
13012       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
13013       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
13014       if (ret >= 1 && y > 1500 && y < 3000) {
13015         GDate *date;
13016
13017         date = g_date_new_dmy (d, m, y);
13018         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
13019         g_date_free (date);
13020       } else {
13021         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
13022       }
13023       g_free (s);
13024     }
13025   }
13026 }
13027
13028 static void
13029 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
13030     const char *tag, const char *dummy, GNode * node)
13031 {
13032   GNode *data;
13033
13034   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13035
13036   /* re-route to normal string tag if major brand says so
13037    * or no data atom and compatible brand suggests so */
13038   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
13039       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
13040     qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
13041     return;
13042   }
13043
13044   if (data) {
13045     guint len, type, n;
13046
13047     len = QT_UINT32 (data->data);
13048     type = QT_UINT32 ((guint8 *) data->data + 8);
13049     if (type == 0x00000000 && len >= 18) {
13050       n = QT_UINT16 ((guint8 *) data->data + 16);
13051       if (n > 0) {
13052         const gchar *genre;
13053
13054         genre = gst_tag_id3_genre_get (n - 1);
13055         if (genre != NULL) {
13056           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
13057           gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
13058         }
13059       }
13060     }
13061   }
13062 }
13063
13064 static void
13065 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
13066     const gchar * tag, guint8 * data, guint32 datasize)
13067 {
13068   gdouble value;
13069   gchar *datacopy;
13070
13071   /* make a copy to have \0 at the end */
13072   datacopy = g_strndup ((gchar *) data, datasize);
13073
13074   /* convert the str to double */
13075   if (sscanf (datacopy, "%lf", &value) == 1) {
13076     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
13077     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
13078   } else {
13079     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
13080         datacopy);
13081   }
13082   g_free (datacopy);
13083 }
13084
13085
13086 static void
13087 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
13088     const char *tag, const char *tag_bis, GNode * node)
13089 {
13090   GNode *mean;
13091   GNode *name;
13092   GNode *data;
13093   guint32 meansize;
13094   guint32 namesize;
13095   guint32 datatype;
13096   guint32 datasize;
13097   const gchar *meanstr;
13098   const gchar *namestr;
13099
13100   /* checking the whole ---- atom size for consistency */
13101   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
13102     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
13103     return;
13104   }
13105
13106   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
13107   if (!mean) {
13108     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
13109     return;
13110   }
13111
13112   meansize = QT_UINT32 (mean->data);
13113   if (meansize <= 12) {
13114     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
13115     return;
13116   }
13117   meanstr = ((gchar *) mean->data) + 12;
13118   meansize -= 12;
13119
13120   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
13121   if (!name) {
13122     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
13123     return;
13124   }
13125
13126   namesize = QT_UINT32 (name->data);
13127   if (namesize <= 12) {
13128     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
13129     return;
13130   }
13131   namestr = ((gchar *) name->data) + 12;
13132   namesize -= 12;
13133
13134   /*
13135    * Data atom is:
13136    * uint32 - size
13137    * uint32 - name
13138    * uint8  - version
13139    * uint24 - data type
13140    * uint32 - all 0
13141    * rest   - the data
13142    */
13143   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
13144   if (!data) {
13145     GST_WARNING_OBJECT (demux, "No data atom in this tag");
13146     return;
13147   }
13148   datasize = QT_UINT32 (data->data);
13149   if (datasize <= 16) {
13150     GST_WARNING_OBJECT (demux, "Data atom too small");
13151     return;
13152   }
13153   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
13154
13155   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
13156       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
13157     static const struct
13158     {
13159       const gchar name[28];
13160       const gchar tag[28];
13161     } tags[] = {
13162       {
13163       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
13164       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
13165       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
13166       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
13167       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
13168       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
13169       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
13170       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
13171     };
13172     int i;
13173
13174     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
13175       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
13176         switch (gst_tag_get_type (tags[i].tag)) {
13177           case G_TYPE_DOUBLE:
13178             qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
13179                 ((guint8 *) data->data) + 16, datasize - 16);
13180             break;
13181           case G_TYPE_STRING:
13182             qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
13183             break;
13184           default:
13185             /* not reached */
13186             break;
13187         }
13188         break;
13189       }
13190     }
13191     if (i == G_N_ELEMENTS (tags))
13192       goto unknown_tag;
13193   } else {
13194     goto unknown_tag;
13195   }
13196
13197   return;
13198
13199 /* errors */
13200 unknown_tag:
13201 #ifndef GST_DISABLE_GST_DEBUG
13202   {
13203     gchar *namestr_dbg;
13204     gchar *meanstr_dbg;
13205
13206     meanstr_dbg = g_strndup (meanstr, meansize);
13207     namestr_dbg = g_strndup (namestr, namesize);
13208
13209     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
13210         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
13211
13212     g_free (namestr_dbg);
13213     g_free (meanstr_dbg);
13214   }
13215 #endif
13216   return;
13217 }
13218
13219 static void
13220 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
13221     const char *tag_bis, GNode * node)
13222 {
13223   guint8 *data;
13224   GstBuffer *buf;
13225   guint len;
13226   GstTagList *id32_taglist = NULL;
13227
13228   GST_LOG_OBJECT (demux, "parsing ID32");
13229
13230   data = node->data;
13231   len = GST_READ_UINT32_BE (data);
13232
13233   /* need at least full box and language tag */
13234   if (len < 12 + 2)
13235     return;
13236
13237   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
13238   gst_buffer_fill (buf, 0, data + 14, len - 14);
13239
13240   id32_taglist = gst_tag_list_from_id3v2_tag (buf);
13241   if (id32_taglist) {
13242     GST_LOG_OBJECT (demux, "parsing ok");
13243     gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
13244     gst_tag_list_unref (id32_taglist);
13245   } else {
13246     GST_LOG_OBJECT (demux, "parsing failed");
13247   }
13248
13249   gst_buffer_unref (buf);
13250 }
13251
13252 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
13253     const char *tag, const char *tag_bis, GNode * node);
13254
13255 /* unmapped tags
13256 FOURCC_pcst -> if media is a podcast -> bool
13257 FOURCC_cpil -> if media is part of a compilation -> bool
13258 FOURCC_pgap -> if media is part of a gapless context -> bool
13259 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
13260 */
13261
13262 static const struct
13263 {
13264   guint32 fourcc;
13265   const gchar *gst_tag;
13266   const gchar *gst_tag_bis;
13267   const GstQTDemuxAddTagFunc func;
13268 } add_funcs[] = {
13269   {
13270   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13271   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
13272   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
13273   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13274   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13275   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
13276   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
13277   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
13278   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13279   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
13280   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13281   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
13282   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13283   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13284   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13285   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
13286   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
13287   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
13288   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
13289   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13290   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
13291   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
13292   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13293         qtdemux_tag_add_num}, {
13294   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
13295         qtdemux_tag_add_num}, {
13296   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
13297   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
13298   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
13299   FOURCC_covr, GST_TAG_IMAGE, NULL, qtdemux_tag_add_covr}, {
13300   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
13301   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
13302   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13303   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
13304   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
13305   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
13306   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
13307   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13308   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
13309   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
13310   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
13311   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
13312   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
13313   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
13314         qtdemux_tag_add_classification}, {
13315   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
13316   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
13317   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
13318
13319     /* This is a special case, some tags are stored in this
13320      * 'reverse dns naming', according to:
13321      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
13322      * bug #614471
13323      */
13324   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
13325     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
13326   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
13327 };
13328
13329 struct _GstQtDemuxTagList
13330 {
13331   GstQTDemux *demux;
13332   GstTagList *taglist;
13333 };
13334 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
13335
13336 static void
13337 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
13338 {
13339   gint len;
13340   guint8 *data;
13341   GstBuffer *buf;
13342   gchar *media_type;
13343   const gchar *style;
13344   GstSample *sample;
13345   GstStructure *s;
13346   guint i;
13347   guint8 ndata[4];
13348   GstQTDemux *demux = qtdemuxtaglist->demux;
13349   GstTagList *taglist = qtdemuxtaglist->taglist;
13350
13351   data = node->data;
13352   len = QT_UINT32 (data);
13353   buf = gst_buffer_new_and_alloc (len);
13354   gst_buffer_fill (buf, 0, data, len);
13355
13356   /* heuristic to determine style of tag */
13357   if (QT_FOURCC (data + 4) == FOURCC_____ ||
13358       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
13359     style = "itunes";
13360   else if (demux->major_brand == FOURCC_qt__)
13361     style = "quicktime";
13362   /* fall back to assuming iso/3gp tag style */
13363   else
13364     style = "iso";
13365
13366   /* santize the name for the caps. */
13367   for (i = 0; i < 4; i++) {
13368     guint8 d = data[4 + i];
13369     if (g_ascii_isalnum (d))
13370       ndata[i] = g_ascii_tolower (d);
13371     else
13372       ndata[i] = '_';
13373   }
13374
13375   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
13376       ndata[0], ndata[1], ndata[2], ndata[3]);
13377   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
13378
13379   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
13380   sample = gst_sample_new (buf, NULL, NULL, s);
13381   gst_buffer_unref (buf);
13382   g_free (media_type);
13383
13384   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
13385       len, s);
13386
13387   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
13388       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
13389
13390   gst_sample_unref (sample);
13391 }
13392
13393 static void
13394 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
13395 {
13396   GNode *meta;
13397   GNode *ilst;
13398   GNode *xmp_;
13399   GNode *node;
13400   gint i;
13401   GstQtDemuxTagList demuxtaglist;
13402
13403   demuxtaglist.demux = qtdemux;
13404   demuxtaglist.taglist = taglist;
13405
13406   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
13407   if (meta != NULL) {
13408     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
13409     if (ilst == NULL) {
13410       GST_LOG_OBJECT (qtdemux, "no ilst");
13411       return;
13412     }
13413   } else {
13414     ilst = udta;
13415     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
13416   }
13417
13418   i = 0;
13419   while (i < G_N_ELEMENTS (add_funcs)) {
13420     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
13421     if (node) {
13422       gint len;
13423
13424       len = QT_UINT32 (node->data);
13425       if (len < 12) {
13426         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
13427             GST_FOURCC_ARGS (add_funcs[i].fourcc));
13428       } else {
13429         add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
13430             add_funcs[i].gst_tag_bis, node);
13431       }
13432       g_node_destroy (node);
13433     } else {
13434       i++;
13435     }
13436   }
13437
13438   /* parsed nodes have been removed, pass along remainder as blob */
13439   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
13440       (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
13441
13442   /* parse up XMP_ node if existing */
13443   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
13444   if (xmp_ != NULL) {
13445     GstBuffer *buf;
13446     GstTagList *xmptaglist;
13447
13448     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
13449         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
13450     xmptaglist = gst_tag_list_from_xmp_buffer (buf);
13451     gst_buffer_unref (buf);
13452
13453     qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
13454   } else {
13455     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
13456   }
13457 }
13458
13459 typedef struct
13460 {
13461   GstStructure *structure;      /* helper for sort function */
13462   gchar *location;
13463   guint min_req_bitrate;
13464   guint min_req_qt_version;
13465 } GstQtReference;
13466
13467 static gint
13468 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
13469 {
13470   GstQtReference *ref_a = (GstQtReference *) a;
13471   GstQtReference *ref_b = (GstQtReference *) b;
13472
13473   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
13474     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
13475
13476   /* known bitrates go before unknown; higher bitrates go first */
13477   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
13478 }
13479
13480 /* sort the redirects and post a message for the application.
13481  */
13482 static void
13483 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
13484 {
13485   GstQtReference *best;
13486   GstStructure *s;
13487   GstMessage *msg;
13488   GValue list_val = { 0, };
13489   GList *l;
13490
13491   g_assert (references != NULL);
13492
13493   references = g_list_sort (references, qtdemux_redirects_sort_func);
13494
13495   best = (GstQtReference *) references->data;
13496
13497   g_value_init (&list_val, GST_TYPE_LIST);
13498
13499   for (l = references; l != NULL; l = l->next) {
13500     GstQtReference *ref = (GstQtReference *) l->data;
13501     GValue struct_val = { 0, };
13502
13503     ref->structure = gst_structure_new ("redirect",
13504         "new-location", G_TYPE_STRING, ref->location, NULL);
13505
13506     if (ref->min_req_bitrate > 0) {
13507       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
13508           ref->min_req_bitrate, NULL);
13509     }
13510
13511     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
13512     g_value_set_boxed (&struct_val, ref->structure);
13513     gst_value_list_append_value (&list_val, &struct_val);
13514     g_value_unset (&struct_val);
13515     /* don't free anything here yet, since we need best->structure below */
13516   }
13517
13518   g_assert (best != NULL);
13519   s = gst_structure_copy (best->structure);
13520
13521   if (g_list_length (references) > 1) {
13522     gst_structure_set_value (s, "locations", &list_val);
13523   }
13524
13525   g_value_unset (&list_val);
13526
13527   for (l = references; l != NULL; l = l->next) {
13528     GstQtReference *ref = (GstQtReference *) l->data;
13529
13530     gst_structure_free (ref->structure);
13531     g_free (ref->location);
13532     g_free (ref);
13533   }
13534   g_list_free (references);
13535
13536   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
13537   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
13538   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
13539   qtdemux->posted_redirect = TRUE;
13540 }
13541
13542 /* look for redirect nodes, collect all redirect information and
13543  * process it.
13544  */
13545 static gboolean
13546 qtdemux_parse_redirects (GstQTDemux * qtdemux)
13547 {
13548   GNode *rmra, *rmda, *rdrf;
13549
13550   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
13551   if (rmra) {
13552     GList *redirects = NULL;
13553
13554     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
13555     while (rmda) {
13556       GstQtReference ref = { NULL, NULL, 0, 0 };
13557       GNode *rmdr, *rmvc;
13558
13559       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
13560         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
13561         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
13562             ref.min_req_bitrate);
13563       }
13564
13565       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
13566         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
13567         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
13568
13569 #ifndef GST_DISABLE_GST_DEBUG
13570         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
13571 #endif
13572         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
13573
13574         GST_LOG_OBJECT (qtdemux,
13575             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
13576             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
13577             bitmask, check_type);
13578         if (package == FOURCC_qtim && check_type == 0) {
13579           ref.min_req_qt_version = version;
13580         }
13581       }
13582
13583       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
13584       if (rdrf) {
13585         guint32 ref_type;
13586         guint8 *ref_data;
13587         guint ref_len;
13588
13589         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
13590         if (ref_len > 20) {
13591           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
13592           ref_data = (guint8 *) rdrf->data + 20;
13593           if (ref_type == FOURCC_alis) {
13594             guint record_len, record_version, fn_len;
13595
13596             if (ref_len > 70) {
13597               /* MacOSX alias record, google for alias-layout.txt */
13598               record_len = QT_UINT16 (ref_data + 4);
13599               record_version = QT_UINT16 (ref_data + 4 + 2);
13600               fn_len = QT_UINT8 (ref_data + 50);
13601               if (record_len > 50 && record_version == 2 && fn_len > 0) {
13602                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
13603               }
13604             } else {
13605               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
13606                   ref_len);
13607             }
13608           } else if (ref_type == FOURCC_url_) {
13609             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
13610           } else {
13611             GST_DEBUG_OBJECT (qtdemux,
13612                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
13613                 GST_FOURCC_ARGS (ref_type));
13614           }
13615           if (ref.location != NULL) {
13616             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
13617             redirects =
13618                 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
13619           } else {
13620             GST_WARNING_OBJECT (qtdemux,
13621                 "Failed to extract redirect location from rdrf atom");
13622           }
13623         } else {
13624           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
13625         }
13626       }
13627
13628       /* look for others */
13629       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
13630     }
13631
13632     if (redirects != NULL) {
13633       qtdemux_process_redirects (qtdemux, redirects);
13634     }
13635   }
13636   return TRUE;
13637 }
13638
13639 static GstTagList *
13640 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
13641 {
13642   const gchar *fmt;
13643
13644   if (tags == NULL) {
13645     tags = gst_tag_list_new_empty ();
13646     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
13647   }
13648
13649   if (qtdemux->major_brand == FOURCC_mjp2)
13650     fmt = "Motion JPEG 2000";
13651   else if ((qtdemux->major_brand & 0xffff) == FOURCC_3g__)
13652     fmt = "3GP";
13653   else if (qtdemux->major_brand == FOURCC_qt__)
13654     fmt = "Quicktime";
13655   else if (qtdemux->fragmented)
13656     fmt = "ISO fMP4";
13657   else
13658     fmt = "ISO MP4/M4A";
13659
13660   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
13661       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
13662
13663   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
13664       fmt, NULL);
13665
13666   return tags;
13667 }
13668
13669 /* we have read the complete moov node now.
13670  * This function parses all of the relevant info, creates the traks and
13671  * prepares all data structures for playback
13672  */
13673 static gboolean
13674 qtdemux_parse_tree (GstQTDemux * qtdemux)
13675 {
13676   GNode *mvhd;
13677   GNode *trak;
13678   GNode *udta;
13679   GNode *mvex;
13680   GstClockTime duration;
13681   GNode *pssh;
13682   guint64 creation_time;
13683   GstDateTime *datetime = NULL;
13684   gint version;
13685
13686   /* make sure we have a usable taglist */
13687   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13688
13689   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
13690   if (mvhd == NULL) {
13691     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
13692     return qtdemux_parse_redirects (qtdemux);
13693   }
13694
13695   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
13696   if (version == 1) {
13697     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
13698     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
13699     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
13700   } else if (version == 0) {
13701     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
13702     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
13703     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
13704   } else {
13705     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
13706     return FALSE;
13707   }
13708
13709   /* Moving qt creation time (secs since 1904) to unix time */
13710   if (creation_time != 0) {
13711     /* Try to use epoch first as it should be faster and more commonly found */
13712     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
13713       GTimeVal now;
13714
13715       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
13716       /* some data cleansing sanity */
13717       g_get_current_time (&now);
13718       if (now.tv_sec + 24 * 3600 < creation_time) {
13719         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
13720       } else {
13721         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
13722       }
13723     } else {
13724       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
13725       GDateTime *dt, *dt_local;
13726
13727       dt = g_date_time_add_seconds (base_dt, creation_time);
13728       dt_local = g_date_time_to_local (dt);
13729       datetime = gst_date_time_new_from_g_date_time (dt_local);
13730
13731       g_date_time_unref (base_dt);
13732       g_date_time_unref (dt);
13733     }
13734   }
13735   if (datetime) {
13736     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
13737     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
13738         datetime, NULL);
13739     gst_date_time_unref (datetime);
13740   }
13741
13742   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
13743   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
13744
13745   /* check for fragmented file and get some (default) data */
13746   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
13747   if (mvex) {
13748     GNode *mehd;
13749     GstByteReader mehd_data;
13750
13751     /* let track parsing or anyone know weird stuff might happen ... */
13752     qtdemux->fragmented = TRUE;
13753
13754     /* compensate for total duration */
13755     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
13756     if (mehd)
13757       qtdemux_parse_mehd (qtdemux, &mehd_data);
13758   }
13759
13760   /* set duration in the segment info */
13761   gst_qtdemux_get_duration (qtdemux, &duration);
13762   if (duration) {
13763     qtdemux->segment.duration = duration;
13764     /* also do not exceed duration; stop is set that way post seek anyway,
13765      * and segment activation falls back to duration,
13766      * whereas loop only checks stop, so let's align this here as well */
13767     qtdemux->segment.stop = duration;
13768   }
13769
13770   /* parse all traks */
13771   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
13772   while (trak) {
13773     qtdemux_parse_trak (qtdemux, trak);
13774     /* iterate all siblings */
13775     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
13776   }
13777
13778   qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
13779
13780   /* find tags */
13781   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
13782   if (udta) {
13783     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13784   } else {
13785     GST_LOG_OBJECT (qtdemux, "No udta node found.");
13786   }
13787
13788   /* maybe also some tags in meta box */
13789   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
13790   if (udta) {
13791     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
13792     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
13793   } else {
13794     GST_LOG_OBJECT (qtdemux, "No meta node found.");
13795   }
13796
13797   /* parse any protection system info */
13798   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
13799   while (pssh) {
13800     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
13801     qtdemux_parse_pssh (qtdemux, pssh);
13802     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
13803   }
13804
13805   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
13806
13807   return TRUE;
13808 }
13809
13810 /* taken from ffmpeg */
13811 static int
13812 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
13813 {
13814   int count = 4;
13815   int len = 0;
13816
13817   while (count--) {
13818     int c;
13819
13820     if (ptr >= end)
13821       return -1;
13822
13823     c = *ptr++;
13824     len = (len << 7) | (c & 0x7f);
13825     if (!(c & 0x80))
13826       break;
13827   }
13828   *end_out = ptr;
13829   return len;
13830 }
13831
13832 /* this can change the codec originally present in @list */
13833 static void
13834 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
13835     QtDemuxStreamStsdEntry * entry, GNode * esds, GstTagList * list)
13836 {
13837   int len = QT_UINT32 (esds->data);
13838   guint8 *ptr = esds->data;
13839   guint8 *end = ptr + len;
13840   int tag;
13841   guint8 *data_ptr = NULL;
13842   int data_len = 0;
13843   guint8 object_type_id = 0;
13844   const char *codec_name = NULL;
13845   GstCaps *caps = NULL;
13846
13847   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
13848   ptr += 8;
13849   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
13850   ptr += 4;
13851   while (ptr + 1 < end) {
13852     tag = QT_UINT8 (ptr);
13853     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
13854     ptr++;
13855     len = read_descr_size (ptr, end, &ptr);
13856     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
13857
13858     /* Check the stated amount of data is available for reading */
13859     if (len < 0 || ptr + len > end)
13860       break;
13861
13862     switch (tag) {
13863       case ES_DESCRIPTOR_TAG:
13864         GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
13865         GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
13866         ptr += 3;
13867         break;
13868       case DECODER_CONFIG_DESC_TAG:{
13869         guint max_bitrate, avg_bitrate;
13870
13871         object_type_id = QT_UINT8 (ptr);
13872         max_bitrate = QT_UINT32 (ptr + 5);
13873         avg_bitrate = QT_UINT32 (ptr + 9);
13874         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
13875         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
13876         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
13877         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
13878         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
13879         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
13880           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
13881               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
13882         }
13883         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
13884           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
13885               avg_bitrate, NULL);
13886         }
13887         ptr += 13;
13888         break;
13889       }
13890       case DECODER_SPECIFIC_INFO_TAG:
13891         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
13892         if (object_type_id == 0xe0 && len == 0x40) {
13893           guint8 *data;
13894           GstStructure *s;
13895           guint32 clut[16];
13896           gint i;
13897
13898           GST_DEBUG_OBJECT (qtdemux,
13899               "Have VOBSUB palette. Creating palette event");
13900           /* move to decConfigDescr data and read palette */
13901           data = ptr;
13902           for (i = 0; i < 16; i++) {
13903             clut[i] = QT_UINT32 (data);
13904             data += 4;
13905           }
13906
13907           s = gst_structure_new ("application/x-gst-dvd", "event",
13908               G_TYPE_STRING, "dvd-spu-clut-change",
13909               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
13910               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
13911               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
13912               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
13913               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
13914               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
13915               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
13916               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
13917               NULL);
13918
13919           /* store event and trigger custom processing */
13920           stream->pending_event =
13921               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
13922         } else {
13923           /* Generic codec_data handler puts it on the caps */
13924           data_ptr = ptr;
13925           data_len = len;
13926         }
13927
13928         ptr += len;
13929         break;
13930       case SL_CONFIG_DESC_TAG:
13931         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
13932         ptr += 1;
13933         break;
13934       default:
13935         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
13936             tag);
13937         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
13938         ptr += len;
13939         break;
13940     }
13941   }
13942
13943   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
13944    * in use, and should also be used to override some other parameters for some
13945    * codecs. */
13946   switch (object_type_id) {
13947     case 0x20:                 /* MPEG-4 */
13948       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
13949        * profile_and_level_indication */
13950       if (data_ptr != NULL && data_len >= 5 &&
13951           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
13952         gst_codec_utils_mpeg4video_caps_set_level_and_profile (entry->caps,
13953             data_ptr + 4, data_len - 4);
13954       }
13955       break;                    /* Nothing special needed here */
13956     case 0x21:                 /* H.264 */
13957       codec_name = "H.264 / AVC";
13958       caps = gst_caps_new_simple ("video/x-h264",
13959           "stream-format", G_TYPE_STRING, "avc",
13960           "alignment", G_TYPE_STRING, "au", NULL);
13961       break;
13962     case 0x40:                 /* AAC (any) */
13963     case 0x66:                 /* AAC Main */
13964     case 0x67:                 /* AAC LC */
13965     case 0x68:                 /* AAC SSR */
13966       /* Override channels and rate based on the codec_data, as it's often
13967        * wrong. */
13968       /* Only do so for basic setup without HE-AAC extension */
13969       if (data_ptr && data_len == 2) {
13970         guint channels, rate;
13971
13972         channels = gst_codec_utils_aac_get_channels (data_ptr, data_len);
13973         if (channels > 0)
13974           entry->n_channels = channels;
13975
13976         rate = gst_codec_utils_aac_get_sample_rate (data_ptr, data_len);
13977         if (rate > 0)
13978           entry->rate = rate;
13979       }
13980
13981       /* Set level and profile if possible */
13982       if (data_ptr != NULL && data_len >= 2) {
13983         gst_codec_utils_aac_caps_set_level_and_profile (entry->caps,
13984             data_ptr, data_len);
13985       } else {
13986         const gchar *profile_str = NULL;
13987         GstBuffer *buffer;
13988         GstMapInfo map;
13989         guint8 *codec_data;
13990         gint rate_idx, profile;
13991
13992         /* No codec_data, let's invent something.
13993          * FIXME: This is wrong for SBR! */
13994
13995         GST_WARNING_OBJECT (qtdemux, "No codec_data for AAC available");
13996
13997         buffer = gst_buffer_new_and_alloc (2);
13998         gst_buffer_map (buffer, &map, GST_MAP_WRITE);
13999         codec_data = map.data;
14000
14001         rate_idx =
14002             gst_codec_utils_aac_get_index_from_sample_rate (CUR_STREAM
14003             (stream)->rate);
14004
14005         switch (object_type_id) {
14006           case 0x66:
14007             profile_str = "main";
14008             profile = 0;
14009             break;
14010           case 0x67:
14011             profile_str = "lc";
14012             profile = 1;
14013             break;
14014           case 0x68:
14015             profile_str = "ssr";
14016             profile = 2;
14017             break;
14018           default:
14019             profile = 3;
14020             break;
14021         }
14022
14023         codec_data[0] = ((profile + 1) << 3) | ((rate_idx & 0xE) >> 1);
14024         codec_data[1] =
14025             ((rate_idx & 0x1) << 7) | (CUR_STREAM (stream)->n_channels << 3);
14026
14027         gst_buffer_unmap (buffer, &map);
14028         gst_caps_set_simple (CUR_STREAM (stream)->caps, "codec_data",
14029             GST_TYPE_BUFFER, buffer, NULL);
14030         gst_buffer_unref (buffer);
14031
14032         if (profile_str) {
14033           gst_caps_set_simple (CUR_STREAM (stream)->caps, "profile",
14034               G_TYPE_STRING, profile_str, NULL);
14035         }
14036       }
14037       break;
14038     case 0x60:                 /* MPEG-2, various profiles */
14039     case 0x61:
14040     case 0x62:
14041     case 0x63:
14042     case 0x64:
14043     case 0x65:
14044       codec_name = "MPEG-2 video";
14045       caps = gst_caps_new_simple ("video/mpeg",
14046           "mpegversion", G_TYPE_INT, 2,
14047           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14048       break;
14049     case 0x69:                 /* MPEG-2 BC audio */
14050     case 0x6B:                 /* MPEG-1 audio */
14051       caps = gst_caps_new_simple ("audio/mpeg",
14052           "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
14053       codec_name = "MPEG-1 audio";
14054       break;
14055     case 0x6A:                 /* MPEG-1 */
14056       codec_name = "MPEG-1 video";
14057       caps = gst_caps_new_simple ("video/mpeg",
14058           "mpegversion", G_TYPE_INT, 1,
14059           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14060       break;
14061     case 0x6C:                 /* MJPEG */
14062       caps =
14063           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14064           NULL);
14065       codec_name = "Motion-JPEG";
14066       break;
14067     case 0x6D:                 /* PNG */
14068       caps =
14069           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
14070           NULL);
14071       codec_name = "PNG still images";
14072       break;
14073     case 0x6E:                 /* JPEG2000 */
14074       codec_name = "JPEG-2000";
14075       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14076       break;
14077     case 0xA4:                 /* Dirac */
14078       codec_name = "Dirac";
14079       caps = gst_caps_new_empty_simple ("video/x-dirac");
14080       break;
14081     case 0xA5:                 /* AC3 */
14082       codec_name = "AC-3 audio";
14083       caps = gst_caps_new_simple ("audio/x-ac3",
14084           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14085       break;
14086     case 0xA9:                 /* AC3 */
14087       codec_name = "DTS audio";
14088       caps = gst_caps_new_simple ("audio/x-dts",
14089           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14090       break;
14091     case 0xE1:                 /* QCELP */
14092       /* QCELP, the codec_data is a riff tag (little endian) with
14093        * 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). */
14094       caps = gst_caps_new_empty_simple ("audio/qcelp");
14095       codec_name = "QCELP";
14096       break;
14097     default:
14098       break;
14099   }
14100
14101   /* If we have a replacement caps, then change our caps for this stream */
14102   if (caps) {
14103     gst_caps_unref (entry->caps);
14104     entry->caps = caps;
14105   }
14106
14107   if (codec_name && list)
14108     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
14109         GST_TAG_AUDIO_CODEC, codec_name, NULL);
14110
14111   /* Add the codec_data attribute to caps, if we have it */
14112   if (data_ptr) {
14113     GstBuffer *buffer;
14114
14115     buffer = gst_buffer_new_and_alloc (data_len);
14116     gst_buffer_fill (buffer, 0, data_ptr, data_len);
14117
14118     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
14119     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
14120
14121     gst_caps_set_simple (entry->caps, "codec_data", GST_TYPE_BUFFER,
14122         buffer, NULL);
14123     gst_buffer_unref (buffer);
14124   }
14125
14126 }
14127
14128 static inline GstCaps *
14129 _get_unknown_codec_name (const gchar * type, guint32 fourcc)
14130 {
14131   GstCaps *caps;
14132   guint i;
14133   char *s, fourstr[5];
14134
14135   g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
14136   for (i = 0; i < 4; i++) {
14137     if (!g_ascii_isalnum (fourstr[i]))
14138       fourstr[i] = '_';
14139   }
14140   s = g_strdup_printf ("%s/x-gst-fourcc-%s", type, g_strstrip (fourstr));
14141   caps = gst_caps_new_empty_simple (s);
14142   g_free (s);
14143   return caps;
14144 }
14145
14146 #define _codec(name) \
14147   do { \
14148     if (codec_name) { \
14149       *codec_name = g_strdup (name); \
14150     } \
14151   } while (0)
14152
14153 static GstCaps *
14154 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14155     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14156     const guint8 * stsd_entry_data, gchar ** codec_name)
14157 {
14158   GstCaps *caps = NULL;
14159   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
14160
14161   switch (fourcc) {
14162     case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
14163       _codec ("PNG still images");
14164       caps = gst_caps_new_empty_simple ("image/png");
14165       break;
14166     case FOURCC_jpeg:
14167       _codec ("JPEG still images");
14168       caps =
14169           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14170           NULL);
14171       break;
14172     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
14173     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
14174     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
14175     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
14176       _codec ("Motion-JPEG");
14177       caps =
14178           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
14179           NULL);
14180       break;
14181     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
14182       _codec ("Motion-JPEG format B");
14183       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
14184       break;
14185     case FOURCC_mjp2:
14186       _codec ("JPEG-2000");
14187       /* override to what it should be according to spec, avoid palette_data */
14188       entry->bits_per_sample = 24;
14189       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
14190       break;
14191     case FOURCC_SVQ3:
14192       _codec ("Sorensen video v.3");
14193       caps = gst_caps_new_simple ("video/x-svq",
14194           "svqversion", G_TYPE_INT, 3, NULL);
14195       break;
14196     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
14197     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
14198       _codec ("Sorensen video v.1");
14199       caps = gst_caps_new_simple ("video/x-svq",
14200           "svqversion", G_TYPE_INT, 1, NULL);
14201       break;
14202     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
14203       caps = gst_caps_new_empty_simple ("video/x-raw");
14204       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
14205       _codec ("Windows Raw RGB");
14206       stream->alignment = 32;
14207       break;
14208     case FOURCC_raw_:
14209     {
14210       guint16 bps;
14211
14212       bps = QT_UINT16 (stsd_entry_data + 82);
14213       switch (bps) {
14214         case 15:
14215           format = GST_VIDEO_FORMAT_RGB15;
14216           break;
14217         case 16:
14218           format = GST_VIDEO_FORMAT_RGB16;
14219           break;
14220         case 24:
14221           format = GST_VIDEO_FORMAT_RGB;
14222           break;
14223         case 32:
14224           format = GST_VIDEO_FORMAT_ARGB;
14225           break;
14226         default:
14227           /* unknown */
14228           break;
14229       }
14230       break;
14231     }
14232     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
14233       format = GST_VIDEO_FORMAT_I420;
14234       break;
14235     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
14236     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
14237       format = GST_VIDEO_FORMAT_I420;
14238       break;
14239     case FOURCC_2vuy:
14240     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
14241       format = GST_VIDEO_FORMAT_UYVY;
14242       break;
14243     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
14244       format = GST_VIDEO_FORMAT_v308;
14245       break;
14246     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
14247       format = GST_VIDEO_FORMAT_v216;
14248       break;
14249     case FOURCC_v210:
14250       format = GST_VIDEO_FORMAT_v210;
14251       break;
14252     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
14253       format = GST_VIDEO_FORMAT_r210;
14254       break;
14255       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
14256          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
14257          format = GST_VIDEO_FORMAT_v410;
14258          break;
14259        */
14260       /* Packed YUV 4:4:4:4 8 bit in 32 bits
14261        * but different order than AYUV
14262        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
14263        format = GST_VIDEO_FORMAT_v408;
14264        break;
14265        */
14266     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
14267     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
14268       _codec ("MPEG-1 video");
14269       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14270           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14271       break;
14272     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
14273     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
14274     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
14275     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
14276     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
14277     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
14278     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
14279     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
14280     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
14281     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
14282     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
14283     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
14284     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
14285     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
14286     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
14287     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
14288     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
14289     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
14290     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
14291     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
14292     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
14293     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
14294     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
14295     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
14296     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
14297     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
14298     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
14299     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
14300     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
14301     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
14302     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
14303     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
14304     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
14305     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
14306     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
14307     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
14308     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14309     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
14310     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
14311     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
14312     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
14313     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
14314     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
14315     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
14316     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
14317     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
14318     case GST_MAKE_FOURCC ('m', '2', 'v', '1'):
14319       _codec ("MPEG-2 video");
14320       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
14321           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14322       break;
14323     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
14324       _codec ("GIF still images");
14325       caps = gst_caps_new_empty_simple ("image/gif");
14326       break;
14327     case FOURCC_h263:
14328     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
14329     case FOURCC_s263:
14330     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
14331       _codec ("H.263");
14332       /* ffmpeg uses the height/width props, don't know why */
14333       caps = gst_caps_new_simple ("video/x-h263",
14334           "variant", G_TYPE_STRING, "itu", NULL);
14335       break;
14336     case FOURCC_mp4v:
14337     case FOURCC_MP4V:
14338       _codec ("MPEG-4 video");
14339       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14340           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14341       break;
14342     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
14343     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
14344       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
14345       caps = gst_caps_new_simple ("video/x-msmpeg",
14346           "msmpegversion", G_TYPE_INT, 43, NULL);
14347       break;
14348     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
14349       _codec ("DivX 3");
14350       caps = gst_caps_new_simple ("video/x-divx",
14351           "divxversion", G_TYPE_INT, 3, NULL);
14352       break;
14353     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
14354     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
14355       _codec ("DivX 4");
14356       caps = gst_caps_new_simple ("video/x-divx",
14357           "divxversion", G_TYPE_INT, 4, NULL);
14358       break;
14359     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
14360       _codec ("DivX 5");
14361       caps = gst_caps_new_simple ("video/x-divx",
14362           "divxversion", G_TYPE_INT, 5, NULL);
14363       break;
14364
14365     case GST_MAKE_FOURCC ('F', 'F', 'V', '1'):
14366       _codec ("FFV1");
14367       caps = gst_caps_new_simple ("video/x-ffv",
14368           "ffvversion", G_TYPE_INT, 1, NULL);
14369       break;
14370
14371     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
14372     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
14373     case FOURCC_XVID:
14374     case FOURCC_xvid:
14375     case FOURCC_FMP4:
14376     case FOURCC_fmp4:
14377     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
14378       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
14379           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14380       _codec ("MPEG-4");
14381       break;
14382
14383     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
14384       _codec ("Cinepak");
14385       caps = gst_caps_new_empty_simple ("video/x-cinepak");
14386       break;
14387     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
14388       _codec ("Apple QuickDraw");
14389       caps = gst_caps_new_empty_simple ("video/x-qdrw");
14390       break;
14391     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
14392       _codec ("Apple video");
14393       caps = gst_caps_new_empty_simple ("video/x-apple-video");
14394       break;
14395     case FOURCC_H264:
14396     case FOURCC_avc1:
14397       _codec ("H.264 / AVC");
14398       caps = gst_caps_new_simple ("video/x-h264",
14399           "stream-format", G_TYPE_STRING, "avc",
14400           "alignment", G_TYPE_STRING, "au", NULL);
14401       break;
14402     case FOURCC_avc3:
14403       _codec ("H.264 / AVC");
14404       caps = gst_caps_new_simple ("video/x-h264",
14405           "stream-format", G_TYPE_STRING, "avc3",
14406           "alignment", G_TYPE_STRING, "au", NULL);
14407       break;
14408     case FOURCC_H265:
14409     case FOURCC_hvc1:
14410       _codec ("H.265 / HEVC");
14411       caps = gst_caps_new_simple ("video/x-h265",
14412           "stream-format", G_TYPE_STRING, "hvc1",
14413           "alignment", G_TYPE_STRING, "au", NULL);
14414       break;
14415     case FOURCC_hev1:
14416       _codec ("H.265 / HEVC");
14417       caps = gst_caps_new_simple ("video/x-h265",
14418           "stream-format", G_TYPE_STRING, "hev1",
14419           "alignment", G_TYPE_STRING, "au", NULL);
14420       break;
14421     case FOURCC_rle_:
14422       _codec ("Run-length encoding");
14423       caps = gst_caps_new_simple ("video/x-rle",
14424           "layout", G_TYPE_STRING, "quicktime", NULL);
14425       break;
14426     case FOURCC_WRLE:
14427       _codec ("Run-length encoding");
14428       caps = gst_caps_new_simple ("video/x-rle",
14429           "layout", G_TYPE_STRING, "microsoft", NULL);
14430       break;
14431     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
14432     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
14433       _codec ("Indeo Video 3");
14434       caps = gst_caps_new_simple ("video/x-indeo",
14435           "indeoversion", G_TYPE_INT, 3, NULL);
14436       break;
14437     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
14438     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
14439       _codec ("Intel Video 4");
14440       caps = gst_caps_new_simple ("video/x-indeo",
14441           "indeoversion", G_TYPE_INT, 4, NULL);
14442       break;
14443     case FOURCC_dvcp:
14444     case FOURCC_dvc_:
14445     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
14446     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
14447     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
14448     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
14449     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
14450     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
14451       _codec ("DV Video");
14452       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
14453           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14454       break;
14455     case FOURCC_dv5n:          /* DVCPRO50 NTSC */
14456     case FOURCC_dv5p:          /* DVCPRO50 PAL */
14457       _codec ("DVCPro50 Video");
14458       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
14459           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14460       break;
14461     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
14462     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
14463       _codec ("DVCProHD Video");
14464       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
14465           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14466       break;
14467     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
14468       _codec ("Apple Graphics (SMC)");
14469       caps = gst_caps_new_empty_simple ("video/x-smc");
14470       break;
14471     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
14472       _codec ("VP3");
14473       caps = gst_caps_new_empty_simple ("video/x-vp3");
14474       break;
14475     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
14476       _codec ("VP6 Flash");
14477       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
14478       break;
14479     case FOURCC_XiTh:
14480       _codec ("Theora");
14481       caps = gst_caps_new_empty_simple ("video/x-theora");
14482       /* theora uses one byte of padding in the data stream because it does not
14483        * allow 0 sized packets while theora does */
14484       entry->padding = 1;
14485       break;
14486     case FOURCC_drac:
14487       _codec ("Dirac");
14488       caps = gst_caps_new_empty_simple ("video/x-dirac");
14489       break;
14490     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
14491       _codec ("TIFF still images");
14492       caps = gst_caps_new_empty_simple ("image/tiff");
14493       break;
14494     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
14495       _codec ("Apple Intermediate Codec");
14496       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
14497       break;
14498     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
14499       _codec ("AVID DNxHD");
14500       caps = gst_caps_from_string ("video/x-dnxhd");
14501       break;
14502     case FOURCC_VP80:
14503       _codec ("On2 VP8");
14504       caps = gst_caps_from_string ("video/x-vp8");
14505       break;
14506     case FOURCC_apcs:
14507       _codec ("Apple ProRes LT");
14508       caps =
14509           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
14510           NULL);
14511       break;
14512     case FOURCC_apch:
14513       _codec ("Apple ProRes HQ");
14514       caps =
14515           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
14516           NULL);
14517       break;
14518     case FOURCC_apcn:
14519       _codec ("Apple ProRes");
14520       caps =
14521           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14522           "standard", NULL);
14523       break;
14524     case FOURCC_apco:
14525       _codec ("Apple ProRes Proxy");
14526       caps =
14527           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14528           "proxy", NULL);
14529       break;
14530     case FOURCC_ap4h:
14531       _codec ("Apple ProRes 4444");
14532       caps =
14533           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14534           "4444", NULL);
14535       break;
14536     case FOURCC_ap4x:
14537       _codec ("Apple ProRes 4444 XQ");
14538       caps =
14539           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
14540           "4444xq", NULL);
14541       break;
14542     case FOURCC_cfhd:
14543       _codec ("GoPro CineForm");
14544       caps = gst_caps_from_string ("video/x-cineform");
14545       break;
14546     case FOURCC_vc_1:
14547     case FOURCC_ovc1:
14548       _codec ("VC-1");
14549       caps = gst_caps_new_simple ("video/x-wmv",
14550           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
14551       break;
14552     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
14553     default:
14554     {
14555       caps = _get_unknown_codec_name ("video", fourcc);
14556       break;
14557     }
14558   }
14559
14560   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
14561     GstVideoInfo info;
14562
14563     gst_video_info_init (&info);
14564     gst_video_info_set_format (&info, format, entry->width, entry->height);
14565
14566     caps = gst_video_info_to_caps (&info);
14567     *codec_name = gst_pb_utils_get_codec_description (caps);
14568
14569     /* enable clipping for raw video streams */
14570     stream->need_clip = TRUE;
14571     stream->alignment = 32;
14572   }
14573
14574   return caps;
14575 }
14576
14577 static guint
14578 round_up_pow2 (guint n)
14579 {
14580   n = n - 1;
14581   n = n | (n >> 1);
14582   n = n | (n >> 2);
14583   n = n | (n >> 4);
14584   n = n | (n >> 8);
14585   n = n | (n >> 16);
14586   return n + 1;
14587 }
14588
14589 static GstCaps *
14590 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14591     QtDemuxStreamStsdEntry * entry, guint32 fourcc, const guint8 * data,
14592     int len, gchar ** codec_name)
14593 {
14594   GstCaps *caps;
14595   const GstStructure *s;
14596   const gchar *name;
14597   gint endian = 0;
14598   GstAudioFormat format = 0;
14599   gint depth;
14600
14601   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14602
14603   depth = entry->bytes_per_packet * 8;
14604
14605   switch (fourcc) {
14606     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
14607     case FOURCC_raw_:
14608       /* 8-bit audio is unsigned */
14609       if (depth == 8)
14610         format = GST_AUDIO_FORMAT_U8;
14611       /* otherwise it's signed and big-endian just like 'twos' */
14612     case FOURCC_twos:
14613       endian = G_BIG_ENDIAN;
14614       /* fall-through */
14615     case FOURCC_sowt:
14616     {
14617       gchar *str;
14618
14619       if (!endian)
14620         endian = G_LITTLE_ENDIAN;
14621
14622       if (!format)
14623         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
14624
14625       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
14626       _codec (str);
14627       g_free (str);
14628
14629       caps = gst_caps_new_simple ("audio/x-raw",
14630           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14631           "layout", G_TYPE_STRING, "interleaved", NULL);
14632       stream->alignment = GST_ROUND_UP_8 (depth);
14633       stream->alignment = round_up_pow2 (stream->alignment);
14634       break;
14635     }
14636     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
14637       _codec ("Raw 64-bit floating-point audio");
14638       caps = gst_caps_new_simple ("audio/x-raw",
14639           "format", G_TYPE_STRING, "F64BE",
14640           "layout", G_TYPE_STRING, "interleaved", NULL);
14641       stream->alignment = 8;
14642       break;
14643     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
14644       _codec ("Raw 32-bit floating-point audio");
14645       caps = gst_caps_new_simple ("audio/x-raw",
14646           "format", G_TYPE_STRING, "F32BE",
14647           "layout", G_TYPE_STRING, "interleaved", NULL);
14648       stream->alignment = 4;
14649       break;
14650     case FOURCC_in24:
14651       _codec ("Raw 24-bit PCM audio");
14652       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
14653        * endian later */
14654       caps = gst_caps_new_simple ("audio/x-raw",
14655           "format", G_TYPE_STRING, "S24BE",
14656           "layout", G_TYPE_STRING, "interleaved", NULL);
14657       stream->alignment = 4;
14658       break;
14659     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
14660       _codec ("Raw 32-bit PCM audio");
14661       caps = gst_caps_new_simple ("audio/x-raw",
14662           "format", G_TYPE_STRING, "S32BE",
14663           "layout", G_TYPE_STRING, "interleaved", NULL);
14664       stream->alignment = 4;
14665       break;
14666     case GST_MAKE_FOURCC ('s', '1', '6', 'l'):
14667       _codec ("Raw 16-bit PCM audio");
14668       caps = gst_caps_new_simple ("audio/x-raw",
14669           "format", G_TYPE_STRING, "S16LE",
14670           "layout", G_TYPE_STRING, "interleaved", NULL);
14671       stream->alignment = 2;
14672       break;
14673     case FOURCC_ulaw:
14674       _codec ("Mu-law audio");
14675       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
14676       break;
14677     case FOURCC_alaw:
14678       _codec ("A-law audio");
14679       caps = gst_caps_new_empty_simple ("audio/x-alaw");
14680       break;
14681     case 0x0200736d:
14682     case 0x6d730002:
14683       _codec ("Microsoft ADPCM");
14684       /* Microsoft ADPCM-ACM code 2 */
14685       caps = gst_caps_new_simple ("audio/x-adpcm",
14686           "layout", G_TYPE_STRING, "microsoft", NULL);
14687       break;
14688     case 0x1100736d:
14689     case 0x6d730011:
14690       _codec ("DVI/IMA ADPCM");
14691       caps = gst_caps_new_simple ("audio/x-adpcm",
14692           "layout", G_TYPE_STRING, "dvi", NULL);
14693       break;
14694     case 0x1700736d:
14695     case 0x6d730017:
14696       _codec ("DVI/Intel IMA ADPCM");
14697       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
14698       caps = gst_caps_new_simple ("audio/x-adpcm",
14699           "layout", G_TYPE_STRING, "quicktime", NULL);
14700       break;
14701     case 0x5500736d:
14702     case 0x6d730055:
14703       /* MPEG layer 3, CBR only (pre QT4.1) */
14704     case FOURCC__mp3:
14705       _codec ("MPEG-1 layer 3");
14706       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
14707       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
14708           "mpegversion", G_TYPE_INT, 1, NULL);
14709       break;
14710     case GST_MAKE_FOURCC ('.', 'm', 'p', '2'):
14711       _codec ("MPEG-1 layer 2");
14712       /* MPEG layer 2 */
14713       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 2,
14714           "mpegversion", G_TYPE_INT, 1, NULL);
14715       break;
14716     case 0x20736d:
14717     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
14718       _codec ("EAC-3 audio");
14719       caps = gst_caps_new_simple ("audio/x-eac3",
14720           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14721       entry->sampled = TRUE;
14722       break;
14723     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
14724     case FOURCC_ac_3:
14725       _codec ("AC-3 audio");
14726       caps = gst_caps_new_simple ("audio/x-ac3",
14727           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14728       entry->sampled = TRUE;
14729       break;
14730     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
14731     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
14732       _codec ("DTS 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 GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
14738     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
14739       _codec ("DTS-HD audio");
14740       caps = gst_caps_new_simple ("audio/x-dts",
14741           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14742       entry->sampled = TRUE;
14743       break;
14744     case FOURCC_MAC3:
14745       _codec ("MACE-3");
14746       caps = gst_caps_new_simple ("audio/x-mace",
14747           "maceversion", G_TYPE_INT, 3, NULL);
14748       break;
14749     case FOURCC_MAC6:
14750       _codec ("MACE-6");
14751       caps = gst_caps_new_simple ("audio/x-mace",
14752           "maceversion", G_TYPE_INT, 6, NULL);
14753       break;
14754     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
14755       /* ogg/vorbis */
14756       caps = gst_caps_new_empty_simple ("application/ogg");
14757       break;
14758     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
14759       _codec ("DV audio");
14760       caps = gst_caps_new_empty_simple ("audio/x-dv");
14761       break;
14762     case FOURCC_mp4a:
14763       _codec ("MPEG-4 AAC audio");
14764       caps = gst_caps_new_simple ("audio/mpeg",
14765           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
14766           "stream-format", G_TYPE_STRING, "raw", NULL);
14767       break;
14768     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
14769       _codec ("QDesign Music");
14770       caps = gst_caps_new_empty_simple ("audio/x-qdm");
14771       break;
14772     case FOURCC_QDM2:
14773       _codec ("QDesign Music v.2");
14774       /* FIXME: QDesign music version 2 (no constant) */
14775       if (FALSE && data) {
14776         caps = gst_caps_new_simple ("audio/x-qdm2",
14777             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
14778             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
14779             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
14780       } else {
14781         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
14782       }
14783       break;
14784     case FOURCC_agsm:
14785       _codec ("GSM audio");
14786       caps = gst_caps_new_empty_simple ("audio/x-gsm");
14787       break;
14788     case FOURCC_samr:
14789       _codec ("AMR audio");
14790       caps = gst_caps_new_empty_simple ("audio/AMR");
14791       break;
14792     case FOURCC_sawb:
14793       _codec ("AMR-WB audio");
14794       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
14795       break;
14796     case FOURCC_ima4:
14797       _codec ("Quicktime IMA ADPCM");
14798       caps = gst_caps_new_simple ("audio/x-adpcm",
14799           "layout", G_TYPE_STRING, "quicktime", NULL);
14800       break;
14801     case FOURCC_alac:
14802       _codec ("Apple lossless audio");
14803       caps = gst_caps_new_empty_simple ("audio/x-alac");
14804       break;
14805     case FOURCC_fLaC:
14806       _codec ("Free Lossless Audio Codec");
14807       caps = gst_caps_new_simple ("audio/x-flac",
14808           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
14809       break;
14810     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
14811       _codec ("QualComm PureVoice");
14812       caps = gst_caps_from_string ("audio/qcelp");
14813       break;
14814     case FOURCC_wma_:
14815     case FOURCC_owma:
14816       _codec ("WMA");
14817       caps = gst_caps_new_empty_simple ("audio/x-wma");
14818       break;
14819     case FOURCC_opus:
14820       _codec ("Opus");
14821       caps = gst_caps_new_empty_simple ("audio/x-opus");
14822       break;
14823     case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
14824     {
14825       guint32 flags = 0;
14826       guint32 depth = 0;
14827       guint32 width = 0;
14828       GstAudioFormat format;
14829       enum
14830       {
14831         FLAG_IS_FLOAT = 0x1,
14832         FLAG_IS_BIG_ENDIAN = 0x2,
14833         FLAG_IS_SIGNED = 0x4,
14834         FLAG_IS_PACKED = 0x8,
14835         FLAG_IS_ALIGNED_HIGH = 0x10,
14836         FLAG_IS_NON_INTERLEAVED = 0x20
14837       };
14838       _codec ("Raw LPCM audio");
14839
14840       if (data && len >= 56) {
14841         depth = QT_UINT32 (data + 40);
14842         flags = QT_UINT32 (data + 44);
14843         width = QT_UINT32 (data + 48) * 8 / entry->n_channels;
14844       }
14845       if ((flags & FLAG_IS_FLOAT) == 0) {
14846         if (depth == 0)
14847           depth = 16;
14848         if (width == 0)
14849           width = 16;
14850         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
14851             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
14852             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
14853         caps = gst_caps_new_simple ("audio/x-raw",
14854             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14855             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14856             "non-interleaved" : "interleaved", NULL);
14857         stream->alignment = GST_ROUND_UP_8 (depth);
14858         stream->alignment = round_up_pow2 (stream->alignment);
14859       } else {
14860         if (width == 0)
14861           width = 32;
14862         if (width == 64) {
14863           if (flags & FLAG_IS_BIG_ENDIAN)
14864             format = GST_AUDIO_FORMAT_F64BE;
14865           else
14866             format = GST_AUDIO_FORMAT_F64LE;
14867         } else {
14868           if (flags & FLAG_IS_BIG_ENDIAN)
14869             format = GST_AUDIO_FORMAT_F32BE;
14870           else
14871             format = GST_AUDIO_FORMAT_F32LE;
14872         }
14873         caps = gst_caps_new_simple ("audio/x-raw",
14874             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
14875             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
14876             "non-interleaved" : "interleaved", NULL);
14877         stream->alignment = width / 8;
14878       }
14879       break;
14880     }
14881     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
14882       /* ? */
14883     default:
14884     {
14885       caps = _get_unknown_codec_name ("audio", fourcc);
14886       break;
14887     }
14888   }
14889
14890   if (caps) {
14891     GstCaps *templ_caps =
14892         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
14893     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
14894     gst_caps_unref (caps);
14895     gst_caps_unref (templ_caps);
14896     caps = intersection;
14897   }
14898
14899   /* enable clipping for raw audio streams */
14900   s = gst_caps_get_structure (caps, 0);
14901   name = gst_structure_get_name (s);
14902   if (g_str_has_prefix (name, "audio/x-raw")) {
14903     stream->need_clip = TRUE;
14904     stream->max_buffer_size = 4096 * entry->bytes_per_frame;
14905     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
14906   }
14907   return caps;
14908 }
14909
14910 static GstCaps *
14911 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14912     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14913     const guint8 * stsd_entry_data, gchar ** codec_name)
14914 {
14915   GstCaps *caps;
14916
14917   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
14918
14919   switch (fourcc) {
14920     case FOURCC_mp4s:
14921       _codec ("DVD subtitle");
14922       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
14923       stream->need_process = TRUE;
14924       break;
14925     case FOURCC_text:
14926       _codec ("Quicktime timed text");
14927       goto text;
14928     case FOURCC_tx3g:
14929       _codec ("3GPP timed text");
14930     text:
14931       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
14932           "utf8", NULL);
14933       /* actual text piece needs to be extracted */
14934       stream->need_process = TRUE;
14935       break;
14936     case FOURCC_stpp:
14937       _codec ("XML subtitles");
14938       caps = gst_caps_new_empty_simple ("application/ttml+xml");
14939       break;
14940     default:
14941     {
14942       caps = _get_unknown_codec_name ("text", fourcc);
14943       break;
14944     }
14945   }
14946   return caps;
14947 }
14948
14949 static GstCaps *
14950 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
14951     QtDemuxStreamStsdEntry * entry, guint32 fourcc,
14952     const guint8 * stsd_entry_data, gchar ** codec_name)
14953 {
14954   GstCaps *caps;
14955
14956   switch (fourcc) {
14957     case FOURCC_m1v:
14958       _codec ("MPEG 1 video");
14959       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
14960           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
14961       break;
14962     default:
14963       caps = NULL;
14964       break;
14965   }
14966   return caps;
14967 }
14968
14969 static void
14970 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
14971     const gchar * system_id)
14972 {
14973   gint i;
14974
14975   if (!qtdemux->protection_system_ids)
14976     qtdemux->protection_system_ids =
14977         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
14978   /* Check whether we already have an entry for this system ID. */
14979   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
14980     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
14981     if (g_ascii_strcasecmp (system_id, id) == 0) {
14982       return;
14983     }
14984   }
14985   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
14986   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
14987           -1));
14988 }