Extract spherical video and spatial audio metadata and send it to the bus
[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  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Library General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Library General Public License for more details.
22  *
23  * You should have received a copy of the GNU Library General Public
24  * License along with this library; if not, write to the
25  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
26  * Boston, MA 02110-1301, USA.
27  */
28
29 /**
30  * SECTION:element-qtdemux
31  *
32  * Demuxes a .mov file into raw or compressed audio and/or video streams.
33  *
34  * This element supports both push and pull-based scheduling, depending on the
35  * capabilities of the upstream elements.
36  *
37  * <refsect2>
38  * <title>Example launch line</title>
39  * |[
40  * 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
41  * ]| Play (parse and decode) a .mov file and try to output it to
42  * an automatically detected soundcard and videosink. If the MOV file contains
43  * compressed audio or video data, this will only work if you have the
44  * right decoder elements/plugins installed.
45  * </refsect2>
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include "gst/gst-i18n-plugin.h"
53
54 #include <glib/gprintf.h>
55 #include <gst/tag/tag.h>
56 #include <gst/audio/audio.h>
57 #include <gst/video/video.h>
58
59 #include "qtatomparser.h"
60 #include "qtdemux_types.h"
61 #include "qtdemux_dump.h"
62 #include "fourcc.h"
63 #include "descriptors.h"
64 #include "qtdemux_lang.h"
65 #include "qtdemux.h"
66 #include "qtpalette.h"
67
68 #include "gst/riff/riff-media.h"
69 #include "gst/riff/riff-read.h"
70
71 #include <gst/pbutils/pbutils.h>
72
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76
77 #include <math.h>
78 #include <gst/math-compat.h>
79
80 #ifdef HAVE_ZLIB
81 #include <zlib.h>
82 #endif
83
84 /* max. size considered 'sane' for non-mdat atoms */
85 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
86
87 /* if the sample index is larger than this, something is likely wrong */
88 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
89
90 /* For converting qt creation times to unix epoch times */
91 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
92 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
93 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
94     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
95
96 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
97
98 GST_DEBUG_CATEGORY (qtdemux_debug);
99
100 /*typedef struct _QtNode QtNode; */
101 typedef struct _QtDemuxSegment QtDemuxSegment;
102 typedef struct _QtDemuxSample QtDemuxSample;
103
104 typedef struct _QtDemuxCencSampleSetInfo QtDemuxCencSampleSetInfo;
105
106 /*struct _QtNode
107 {
108   guint32 type;
109   guint8 *data;
110   gint len;
111 };*/
112
113 struct _QtDemuxSample
114 {
115   guint32 size;
116   gint32 pts_offset;            /* Add this value to timestamp to get the pts */
117   guint64 offset;
118   guint64 timestamp;            /* DTS In mov time */
119   guint32 duration;             /* In mov time */
120   gboolean keyframe;            /* TRUE when this packet is a keyframe */
121 };
122
123 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
124 typedef struct _QtDemuxSphericalMetadata QtDemuxSphericalMetadata;
125
126 struct _QtDemuxSphericalMetadata
127 {
128   gboolean is_spherical;
129   gboolean is_stitched;
130   char *stitching_software;
131   char *projection_type;
132   char *stereo_mode;
133   int source_count;
134   int init_view_heading;
135   int init_view_pitch;
136   int init_view_roll;
137   int timestamp;
138   int full_pano_width_pixels;
139   int full_pano_height_pixels;
140   int cropped_area_image_width;
141   int cropped_area_image_height;
142   int cropped_area_left;
143   int cropped_area_top;
144   QTDEMUX_AMBISONIC_TYPE ambisonic_type;
145   QTDEMUX_AMBISONIC_FORMAT ambisonic_format;
146   QTDEMUX_AMBISONIC_ORDER ambisonic_order;
147 };
148
149 QtDemuxSphericalMetadata *spherical_metadata;
150 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
151
152 /* Macros for converting to/from timescale */
153 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
154 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
155
156 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
157 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
158
159 /* timestamp is the DTS */
160 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
161 /* timestamp + offset is the PTS */
162 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (stream)->cslg_shift + (sample)->pts_offset))
163 /* timestamp + duration - dts is the duration */
164 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
165
166 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
167
168 /*
169  * Quicktime has tracks and segments. A track is a continuous piece of
170  * multimedia content. The track is not always played from start to finish but
171  * instead, pieces of the track are 'cut out' and played in sequence. This is
172  * what the segments do.
173  *
174  * Inside the track we have keyframes (K) and delta frames. The track has its
175  * own timing, which starts from 0 and extends to end. The position in the track
176  * is called the media_time.
177  *
178  * The segments now describe the pieces that should be played from this track
179  * and are basically tuples of media_time/duration/rate entries. We can have
180  * multiple segments and they are all played after one another. An example:
181  *
182  * segment 1: media_time: 1 second, duration: 1 second, rate 1
183  * segment 2: media_time: 3 second, duration: 2 second, rate 2
184  *
185  * To correctly play back this track, one must play: 1 second of media starting
186  * from media_time 1 followed by 2 seconds of media starting from media_time 3
187  * at a rate of 2.
188  *
189  * Each of the segments will be played at a specific time, the first segment at
190  * time 0, the second one after the duration of the first one, etc.. Note that
191  * the time in resulting playback is not identical to the media_time of the
192  * track anymore.
193  *
194  * Visually, assuming the track has 4 second of media_time:
195  *
196  *                (a)                   (b)          (c)              (d)
197  *         .-----------------------------------------------------------.
198  * track:  | K.....K.........K........K.......K.......K...........K... |
199  *         '-----------------------------------------------------------'
200  *         0              1              2              3              4
201  *           .------------^              ^   .----------^              ^
202  *          /              .-------------'  /       .------------------'
203  *         /              /          .-----'       /
204  *         .--------------.         .--------------.
205  *         | segment 1    |         | segment 2    |
206  *         '--------------'         '--------------'
207  *
208  * The challenge here is to cut out the right pieces of the track for each of
209  * the playback segments. This fortunately can easily be done with the SEGMENT
210  * events of GStreamer.
211  *
212  * For playback of segment 1, we need to provide the decoder with the keyframe
213  * (a), in the above figure, but we must instruct it only to output the decoded
214  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
215  * position set to the time of the segment: 0.
216  *
217  * We then proceed to push data from keyframe (a) to frame (b). The decoder
218  * decodes but clips all before media_time 1.
219  *
220  * After finishing a segment, we push out a new SEGMENT event with the clipping
221  * boundaries of the new data.
222  *
223  * This is a good usecase for the GStreamer accumulated SEGMENT events.
224  */
225
226 struct _QtDemuxSegment
227 {
228   /* global time and duration, all gst time */
229   GstClockTime time;
230   GstClockTime stop_time;
231   GstClockTime duration;
232   /* media time of trak, all gst time */
233   GstClockTime media_start;
234   GstClockTime media_stop;
235   gdouble rate;
236   /* Media start time in trak timescale units */
237   guint32 trak_media_start;
238 };
239
240 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
241
242 /* Used with fragmented MP4 files (mfra atom) */
243 typedef struct
244 {
245   GstClockTime ts;
246   guint64 moof_offset;
247 } QtDemuxRandomAccessEntry;
248
249 struct _QtDemuxStream
250 {
251   GstPad *pad;
252
253   /* stream type */
254   guint32 subtype;
255   GstCaps *caps;
256   guint32 fourcc;
257   gboolean sparse;
258
259   gboolean new_caps;
260   gboolean new_stream;          /* signals that a stream_start is required */
261   gboolean on_keyframe;         /* if this stream last pushed buffer was a
262                                  * keyframe. This is important to identify
263                                  * where to stop pushing buffers after a
264                                  * segment stop time */
265
266   /* if the stream has a redirect URI in its headers, we store it here */
267   gchar *redirect_uri;
268
269   /* track id */
270   guint track_id;
271
272   /* duration/scale */
273   guint64 duration;             /* in timescale */
274   guint32 timescale;
275
276   /* language */
277   gchar lang_id[4];             /* ISO 639-2T language code */
278
279   /* our samples */
280   guint32 n_samples;
281   QtDemuxSample *samples;
282   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
283   guint32 first_duration;       /* duration in timescale of first sample, used for figuring out
284                                    the framerate, in timescale units */
285   guint32 offset_in_sample;
286   guint32 max_buffer_size;
287
288   /* if we use chunks or samples */
289   gboolean sampled;
290   guint padding;
291
292   /* video info */
293   gint width;
294   gint height;
295   /* aspect ratio */
296   gint display_width;
297   gint display_height;
298   gint par_w;
299   gint par_h;
300   /* Numerator/denominator framerate */
301   gint fps_n;
302   gint fps_d;
303   guint16 bits_per_sample;
304   guint16 color_table_id;
305   GstMemory *rgb8_palette;
306
307   /* audio info */
308   gdouble rate;
309   gint n_channels;
310   guint samples_per_packet;
311   guint samples_per_frame;
312   guint bytes_per_packet;
313   guint bytes_per_sample;
314   guint bytes_per_frame;
315   guint compression;
316
317   /* allocation */
318   gboolean use_allocator;
319   GstAllocator *allocator;
320   GstAllocationParams params;
321
322   /* when a discontinuity is pending */
323   gboolean discont;
324
325   /* list of buffers to push first */
326   GSList *buffers;
327
328   /* if we need to clip this buffer. This is only needed for uncompressed
329    * data */
330   gboolean need_clip;
331
332   /* buffer needs some custom processing, e.g. subtitles */
333   gboolean need_process;
334
335   /* current position */
336   guint32 segment_index;
337   guint32 sample_index;
338   GstClockTime time_position;   /* in gst time */
339   guint64 accumulated_base;
340
341   /* the Gst segment we are processing out, used for clipping */
342   GstSegment segment;
343   guint32 segment_seqnum;       /* segment event seqnum obtained from seek */
344
345   /* quicktime segments */
346   guint32 n_segments;
347   QtDemuxSegment *segments;
348   gboolean dummy_segment;
349   guint32 from_sample;
350   guint32 to_sample;
351
352   gboolean sent_eos;
353   GstTagList *pending_tags;
354   gboolean send_global_tags;
355
356   GstEvent *pending_event;
357
358   GstByteReader stco;
359   GstByteReader stsz;
360   GstByteReader stsc;
361   GstByteReader stts;
362   GstByteReader stss;
363   GstByteReader stps;
364   GstByteReader ctts;
365
366   gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
367   gint64 stbl_index;
368   /* stco */
369   guint co_size;
370   GstByteReader co_chunk;
371   guint32 first_chunk;
372   guint32 current_chunk;
373   guint32 last_chunk;
374   guint32 samples_per_chunk;
375   guint32 stco_sample_index;
376   /* stsz */
377   guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
378   /* stsc */
379   guint32 stsc_index;
380   guint32 n_samples_per_chunk;
381   guint32 stsc_chunk_index;
382   guint32 stsc_sample_index;
383   guint64 chunk_offset;
384   /* stts */
385   guint32 stts_index;
386   guint32 stts_samples;
387   guint32 n_sample_times;
388   guint32 stts_sample_index;
389   guint64 stts_time;
390   guint32 stts_duration;
391   /* stss */
392   gboolean stss_present;
393   guint32 n_sample_syncs;
394   guint32 stss_index;
395   /* stps */
396   gboolean stps_present;
397   guint32 n_sample_partial_syncs;
398   guint32 stps_index;
399   QtDemuxRandomAccessEntry *ra_entries;
400   guint n_ra_entries;
401
402   const QtDemuxRandomAccessEntry *pending_seek;
403
404   /* ctts */
405   gboolean ctts_present;
406   guint32 n_composition_times;
407   guint32 ctts_index;
408   guint32 ctts_sample_index;
409   guint32 ctts_count;
410   gint32 ctts_soffset;
411
412   /* cslg */
413   guint32 cslg_shift;
414
415   /* fragmented */
416   gboolean parsed_trex;
417   guint32 def_sample_duration;
418   guint32 def_sample_size;
419   guint32 def_sample_flags;
420
421   gboolean disabled;
422
423   /* stereoscopic video streams */
424   GstVideoMultiviewMode multiview_mode;
425   GstVideoMultiviewFlags multiview_flags;
426
427   /* protected streams */
428   gboolean protected;
429   guint32 protection_scheme_type;
430   guint32 protection_scheme_version;
431   gpointer protection_scheme_info;      /* specific to the protection scheme */
432   GQueue protection_scheme_event_queue;
433 };
434
435 /* Contains properties and cryptographic info for a set of samples from a
436  * track protected using Common Encryption (cenc) */
437 struct _QtDemuxCencSampleSetInfo
438 {
439   GstStructure *default_properties;
440
441   /* @crypto_info holds one GstStructure per sample */
442   GPtrArray *crypto_info;
443 };
444
445 enum QtDemuxState
446 {
447   QTDEMUX_STATE_INITIAL,        /* Initial state (haven't got the header yet) */
448   QTDEMUX_STATE_HEADER,         /* Parsing the header */
449   QTDEMUX_STATE_MOVIE,          /* Parsing/Playing the media data */
450   QTDEMUX_STATE_BUFFER_MDAT     /* Buffering the mdat atom */
451 };
452
453 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
454 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
455     guint32 fourcc, GstByteReader * parser);
456 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
457 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
458     guint32 fourcc, GstByteReader * parser);
459
460 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
461
462 static GstStaticPadTemplate gst_qtdemux_sink_template =
463     GST_STATIC_PAD_TEMPLATE ("sink",
464     GST_PAD_SINK,
465     GST_PAD_ALWAYS,
466     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
467         "application/x-3gp")
468     );
469
470 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
471 GST_STATIC_PAD_TEMPLATE ("video_%u",
472     GST_PAD_SRC,
473     GST_PAD_SOMETIMES,
474     GST_STATIC_CAPS_ANY);
475
476 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
477 GST_STATIC_PAD_TEMPLATE ("audio_%u",
478     GST_PAD_SRC,
479     GST_PAD_SOMETIMES,
480     GST_STATIC_CAPS_ANY);
481
482 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
483 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
484     GST_PAD_SRC,
485     GST_PAD_SOMETIMES,
486     GST_STATIC_CAPS_ANY);
487
488 #define gst_qtdemux_parent_class parent_class
489 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
490
491 static void gst_qtdemux_dispose (GObject * object);
492
493 static guint32
494 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
495     GstClockTime media_time);
496 static guint32
497 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
498     QtDemuxStream * str, gint64 media_offset);
499
500 #if 0
501 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
502 static GstIndex *gst_qtdemux_get_index (GstElement * element);
503 #endif
504 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
505     GstStateChange transition);
506 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
507 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
508     GstObject * parent, GstPadMode mode, gboolean active);
509
510 static void gst_qtdemux_loop (GstPad * pad);
511 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
512     GstBuffer * inbuf);
513 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
514     GstEvent * event);
515 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
516 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
517     QtDemuxStream * stream);
518 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
519     gboolean force);
520
521 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
522     const guint8 * buffer, guint length);
523 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
524     const guint8 * buffer, guint length);
525 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
526 static void qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist,
527     GNode * udta);
528
529 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
530     QtDemuxStream * stream, GNode * esds, GstTagList * list);
531 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
532     QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
533     gchar ** codec_name);
534 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
535     QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
536     gchar ** codec_name);
537 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
538     QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
539     gchar ** codec_name);
540 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
541     QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
542     gchar ** codec_name);
543
544 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
545     QtDemuxStream * stream, guint32 n);
546 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
547 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
548     QtDemuxStream * stream);
549 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
550     QtDemuxStream * stream);
551 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
552 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
553 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
554     QtDemuxStream * stream);
555
556 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
557 static void check_update_duration (GstQTDemux * qtdemux, GstClockTime duration);
558
559 static void gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
560     const gchar * id);
561
562 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
563 static void gst_tag_register_spherical_tags (void);
564 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
565
566 static void
567 gst_qtdemux_class_init (GstQTDemuxClass * klass)
568 {
569   GObjectClass *gobject_class;
570   GstElementClass *gstelement_class;
571
572   gobject_class = (GObjectClass *) klass;
573   gstelement_class = (GstElementClass *) klass;
574
575   parent_class = g_type_class_peek_parent (klass);
576
577   gobject_class->dispose = gst_qtdemux_dispose;
578
579   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
580 #if 0
581   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
582   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
583 #endif
584
585   gst_tag_register_musicbrainz_tags ();
586
587 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
588   gst_tag_register_spherical_tags ();
589 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
590
591   gst_element_class_add_pad_template (gstelement_class,
592       gst_static_pad_template_get (&gst_qtdemux_sink_template));
593   gst_element_class_add_pad_template (gstelement_class,
594       gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
595   gst_element_class_add_pad_template (gstelement_class,
596       gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
597   gst_element_class_add_pad_template (gstelement_class,
598       gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
599   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
600       "Codec/Demuxer",
601       "Demultiplex a QuickTime file into audio and video streams",
602       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
603
604   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
605
606 }
607
608 static void
609 gst_qtdemux_init (GstQTDemux * qtdemux)
610 {
611   qtdemux->sinkpad =
612       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
613   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
614   gst_pad_set_activatemode_function (qtdemux->sinkpad,
615       qtdemux_sink_activate_mode);
616   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
617   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
618   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
619
620   qtdemux->state = QTDEMUX_STATE_INITIAL;
621   qtdemux->pullbased = FALSE;
622   qtdemux->posted_redirect = FALSE;
623   qtdemux->neededbytes = 16;
624   qtdemux->todrop = 0;
625   qtdemux->adapter = gst_adapter_new ();
626   qtdemux->offset = 0;
627   qtdemux->first_mdat = -1;
628   qtdemux->got_moov = FALSE;
629   qtdemux->mdatoffset = -1;
630   qtdemux->mdatbuffer = NULL;
631   qtdemux->restoredata_buffer = NULL;
632   qtdemux->restoredata_offset = -1;
633   qtdemux->fragment_start = -1;
634   qtdemux->fragment_start_offset = -1;
635   qtdemux->media_caps = NULL;
636   qtdemux->exposed = FALSE;
637   qtdemux->mss_mode = FALSE;
638   qtdemux->pending_newsegment = NULL;
639   qtdemux->upstream_format_is_time = FALSE;
640   qtdemux->have_group_id = FALSE;
641   qtdemux->group_id = G_MAXUINT;
642   qtdemux->protection_system_ids = NULL;
643   g_queue_init (&qtdemux->protection_event_queue);
644   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
645   qtdemux->flowcombiner = gst_flow_combiner_new ();
646
647 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
648   spherical_metadata = (QtDemuxSphericalMetadata *)
649       malloc (sizeof (QtDemuxSphericalMetadata));
650
651   if (spherical_metadata) {
652     spherical_metadata->is_spherical = FALSE;
653     spherical_metadata->is_stitched = FALSE;
654     spherical_metadata->stitching_software = NULL;
655     spherical_metadata->projection_type = NULL;
656     spherical_metadata->stereo_mode = NULL;
657     spherical_metadata->source_count = 0;
658     spherical_metadata->init_view_heading = 0;
659     spherical_metadata->init_view_pitch = 0;
660     spherical_metadata->init_view_roll = 0;
661     spherical_metadata->timestamp = 0;
662     spherical_metadata->full_pano_width_pixels = 0;
663     spherical_metadata->full_pano_height_pixels = 0;
664     spherical_metadata->cropped_area_image_width = 0;
665     spherical_metadata->cropped_area_image_height = 0;
666     spherical_metadata->cropped_area_left = 0;
667     spherical_metadata->cropped_area_top = 0;
668     spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
669     spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_TYPE_UNKNOWN;
670     spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_UNKNOWN;
671   }
672 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
673
674   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
675 }
676
677 static void
678 gst_qtdemux_dispose (GObject * object)
679 {
680   GstQTDemux *qtdemux = GST_QTDEMUX (object);
681
682 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
683   if (spherical_metadata->stitching_software)
684     free(spherical_metadata->stitching_software);
685   if (spherical_metadata->projection_type)
686     free(spherical_metadata->projection_type);
687   if (spherical_metadata->stereo_mode)
688     free(spherical_metadata->stereo_mode);
689   if (spherical_metadata)
690     free(spherical_metadata);
691 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
692
693   if (qtdemux->adapter) {
694     g_object_unref (G_OBJECT (qtdemux->adapter));
695     qtdemux->adapter = NULL;
696   }
697   gst_flow_combiner_free (qtdemux->flowcombiner);
698   g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
699       NULL);
700   g_queue_clear (&qtdemux->protection_event_queue);
701
702   G_OBJECT_CLASS (parent_class)->dispose (object);
703 }
704
705 static void
706 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
707 {
708   if (qtdemux->posted_redirect) {
709     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
710         (_("This file contains no playable streams.")),
711         ("no known streams found, a redirect message has been posted"));
712   } else {
713     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
714         (_("This file contains no playable streams.")),
715         ("no known streams found"));
716   }
717 }
718
719 static GstBuffer *
720 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
721 {
722   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
723       mem, size, 0, size, mem, free_func);
724 }
725
726 static GstFlowReturn
727 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
728     GstBuffer ** buf)
729 {
730   GstFlowReturn flow;
731   GstMapInfo map;
732   gsize bsize;
733
734   if (G_UNLIKELY (size == 0)) {
735     GstFlowReturn ret;
736     GstBuffer *tmp = NULL;
737
738     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
739     if (ret != GST_FLOW_OK)
740       return ret;
741
742     gst_buffer_map (tmp, &map, GST_MAP_READ);
743     size = QT_UINT32 (map.data);
744     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
745
746     gst_buffer_unmap (tmp, &map);
747     gst_buffer_unref (tmp);
748   }
749
750   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
751   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
752     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
753       /* we're pulling header but already got most interesting bits,
754        * so never mind the rest (e.g. tags) (that much) */
755       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
756           size);
757       return GST_FLOW_EOS;
758     } else {
759       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
760           (_("This file is invalid and cannot be played.")),
761           ("atom has bogus size %" G_GUINT64_FORMAT, size));
762       return GST_FLOW_ERROR;
763     }
764   }
765
766   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
767
768   if (G_UNLIKELY (flow != GST_FLOW_OK))
769     return flow;
770
771   bsize = gst_buffer_get_size (*buf);
772   /* Catch short reads - we don't want any partial atoms */
773   if (G_UNLIKELY (bsize < size)) {
774     GST_WARNING_OBJECT (qtdemux,
775         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
776     gst_buffer_unref (*buf);
777     *buf = NULL;
778     return GST_FLOW_EOS;
779   }
780
781   return flow;
782 }
783
784 #if 1
785 static gboolean
786 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
787     GstFormat dest_format, gint64 * dest_value)
788 {
789   gboolean res = TRUE;
790   QtDemuxStream *stream = gst_pad_get_element_private (pad);
791   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
792   gint32 index;
793
794   if (stream->subtype != FOURCC_vide) {
795     res = FALSE;
796     goto done;
797   }
798
799   switch (src_format) {
800     case GST_FORMAT_TIME:
801       switch (dest_format) {
802         case GST_FORMAT_BYTES:{
803           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
804           if (-1 == index)
805             return FALSE;
806
807           *dest_value = stream->samples[index].offset;
808
809           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
810               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
811               GST_TIME_ARGS (src_value), *dest_value);
812           break;
813         }
814         default:
815           res = FALSE;
816           break;
817       }
818       break;
819     case GST_FORMAT_BYTES:
820       switch (dest_format) {
821         case GST_FORMAT_TIME:{
822           index =
823               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
824               stream, src_value);
825
826           if (-1 == index)
827             return FALSE;
828
829           *dest_value =
830               QTSTREAMTIME_TO_GSTTIME (stream,
831               stream->samples[index].timestamp);
832           GST_DEBUG_OBJECT (qtdemux,
833               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
834               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
835           break;
836         }
837         default:
838           res = FALSE;
839           break;
840       }
841       break;
842     default:
843       res = FALSE;
844   }
845
846 done:
847   gst_object_unref (qtdemux);
848
849   return res;
850 }
851 #endif
852
853 static gboolean
854 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
855 {
856   gboolean res = TRUE;
857
858   *duration = GST_CLOCK_TIME_NONE;
859
860   if (qtdemux->duration != 0) {
861     if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
862       *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
863     }
864   }
865   return res;
866 }
867
868 static gboolean
869 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
870     GstQuery * query)
871 {
872   gboolean res = FALSE;
873   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
874
875   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
876
877   switch (GST_QUERY_TYPE (query)) {
878     case GST_QUERY_POSITION:{
879       GstFormat fmt;
880
881       gst_query_parse_position (query, &fmt, NULL);
882       if (fmt == GST_FORMAT_TIME
883           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
884         gst_query_set_position (query, GST_FORMAT_TIME,
885             qtdemux->segment.position);
886         res = TRUE;
887       }
888     }
889       break;
890     case GST_QUERY_DURATION:{
891       GstFormat fmt;
892
893       gst_query_parse_duration (query, &fmt, NULL);
894       if (fmt == GST_FORMAT_TIME) {
895         /* First try to query upstream */
896         res = gst_pad_query_default (pad, parent, query);
897         if (!res) {
898           guint64 duration;
899           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
900             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
901             res = TRUE;
902           }
903         }
904       }
905       break;
906     }
907     case GST_QUERY_CONVERT:{
908       GstFormat src_fmt, dest_fmt;
909       gint64 src_value, dest_value = 0;
910
911       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
912
913       res = gst_qtdemux_src_convert (pad,
914           src_fmt, src_value, dest_fmt, &dest_value);
915       if (res) {
916         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
917         res = TRUE;
918       }
919       break;
920     }
921     case GST_QUERY_FORMATS:
922       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
923       res = TRUE;
924       break;
925     case GST_QUERY_SEEKING:{
926       GstFormat fmt;
927       gboolean seekable;
928
929       /* try upstream first */
930       res = gst_pad_query_default (pad, parent, query);
931
932       if (!res) {
933         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
934         if (fmt == GST_FORMAT_TIME) {
935           GstClockTime duration = GST_CLOCK_TIME_NONE;
936
937           gst_qtdemux_get_duration (qtdemux, &duration);
938           seekable = TRUE;
939           if (!qtdemux->pullbased) {
940             GstQuery *q;
941
942             /* we might be able with help from upstream */
943             seekable = FALSE;
944             q = gst_query_new_seeking (GST_FORMAT_BYTES);
945             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
946               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
947               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
948             }
949             gst_query_unref (q);
950           }
951           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
952           res = TRUE;
953         }
954       }
955       break;
956     }
957     case GST_QUERY_SEGMENT:
958     {
959       GstFormat format;
960       gint64 start, stop;
961
962       format = qtdemux->segment.format;
963
964       start =
965           gst_segment_to_stream_time (&qtdemux->segment, format,
966           qtdemux->segment.start);
967       if ((stop = qtdemux->segment.stop) == -1)
968         stop = qtdemux->segment.duration;
969       else
970         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
971
972       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
973       res = TRUE;
974       break;
975     }
976     default:
977       res = gst_pad_query_default (pad, parent, query);
978       break;
979   }
980
981   return res;
982 }
983
984 static void
985 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
986 {
987   if (G_LIKELY (stream->pad)) {
988     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
989         GST_DEBUG_PAD_NAME (stream->pad));
990
991     if (G_UNLIKELY (stream->pending_tags)) {
992       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
993           stream->pending_tags);
994       gst_pad_push_event (stream->pad,
995           gst_event_new_tag (stream->pending_tags));
996 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
997       /* post message qtdemux tag (for early recive application) */
998       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
999             gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
1000                   gst_tag_list_copy (stream->pending_tags)));
1001 #endif
1002       stream->pending_tags = NULL;
1003     }
1004
1005     if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
1006       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
1007           qtdemux->tag_list);
1008       gst_pad_push_event (stream->pad,
1009           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
1010       stream->send_global_tags = FALSE;
1011     }
1012   }
1013 }
1014
1015 /* push event on all source pads; takes ownership of the event */
1016 static void
1017 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
1018 {
1019   guint n;
1020   gboolean has_valid_stream = FALSE;
1021   GstEventType etype = GST_EVENT_TYPE (event);
1022
1023   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
1024       GST_EVENT_TYPE_NAME (event));
1025
1026   for (n = 0; n < qtdemux->n_streams; n++) {
1027     GstPad *pad;
1028     QtDemuxStream *stream = qtdemux->streams[n];
1029     GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
1030
1031     if ((pad = stream->pad)) {
1032       has_valid_stream = TRUE;
1033
1034       if (etype == GST_EVENT_EOS) {
1035         /* let's not send twice */
1036         if (stream->sent_eos)
1037           continue;
1038         stream->sent_eos = TRUE;
1039       }
1040
1041       gst_pad_push_event (pad, gst_event_ref (event));
1042     }
1043   }
1044
1045   gst_event_unref (event);
1046
1047   /* if it is EOS and there are no pads, post an error */
1048   if (!has_valid_stream && etype == GST_EVENT_EOS) {
1049     gst_qtdemux_post_no_playable_stream_error (qtdemux);
1050   }
1051 }
1052
1053 /* push a pending newsegment event, if any from the streaming thread */
1054 static void
1055 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
1056 {
1057   if (qtdemux->pending_newsegment) {
1058     gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
1059     qtdemux->pending_newsegment = NULL;
1060   }
1061 }
1062
1063 typedef struct
1064 {
1065   guint64 media_time;
1066 } FindData;
1067
1068 static gint
1069 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
1070 {
1071   if (s1->timestamp + s1->pts_offset > *media_time)
1072     return 1;
1073
1074   return -1;
1075 }
1076
1077 /* find the index of the sample that includes the data for @media_time using a
1078  * binary search.  Only to be called in optimized cases of linear search below.
1079  *
1080  * Returns the index of the sample.
1081  */
1082 static guint32
1083 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
1084     guint64 media_time)
1085 {
1086   QtDemuxSample *result;
1087   guint32 index;
1088
1089   /* convert media_time to mov format */
1090   media_time =
1091       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1092
1093   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
1094       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
1095       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
1096
1097   if (G_LIKELY (result))
1098     index = result - str->samples;
1099   else
1100     index = 0;
1101
1102   return index;
1103 }
1104
1105
1106
1107 /* find the index of the sample that includes the data for @media_offset using a
1108  * linear search
1109  *
1110  * Returns the index of the sample.
1111  */
1112 static guint32
1113 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
1114     QtDemuxStream * str, gint64 media_offset)
1115 {
1116   QtDemuxSample *result = str->samples;
1117   guint32 index = 0;
1118
1119   if (result == NULL || str->n_samples == 0)
1120     return -1;
1121
1122   if (media_offset == result->offset)
1123     return index;
1124
1125   result++;
1126   while (index < str->n_samples - 1) {
1127     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1128       goto parse_failed;
1129
1130     if (media_offset < result->offset)
1131       break;
1132
1133     index++;
1134     result++;
1135   }
1136   return index;
1137
1138   /* ERRORS */
1139 parse_failed:
1140   {
1141     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1142     return -1;
1143   }
1144 }
1145
1146 /* find the index of the sample that includes the data for @media_time using a
1147  * linear search, and keeping in mind that not all samples may have been parsed
1148  * yet.  If possible, it will delegate to binary search.
1149  *
1150  * Returns the index of the sample.
1151  */
1152 static guint32
1153 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1154     GstClockTime media_time)
1155 {
1156   guint32 index = 0;
1157   guint64 mov_time;
1158   QtDemuxSample *sample;
1159
1160   /* convert media_time to mov format */
1161   mov_time =
1162       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1163
1164   sample = str->samples;
1165   if (mov_time == sample->timestamp + sample->pts_offset)
1166     return index;
1167
1168   /* use faster search if requested time in already parsed range */
1169   sample = str->samples + str->stbl_index;
1170   if (str->stbl_index >= 0 &&
1171       mov_time <= (sample->timestamp + sample->pts_offset))
1172     return gst_qtdemux_find_index (qtdemux, str, media_time);
1173
1174   while (index < str->n_samples - 1) {
1175     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1176       goto parse_failed;
1177
1178     sample = str->samples + index + 1;
1179     if (mov_time < (sample->timestamp + sample->pts_offset))
1180       break;
1181
1182     index++;
1183   }
1184   return index;
1185
1186   /* ERRORS */
1187 parse_failed:
1188   {
1189     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1190     return -1;
1191   }
1192 }
1193
1194 /* find the index of the keyframe needed to decode the sample at @index
1195  * of stream @str.
1196  *
1197  * Returns the index of the keyframe.
1198  */
1199 static guint32
1200 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1201     guint32 index)
1202 {
1203   guint32 new_index = index;
1204
1205   if (index >= str->n_samples) {
1206     new_index = str->n_samples;
1207     goto beach;
1208   }
1209
1210   /* all keyframes, return index */
1211   if (str->all_keyframe) {
1212     new_index = index;
1213     goto beach;
1214   }
1215
1216   /* else go back until we have a keyframe */
1217   while (TRUE) {
1218     if (str->samples[new_index].keyframe)
1219       break;
1220
1221     if (new_index == 0)
1222       break;
1223
1224     new_index--;
1225   }
1226
1227 beach:
1228   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1229       "gave %u", index, new_index);
1230
1231   return new_index;
1232 }
1233
1234 /* find the segment for @time_position for @stream
1235  *
1236  * Returns the index of the segment containing @time_position.
1237  * Returns the last segment and sets the @eos variable to TRUE
1238  * if the time is beyond the end. @eos may be NULL
1239  */
1240 static guint32
1241 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1242     GstClockTime time_position)
1243 {
1244   gint i;
1245   guint32 seg_idx;
1246
1247   GST_LOG_OBJECT (stream->pad, "finding segment for %" GST_TIME_FORMAT,
1248       GST_TIME_ARGS (time_position));
1249
1250   seg_idx = -1;
1251   for (i = 0; i < stream->n_segments; i++) {
1252     QtDemuxSegment *segment = &stream->segments[i];
1253
1254     GST_LOG_OBJECT (stream->pad,
1255         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1256         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1257
1258     /* For the last segment we include stop_time in the last segment */
1259     if (i < stream->n_segments - 1) {
1260       if (segment->time <= time_position && time_position < segment->stop_time) {
1261         GST_LOG_OBJECT (stream->pad, "segment %d matches", i);
1262         seg_idx = i;
1263         break;
1264       }
1265     } else {
1266       /* Last segment always matches */
1267       seg_idx = i;
1268       break;
1269     }
1270   }
1271   return seg_idx;
1272 }
1273
1274 /* move the stream @str to the sample position @index.
1275  *
1276  * Updates @str->sample_index and marks discontinuity if needed.
1277  */
1278 static void
1279 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1280     guint32 index)
1281 {
1282   /* no change needed */
1283   if (index == str->sample_index)
1284     return;
1285
1286   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1287       str->n_samples);
1288
1289   /* position changed, we have a discont */
1290   str->sample_index = index;
1291   str->offset_in_sample = 0;
1292   /* Each time we move in the stream we store the position where we are
1293    * starting from */
1294   str->from_sample = index;
1295   str->discont = TRUE;
1296 }
1297
1298 static void
1299 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1300     gboolean use_sparse, gint64 * key_time, gint64 * key_offset)
1301 {
1302   guint64 min_offset;
1303   gint64 min_byte_offset = -1;
1304   gint n;
1305
1306   min_offset = desired_time;
1307
1308   /* for each stream, find the index of the sample in the segment
1309    * and move back to the previous keyframe. */
1310   for (n = 0; n < qtdemux->n_streams; n++) {
1311     QtDemuxStream *str;
1312     guint32 index, kindex;
1313     guint32 seg_idx;
1314     GstClockTime media_start;
1315     GstClockTime media_time;
1316     GstClockTime seg_time;
1317     QtDemuxSegment *seg;
1318
1319     str = qtdemux->streams[n];
1320
1321     if (str->sparse && !use_sparse)
1322       continue;
1323
1324     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1325     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1326
1327     /* get segment and time in the segment */
1328     seg = &str->segments[seg_idx];
1329     seg_time = desired_time - seg->time;
1330
1331     /* get the media time in the segment */
1332     media_start = seg->media_start + seg_time;
1333
1334     /* get the index of the sample with media time */
1335     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1336     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1337         " at offset %" G_GUINT64_FORMAT,
1338         GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1339
1340     /* find previous keyframe */
1341     kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1342
1343     /* if the keyframe is at a different position, we need to update the
1344      * requested seek time */
1345     if (index != kindex) {
1346       index = kindex;
1347
1348       /* get timestamp of keyframe */
1349       media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1350       GST_DEBUG_OBJECT (qtdemux,
1351           "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1352           G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1353           str->samples[kindex].offset);
1354
1355       /* keyframes in the segment get a chance to change the
1356        * desired_offset. keyframes out of the segment are
1357        * ignored. */
1358       if (media_time >= seg->media_start) {
1359         GstClockTime seg_time;
1360
1361         /* this keyframe is inside the segment, convert back to
1362          * segment time */
1363         seg_time = (media_time - seg->media_start) + seg->time;
1364         if (seg_time < min_offset)
1365           min_offset = seg_time;
1366       }
1367     }
1368
1369     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1370       min_byte_offset = str->samples[index].offset;
1371   }
1372
1373   if (key_time)
1374     *key_time = min_offset;
1375   if (key_offset)
1376     *key_offset = min_byte_offset;
1377 }
1378
1379 static gboolean
1380 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1381     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1382 {
1383   gboolean res;
1384
1385   g_return_val_if_fail (format != NULL, FALSE);
1386   g_return_val_if_fail (cur != NULL, FALSE);
1387   g_return_val_if_fail (stop != NULL, FALSE);
1388
1389   if (*format == GST_FORMAT_TIME)
1390     return TRUE;
1391
1392   res = TRUE;
1393   if (cur_type != GST_SEEK_TYPE_NONE)
1394     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1395   if (res && stop_type != GST_SEEK_TYPE_NONE)
1396     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1397
1398   if (res)
1399     *format = GST_FORMAT_TIME;
1400
1401   return res;
1402 }
1403
1404 /* perform seek in push based mode:
1405    find BYTE position to move to based on time and delegate to upstream
1406 */
1407 static gboolean
1408 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1409 {
1410   gdouble rate;
1411   GstFormat format;
1412   GstSeekFlags flags;
1413   GstSeekType cur_type, stop_type;
1414   gint64 cur, stop, key_cur;
1415   gboolean res;
1416   gint64 byte_cur;
1417   gint64 original_stop;
1418   guint32 seqnum;
1419
1420   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1421
1422   gst_event_parse_seek (event, &rate, &format, &flags,
1423       &cur_type, &cur, &stop_type, &stop);
1424   seqnum = gst_event_get_seqnum (event);
1425
1426   /* only forward streaming and seeking is possible */
1427   if (rate <= 0)
1428     goto unsupported_seek;
1429
1430   /* convert to TIME if needed and possible */
1431   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1432           stop_type, &stop))
1433     goto no_format;
1434
1435   /* Upstream seek in bytes will have undefined stop, but qtdemux stores
1436    * the original stop position to use when upstream pushes the new segment
1437    * for this seek */
1438   original_stop = stop;
1439   stop = -1;
1440
1441   /* find reasonable corresponding BYTE position,
1442    * also try to mind about keyframes, since we can not go back a bit for them
1443    * later on */
1444   gst_qtdemux_adjust_seek (qtdemux, cur, FALSE, &key_cur, &byte_cur);
1445
1446   if (byte_cur == -1)
1447     goto abort_seek;
1448
1449   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1450       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1451       stop);
1452
1453   GST_OBJECT_LOCK (qtdemux);
1454   qtdemux->seek_offset = byte_cur;
1455   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1456     qtdemux->push_seek_start = cur;
1457   } else {
1458     qtdemux->push_seek_start = key_cur;
1459   }
1460
1461   if (stop_type == GST_SEEK_TYPE_NONE) {
1462     qtdemux->push_seek_stop = qtdemux->segment.stop;
1463   } else {
1464     qtdemux->push_seek_stop = original_stop;
1465   }
1466   GST_OBJECT_UNLOCK (qtdemux);
1467
1468   /* BYTE seek event */
1469   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1470       stop_type, stop);
1471   gst_event_set_seqnum (event, seqnum);
1472   res = gst_pad_push_event (qtdemux->sinkpad, event);
1473
1474   return res;
1475
1476   /* ERRORS */
1477 abort_seek:
1478   {
1479     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1480         "seek aborted.");
1481     return FALSE;
1482   }
1483 unsupported_seek:
1484   {
1485     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1486     return FALSE;
1487   }
1488 no_format:
1489   {
1490     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1491     return FALSE;
1492   }
1493 }
1494
1495 /* perform the seek.
1496  *
1497  * We set all segment_indexes in the streams to unknown and
1498  * adjust the time_position to the desired position. this is enough
1499  * to trigger a segment switch in the streaming thread to start
1500  * streaming from the desired position.
1501  *
1502  * Keyframe seeking is a little more complicated when dealing with
1503  * segments. Ideally we want to move to the previous keyframe in
1504  * the segment but there might not be a keyframe in the segment. In
1505  * fact, none of the segments could contain a keyframe. We take a
1506  * practical approach: seek to the previous keyframe in the segment,
1507  * if there is none, seek to the beginning of the segment.
1508  *
1509  * Called with STREAM_LOCK
1510  */
1511 static gboolean
1512 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1513     guint32 seqnum, GstSeekFlags flags)
1514 {
1515   gint64 desired_offset;
1516   gint n;
1517
1518   desired_offset = segment->position;
1519
1520   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1521       GST_TIME_ARGS (desired_offset));
1522
1523   /* may not have enough fragmented info to do this adjustment,
1524    * and we can't scan (and probably should not) at this time with
1525    * possibly flushing upstream */
1526   if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1527     gint64 min_offset;
1528
1529     gst_qtdemux_adjust_seek (qtdemux, desired_offset, TRUE, &min_offset, NULL);
1530     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1531         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1532     desired_offset = min_offset;
1533   }
1534
1535   /* and set all streams to the final position */
1536   gst_flow_combiner_reset (qtdemux->flowcombiner);
1537   for (n = 0; n < qtdemux->n_streams; n++) {
1538     QtDemuxStream *stream = qtdemux->streams[n];
1539
1540     stream->time_position = desired_offset;
1541     stream->accumulated_base = 0;
1542     stream->sample_index = -1;
1543     stream->offset_in_sample = 0;
1544     stream->segment_index = -1;
1545     stream->sent_eos = FALSE;
1546     stream->segment_seqnum = seqnum;
1547
1548     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1549       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1550   }
1551   segment->position = desired_offset;
1552   segment->time = desired_offset;
1553   if (segment->rate >= 0) {
1554     segment->start = desired_offset;
1555
1556     /* we stop at the end */
1557     if (segment->stop == -1)
1558       segment->stop = segment->duration;
1559   } else {
1560     segment->stop = desired_offset;
1561   }
1562
1563   if (qtdemux->fragmented)
1564     qtdemux->fragmented_seek_pending = TRUE;
1565
1566   return TRUE;
1567 }
1568
1569 /* do a seek in pull based mode */
1570 static gboolean
1571 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1572 {
1573   gdouble rate;
1574   GstFormat format;
1575   GstSeekFlags flags;
1576   GstSeekType cur_type, stop_type;
1577   gint64 cur, stop;
1578   gboolean flush;
1579   gboolean update;
1580   GstSegment seeksegment;
1581   guint32 seqnum = 0;
1582   GstEvent *flush_event;
1583
1584   if (event) {
1585     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1586
1587     gst_event_parse_seek (event, &rate, &format, &flags,
1588         &cur_type, &cur, &stop_type, &stop);
1589     seqnum = gst_event_get_seqnum (event);
1590
1591     /* we have to have a format as the segment format. Try to convert
1592      * if not. */
1593     if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1594             stop_type, &stop))
1595       goto no_format;
1596
1597     GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1598   } else {
1599     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1600     flags = 0;
1601   }
1602
1603   flush = flags & GST_SEEK_FLAG_FLUSH;
1604
1605   /* stop streaming, either by flushing or by pausing the task */
1606   if (flush) {
1607     flush_event = gst_event_new_flush_start ();
1608     if (seqnum)
1609       gst_event_set_seqnum (flush_event, seqnum);
1610     /* unlock upstream pull_range */
1611     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1612     /* make sure out loop function exits */
1613     gst_qtdemux_push_event (qtdemux, flush_event);
1614   } else {
1615     /* non flushing seek, pause the task */
1616     gst_pad_pause_task (qtdemux->sinkpad);
1617   }
1618
1619   /* wait for streaming to finish */
1620   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1621
1622   /* copy segment, we need this because we still need the old
1623    * segment when we close the current segment. */
1624   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1625
1626   if (event) {
1627     /* configure the segment with the seek variables */
1628     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1629     gst_segment_do_seek (&seeksegment, rate, format, flags,
1630         cur_type, cur, stop_type, stop, &update);
1631   }
1632
1633   /* now do the seek, this actually never returns FALSE */
1634   gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum, flags);
1635
1636   /* prepare for streaming again */
1637   if (flush) {
1638     flush_event = gst_event_new_flush_stop (TRUE);
1639     if (seqnum)
1640       gst_event_set_seqnum (flush_event, seqnum);
1641
1642     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1643     gst_qtdemux_push_event (qtdemux, flush_event);
1644   }
1645
1646   /* commit the new segment */
1647   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1648
1649   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1650     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1651         qtdemux->segment.format, qtdemux->segment.position);
1652     if (seqnum)
1653       gst_message_set_seqnum (msg, seqnum);
1654     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1655   }
1656
1657   /* restart streaming, NEWSEGMENT will be sent from the streaming thread. */
1658   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1659       qtdemux->sinkpad, NULL);
1660
1661   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1662
1663   return TRUE;
1664
1665   /* ERRORS */
1666 no_format:
1667   {
1668     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1669     return FALSE;
1670   }
1671 }
1672
1673 static gboolean
1674 qtdemux_ensure_index (GstQTDemux * qtdemux)
1675 {
1676   guint i;
1677
1678   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1679
1680   /* Build complete index */
1681   for (i = 0; i < qtdemux->n_streams; i++) {
1682     QtDemuxStream *stream = qtdemux->streams[i];
1683
1684     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1685       goto parse_error;
1686   }
1687   return TRUE;
1688
1689   /* ERRORS */
1690 parse_error:
1691   {
1692     GST_LOG_OBJECT (qtdemux,
1693         "Building complete index of stream %u for seeking failed!", i);
1694     return FALSE;
1695   }
1696 }
1697
1698 static gboolean
1699 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1700     GstEvent * event)
1701 {
1702   gboolean res = TRUE;
1703   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1704
1705   switch (GST_EVENT_TYPE (event)) {
1706     case GST_EVENT_SEEK:
1707     {
1708 #ifndef GST_DISABLE_GST_DEBUG
1709       GstClockTime ts = gst_util_get_timestamp ();
1710 #endif
1711
1712       if (qtdemux->upstream_format_is_time && qtdemux->fragmented) {
1713         /* seek should be handled by upstream, we might need to re-download fragments */
1714         GST_DEBUG_OBJECT (qtdemux,
1715             "let upstream handle seek for fragmented playback");
1716         goto upstream;
1717       }
1718
1719       /* Build complete index for seeking;
1720        * if not a fragmented file at least */
1721       if (!qtdemux->fragmented)
1722         if (!qtdemux_ensure_index (qtdemux))
1723           goto index_failed;
1724 #ifndef GST_DISABLE_GST_DEBUG
1725       ts = gst_util_get_timestamp () - ts;
1726       GST_INFO_OBJECT (qtdemux,
1727           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1728 #endif
1729     }
1730       if (qtdemux->pullbased) {
1731         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1732       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1733         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1734         res = TRUE;
1735       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1736           && !qtdemux->fragmented) {
1737         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1738       } else {
1739         GST_DEBUG_OBJECT (qtdemux,
1740             "ignoring seek in push mode in current state");
1741         res = FALSE;
1742       }
1743       gst_event_unref (event);
1744       break;
1745     case GST_EVENT_QOS:
1746     case GST_EVENT_NAVIGATION:
1747       res = FALSE;
1748       gst_event_unref (event);
1749       break;
1750     default:
1751     upstream:
1752       res = gst_pad_event_default (pad, parent, event);
1753       break;
1754   }
1755
1756 done:
1757   return res;
1758
1759   /* ERRORS */
1760 index_failed:
1761   {
1762     GST_ERROR_OBJECT (qtdemux, "Index failed");
1763     gst_event_unref (event);
1764     res = FALSE;
1765     goto done;
1766   }
1767 }
1768
1769 /* stream/index return sample that is min/max w.r.t. byte position,
1770  * time is min/max w.r.t. time of samples,
1771  * the latter need not be time of the former sample */
1772 static void
1773 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1774     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1775 {
1776   gint i, n, index;
1777   gint64 time, min_time;
1778   QtDemuxStream *stream;
1779
1780   min_time = -1;
1781   stream = NULL;
1782   index = -1;
1783
1784   for (n = 0; n < qtdemux->n_streams; ++n) {
1785     QtDemuxStream *str;
1786     gint inc;
1787     gboolean set_sample;
1788
1789     str = qtdemux->streams[n];
1790     set_sample = !set;
1791
1792     if (fw) {
1793       i = 0;
1794       inc = 1;
1795     } else {
1796       i = str->n_samples - 1;
1797       inc = -1;
1798     }
1799
1800     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1801       if (str->samples[i].size == 0)
1802         continue;
1803
1804       if (fw && (str->samples[i].offset < byte_pos))
1805         continue;
1806
1807       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1808         continue;
1809
1810       /* move stream to first available sample */
1811       if (set) {
1812         gst_qtdemux_move_stream (qtdemux, str, i);
1813         set_sample = TRUE;
1814       }
1815
1816       /* avoid index from sparse streams since they might be far away */
1817       if (!str->sparse) {
1818         /* determine min/max time */
1819         time = QTSAMPLE_PTS (str, &str->samples[i]);
1820         if (min_time == -1 || (!fw && time > min_time) ||
1821             (fw && time < min_time)) {
1822           min_time = time;
1823         }
1824
1825         /* determine stream with leading sample, to get its position */
1826         if (!stream ||
1827             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1828             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1829           stream = str;
1830           index = i;
1831         }
1832       }
1833       break;
1834     }
1835
1836     /* no sample for this stream, mark eos */
1837     if (!set_sample)
1838       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1839   }
1840
1841   if (_time)
1842     *_time = min_time;
1843   if (_stream)
1844     *_stream = stream;
1845   if (_index)
1846     *_index = index;
1847 }
1848
1849 static QtDemuxStream *
1850 _create_stream (void)
1851 {
1852   QtDemuxStream *stream;
1853
1854   stream = g_new0 (QtDemuxStream, 1);
1855   /* new streams always need a discont */
1856   stream->discont = TRUE;
1857   /* we enable clipping for raw audio/video streams */
1858   stream->need_clip = FALSE;
1859   stream->need_process = FALSE;
1860   stream->segment_index = -1;
1861   stream->time_position = 0;
1862   stream->sample_index = -1;
1863   stream->offset_in_sample = 0;
1864   stream->new_stream = TRUE;
1865   stream->multiview_mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
1866   stream->multiview_flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
1867   stream->protected = FALSE;
1868   stream->protection_scheme_type = 0;
1869   stream->protection_scheme_version = 0;
1870   stream->protection_scheme_info = NULL;
1871   g_queue_init (&stream->protection_scheme_event_queue);
1872   return stream;
1873 }
1874
1875 static gboolean
1876 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1877 {
1878   GstStructure *structure;
1879   const gchar *variant;
1880   const GstCaps *mediacaps = NULL;
1881
1882   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1883
1884   structure = gst_caps_get_structure (caps, 0);
1885   variant = gst_structure_get_string (structure, "variant");
1886
1887   if (variant && strcmp (variant, "mss-fragmented") == 0) {
1888     QtDemuxStream *stream;
1889     const GValue *value;
1890
1891     demux->fragmented = TRUE;
1892     demux->mss_mode = TRUE;
1893
1894     if (demux->n_streams > 1) {
1895       /* can't do this, we can only renegotiate for another mss format */
1896       return FALSE;
1897     }
1898
1899     value = gst_structure_get_value (structure, "media-caps");
1900     /* create stream */
1901     if (value) {
1902       const GValue *timescale_v;
1903
1904       /* TODO update when stream changes during playback */
1905
1906       if (demux->n_streams == 0) {
1907         stream = _create_stream ();
1908         demux->streams[demux->n_streams] = stream;
1909         demux->n_streams = 1;
1910       } else {
1911         stream = demux->streams[0];
1912       }
1913
1914       timescale_v = gst_structure_get_value (structure, "timescale");
1915       if (timescale_v) {
1916         stream->timescale = g_value_get_uint64 (timescale_v);
1917       } else {
1918         /* default mss timescale */
1919         stream->timescale = 10000000;
1920       }
1921       demux->timescale = stream->timescale;
1922
1923       mediacaps = gst_value_get_caps (value);
1924       if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1925         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1926             mediacaps);
1927         stream->new_caps = TRUE;
1928       }
1929       gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1930       structure = gst_caps_get_structure (mediacaps, 0);
1931       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1932         stream->subtype = FOURCC_vide;
1933
1934         gst_structure_get_int (structure, "width", &stream->width);
1935         gst_structure_get_int (structure, "height", &stream->height);
1936         gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1937             &stream->fps_d);
1938       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1939         gint rate = 0;
1940         stream->subtype = FOURCC_soun;
1941         gst_structure_get_int (structure, "channels", &stream->n_channels);
1942         gst_structure_get_int (structure, "rate", &rate);
1943         stream->rate = rate;
1944       }
1945     }
1946     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1947   } else {
1948     demux->mss_mode = FALSE;
1949   }
1950
1951   return TRUE;
1952 }
1953
1954 static void
1955 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1956 {
1957   gint n;
1958
1959   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1960   gst_pad_stop_task (qtdemux->sinkpad);
1961
1962   if (hard || qtdemux->upstream_format_is_time) {
1963     qtdemux->state = QTDEMUX_STATE_INITIAL;
1964     qtdemux->neededbytes = 16;
1965     qtdemux->todrop = 0;
1966     qtdemux->pullbased = FALSE;
1967     qtdemux->posted_redirect = FALSE;
1968     qtdemux->first_mdat = -1;
1969     qtdemux->header_size = 0;
1970     qtdemux->mdatoffset = -1;
1971     qtdemux->restoredata_offset = -1;
1972     if (qtdemux->mdatbuffer)
1973       gst_buffer_unref (qtdemux->mdatbuffer);
1974     if (qtdemux->restoredata_buffer)
1975       gst_buffer_unref (qtdemux->restoredata_buffer);
1976     qtdemux->mdatbuffer = NULL;
1977     qtdemux->restoredata_buffer = NULL;
1978     qtdemux->mdatleft = 0;
1979     if (qtdemux->comp_brands)
1980       gst_buffer_unref (qtdemux->comp_brands);
1981     qtdemux->comp_brands = NULL;
1982     qtdemux->last_moov_offset = -1;
1983     if (qtdemux->moov_node)
1984       g_node_destroy (qtdemux->moov_node);
1985     qtdemux->moov_node = NULL;
1986     qtdemux->moov_node_compressed = NULL;
1987     if (qtdemux->tag_list)
1988       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1989     qtdemux->tag_list = NULL;
1990 #if 0
1991     if (qtdemux->element_index)
1992       gst_object_unref (qtdemux->element_index);
1993     qtdemux->element_index = NULL;
1994 #endif
1995     qtdemux->major_brand = 0;
1996     if (qtdemux->pending_newsegment)
1997       gst_event_unref (qtdemux->pending_newsegment);
1998     qtdemux->pending_newsegment = NULL;
1999     qtdemux->upstream_format_is_time = FALSE;
2000     qtdemux->upstream_seekable = FALSE;
2001     qtdemux->upstream_size = 0;
2002
2003     qtdemux->fragment_start = -1;
2004     qtdemux->fragment_start_offset = -1;
2005     qtdemux->duration = 0;
2006     qtdemux->moof_offset = 0;
2007     qtdemux->chapters_track_id = 0;
2008     qtdemux->have_group_id = FALSE;
2009     qtdemux->group_id = G_MAXUINT;
2010
2011     if (qtdemux->protection_system_ids) {
2012       g_ptr_array_free (qtdemux->protection_system_ids, TRUE);
2013       qtdemux->protection_system_ids = NULL;
2014     }
2015     g_queue_foreach (&qtdemux->protection_event_queue, (GFunc) gst_event_unref,
2016         NULL);
2017     g_queue_clear (&qtdemux->protection_event_queue);
2018   }
2019   qtdemux->offset = 0;
2020   gst_adapter_clear (qtdemux->adapter);
2021   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
2022
2023   if (hard) {
2024     for (n = 0; n < qtdemux->n_streams; n++) {
2025       gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
2026       qtdemux->streams[n] = NULL;
2027     }
2028     qtdemux->n_streams = 0;
2029     qtdemux->n_video_streams = 0;
2030     qtdemux->n_audio_streams = 0;
2031     qtdemux->n_sub_streams = 0;
2032     qtdemux->exposed = FALSE;
2033     qtdemux->fragmented = FALSE;
2034     qtdemux->mss_mode = FALSE;
2035     gst_caps_replace (&qtdemux->media_caps, NULL);
2036     qtdemux->timescale = 0;
2037     qtdemux->got_moov = FALSE;
2038   } else if (qtdemux->mss_mode) {
2039     gst_flow_combiner_reset (qtdemux->flowcombiner);
2040     for (n = 0; n < qtdemux->n_streams; n++)
2041       gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
2042   } else {
2043     gst_flow_combiner_reset (qtdemux->flowcombiner);
2044     for (n = 0; n < qtdemux->n_streams; n++) {
2045       qtdemux->streams[n]->sent_eos = FALSE;
2046       qtdemux->streams[n]->segment_seqnum = 0;
2047       qtdemux->streams[n]->time_position = 0;
2048       qtdemux->streams[n]->accumulated_base = 0;
2049     }
2050   }
2051 }
2052
2053 static gboolean
2054 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
2055     GstEvent * event)
2056 {
2057   GstQTDemux *demux = GST_QTDEMUX (parent);
2058   gboolean res = TRUE;
2059
2060   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
2061
2062   switch (GST_EVENT_TYPE (event)) {
2063     case GST_EVENT_SEGMENT:
2064     {
2065       gint64 offset = 0;
2066       QtDemuxStream *stream;
2067       gint idx;
2068       GstSegment segment;
2069       GstEvent *segment_event;
2070
2071       /* some debug output */
2072       gst_event_copy_segment (event, &segment);
2073       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
2074           &segment);
2075
2076       if (segment.format == GST_FORMAT_TIME) {
2077         GST_DEBUG_OBJECT (demux, "new pending_newsegment");
2078         gst_event_replace (&demux->pending_newsegment, event);
2079         demux->upstream_format_is_time = TRUE;
2080       } else {
2081         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
2082             "not in time format");
2083
2084         /* chain will send initial newsegment after pads have been added */
2085         if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
2086           GST_DEBUG_OBJECT (demux, "still starting, eating event");
2087           goto exit;
2088         }
2089       }
2090
2091       /* check if this matches a time seek we received previously
2092        * FIXME for backwards compatibility reasons we use the
2093        * seek_offset here to compare. In the future we might want to
2094        * change this to use the seqnum as it uniquely should identify
2095        * the segment that corresponds to the seek. */
2096       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
2097           ", received segment offset %" G_GINT64_FORMAT,
2098           demux->seek_offset, segment.start);
2099       if (segment.format == GST_FORMAT_BYTES
2100           && demux->seek_offset == segment.start) {
2101         GST_OBJECT_LOCK (demux);
2102         offset = segment.start;
2103
2104         segment.format = GST_FORMAT_TIME;
2105         segment.start = demux->push_seek_start;
2106         segment.stop = demux->push_seek_stop;
2107         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
2108             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
2109             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
2110         GST_OBJECT_UNLOCK (demux);
2111       }
2112
2113       /* we only expect a BYTE segment, e.g. following a seek */
2114       if (segment.format == GST_FORMAT_BYTES) {
2115         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
2116           offset = segment.start;
2117
2118           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
2119               NULL, (gint64 *) & segment.start);
2120           if ((gint64) segment.start < 0)
2121             segment.start = 0;
2122         }
2123         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
2124           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
2125               NULL, (gint64 *) & segment.stop);
2126           /* keyframe seeking should already arrange for start >= stop,
2127            * but make sure in other rare cases */
2128           segment.stop = MAX (segment.stop, segment.start);
2129         }
2130       } else if (segment.format == GST_FORMAT_TIME) {
2131         /* push all data on the adapter before starting this
2132          * new segment */
2133         gst_qtdemux_process_adapter (demux, TRUE);
2134       } else {
2135         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
2136         goto exit;
2137       }
2138
2139       /* accept upstream's notion of segment and distribute along */
2140       segment.format = GST_FORMAT_TIME;
2141       segment.position = segment.time = segment.start;
2142       segment.duration = demux->segment.duration;
2143       segment.base = gst_segment_to_running_time (&demux->segment,
2144           GST_FORMAT_TIME, demux->segment.position);
2145
2146       gst_segment_copy_into (&segment, &demux->segment);
2147       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2148       segment_event = gst_event_new_segment (&segment);
2149       gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2150       gst_qtdemux_push_event (demux, segment_event);
2151
2152       /* clear leftover in current segment, if any */
2153       gst_adapter_clear (demux->adapter);
2154
2155       /* set up streaming thread */
2156       demux->offset = offset;
2157       if (demux->upstream_format_is_time) {
2158         GST_DEBUG_OBJECT (demux, "Upstream is driving in time format, "
2159             "set values to restart reading from a new atom");
2160         demux->neededbytes = 16;
2161         demux->todrop = 0;
2162       } else {
2163         gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx,
2164             NULL);
2165         if (stream) {
2166           demux->todrop = stream->samples[idx].offset - offset;
2167           demux->neededbytes = demux->todrop + stream->samples[idx].size;
2168         } else {
2169           /* set up for EOS */
2170           demux->neededbytes = -1;
2171           demux->todrop = 0;
2172         }
2173       }
2174     exit:
2175       gst_event_unref (event);
2176       res = TRUE;
2177       goto drop;
2178     }
2179     case GST_EVENT_FLUSH_STOP:
2180     {
2181       guint64 dur;
2182
2183       dur = demux->segment.duration;
2184       gst_qtdemux_reset (demux, FALSE);
2185       demux->segment.duration = dur;
2186       break;
2187     }
2188     case GST_EVENT_EOS:
2189       /* If we are in push mode, and get an EOS before we've seen any streams,
2190        * then error out - we have nowhere to send the EOS */
2191       if (!demux->pullbased) {
2192         gint i;
2193         gboolean has_valid_stream = FALSE;
2194         for (i = 0; i < demux->n_streams; i++) {
2195           if (demux->streams[i]->pad != NULL) {
2196             has_valid_stream = TRUE;
2197             break;
2198           }
2199         }
2200         if (!has_valid_stream)
2201           gst_qtdemux_post_no_playable_stream_error (demux);
2202         else {
2203           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2204               (guint) gst_adapter_available (demux->adapter));
2205           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2206             res = FALSE;
2207           }
2208         }
2209       }
2210       break;
2211     case GST_EVENT_CAPS:{
2212       GstCaps *caps = NULL;
2213
2214       gst_event_parse_caps (event, &caps);
2215       gst_qtdemux_setcaps (demux, caps);
2216       res = TRUE;
2217       gst_event_unref (event);
2218       goto drop;
2219     }
2220     case GST_EVENT_PROTECTION:
2221     {
2222       const gchar *system_id = NULL;
2223
2224       gst_event_parse_protection (event, &system_id, NULL, NULL);
2225       GST_DEBUG_OBJECT (demux, "Received protection event for system ID %s",
2226           system_id);
2227       gst_qtdemux_append_protection_system_id (demux, system_id);
2228       /* save the event for later, for source pads that have not been created */
2229       g_queue_push_tail (&demux->protection_event_queue, gst_event_ref (event));
2230       /* send it to all pads that already exist */
2231       gst_qtdemux_push_event (demux, event);
2232       res = TRUE;
2233       goto drop;
2234     }
2235     default:
2236       break;
2237   }
2238
2239   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2240
2241 drop:
2242   return res;
2243 }
2244
2245 #if 0
2246 static void
2247 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2248 {
2249   GstQTDemux *demux = GST_QTDEMUX (element);
2250
2251   GST_OBJECT_LOCK (demux);
2252   if (demux->element_index)
2253     gst_object_unref (demux->element_index);
2254   if (index) {
2255     demux->element_index = gst_object_ref (index);
2256   } else {
2257     demux->element_index = NULL;
2258   }
2259   GST_OBJECT_UNLOCK (demux);
2260   /* object lock might be taken again */
2261   if (index)
2262     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2263   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2264       demux->element_index, demux->index_id);
2265 }
2266
2267 static GstIndex *
2268 gst_qtdemux_get_index (GstElement * element)
2269 {
2270   GstIndex *result = NULL;
2271   GstQTDemux *demux = GST_QTDEMUX (element);
2272
2273   GST_OBJECT_LOCK (demux);
2274   if (demux->element_index)
2275     result = gst_object_ref (demux->element_index);
2276   GST_OBJECT_UNLOCK (demux);
2277
2278   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2279
2280   return result;
2281 }
2282 #endif
2283
2284 static void
2285 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2286 {
2287   g_free ((gpointer) stream->stco.data);
2288   stream->stco.data = NULL;
2289   g_free ((gpointer) stream->stsz.data);
2290   stream->stsz.data = NULL;
2291   g_free ((gpointer) stream->stsc.data);
2292   stream->stsc.data = NULL;
2293   g_free ((gpointer) stream->stts.data);
2294   stream->stts.data = NULL;
2295   g_free ((gpointer) stream->stss.data);
2296   stream->stss.data = NULL;
2297   g_free ((gpointer) stream->stps.data);
2298   stream->stps.data = NULL;
2299   g_free ((gpointer) stream->ctts.data);
2300   stream->ctts.data = NULL;
2301 }
2302
2303 static void
2304 gst_qtdemux_stream_flush_segments_data (GstQTDemux * qtdemux,
2305     QtDemuxStream * stream)
2306 {
2307   g_free (stream->segments);
2308   stream->segments = NULL;
2309   stream->segment_index = -1;
2310   stream->accumulated_base = 0;
2311 }
2312
2313 static void
2314 gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
2315     QtDemuxStream * stream)
2316 {
2317   g_free (stream->samples);
2318   stream->samples = NULL;
2319   gst_qtdemux_stbl_free (stream);
2320
2321   /* fragments */
2322   g_free (stream->ra_entries);
2323   stream->ra_entries = NULL;
2324   stream->n_ra_entries = 0;
2325
2326   stream->sample_index = -1;
2327   stream->stbl_index = -1;
2328   stream->n_samples = 0;
2329   stream->time_position = 0;
2330 }
2331
2332 static void
2333 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2334 {
2335   if (stream->allocator)
2336     gst_object_unref (stream->allocator);
2337   while (stream->buffers) {
2338     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2339     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2340   }
2341   if (stream->rgb8_palette) {
2342     gst_memory_unref (stream->rgb8_palette);
2343     stream->rgb8_palette = NULL;
2344   }
2345
2346   if (stream->pending_tags)
2347     gst_tag_list_unref (stream->pending_tags);
2348   stream->pending_tags = NULL;
2349   g_free (stream->redirect_uri);
2350   stream->redirect_uri = NULL;
2351   stream->sent_eos = FALSE;
2352   stream->sparse = FALSE;
2353   stream->protected = FALSE;
2354   if (stream->protection_scheme_info) {
2355     if (stream->protection_scheme_type == FOURCC_cenc) {
2356       QtDemuxCencSampleSetInfo *info =
2357           (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
2358       if (info->default_properties)
2359         gst_structure_free (info->default_properties);
2360       if (info->crypto_info)
2361         g_ptr_array_free (info->crypto_info, TRUE);
2362     }
2363     g_free (stream->protection_scheme_info);
2364     stream->protection_scheme_info = NULL;
2365   }
2366   stream->protection_scheme_type = 0;
2367   stream->protection_scheme_version = 0;
2368   g_queue_foreach (&stream->protection_scheme_event_queue,
2369       (GFunc) gst_event_unref, NULL);
2370   g_queue_clear (&stream->protection_scheme_event_queue);
2371   gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
2372   gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
2373 }
2374
2375 static void
2376 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2377 {
2378   gst_qtdemux_stream_clear (qtdemux, stream);
2379   if (stream->caps)
2380     gst_caps_unref (stream->caps);
2381   stream->caps = NULL;
2382   if (stream->pad) {
2383     gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2384     gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2385   }
2386   g_free (stream);
2387 }
2388
2389 static void
2390 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2391 {
2392   g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2393
2394   gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2395   qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2396   qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2397   qtdemux->n_streams--;
2398 }
2399
2400 static GstStateChangeReturn
2401 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2402 {
2403   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2404   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2405
2406   switch (transition) {
2407     case GST_STATE_CHANGE_PAUSED_TO_READY:
2408       break;
2409     default:
2410       break;
2411   }
2412
2413   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2414
2415   switch (transition) {
2416     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2417       gst_qtdemux_reset (qtdemux, TRUE);
2418       break;
2419     }
2420     default:
2421       break;
2422   }
2423
2424   return result;
2425 }
2426
2427 static void
2428 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2429 {
2430   /* counts as header data */
2431   qtdemux->header_size += length;
2432
2433   /* only consider at least a sufficiently complete ftyp atom */
2434   if (length >= 20) {
2435     GstBuffer *buf;
2436
2437     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2438     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2439         GST_FOURCC_ARGS (qtdemux->major_brand));
2440     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2441     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2442   }
2443 }
2444
2445 static void
2446 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist,
2447     GstTagList * xmptaglist)
2448 {
2449   /* Strip out bogus fields */
2450   if (xmptaglist) {
2451     if (gst_tag_list_get_scope (taglist) == GST_TAG_SCOPE_GLOBAL) {
2452       gst_tag_list_remove_tag (xmptaglist, GST_TAG_VIDEO_CODEC);
2453       gst_tag_list_remove_tag (xmptaglist, GST_TAG_AUDIO_CODEC);
2454     } else {
2455       gst_tag_list_remove_tag (xmptaglist, GST_TAG_CONTAINER_FORMAT);
2456     }
2457
2458     GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, xmptaglist);
2459
2460     /* prioritize native tags using _KEEP mode */
2461     gst_tag_list_insert (taglist, xmptaglist, GST_TAG_MERGE_KEEP);
2462     gst_tag_list_unref (xmptaglist);
2463   }
2464 }
2465
2466 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
2467 static void
2468 _get_int_value_from_xml_string (GstQTDemux * qtdemux,
2469     const char *xml_str, const char *param_name, int *value)
2470 {
2471   char *value_start, *value_end, *endptr;
2472   const short value_length_max = 12;
2473   char init_view_ret[12];
2474   int value_length = 0;
2475   int i = 0;
2476
2477   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2478
2479   if (!value_start) {
2480     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2481         param_name);
2482     return;
2483   }
2484
2485   value_start += strlen (param_name);
2486   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2487     value_start++;
2488
2489   value_end = strchr (value_start, '<');
2490   if (!value_end) {
2491     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2492     return;
2493   }
2494
2495   value_length = value_end - value_start;
2496   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2497           || (value_start[value_length - 1] == '\t')))
2498     value_length--;
2499
2500   if (value_start[i] == '+' || value_start[i] == '-')
2501     i++;
2502   while (i < value_length) {
2503     if (value_start[i] < '0' || value_start[i] > '9') {
2504       GST_ERROR_OBJECT (qtdemux,
2505           "error: incorrect value, integer was expected\n");
2506       return;
2507     }
2508     i++;
2509   }
2510
2511   if (value_length >= value_length_max || value_length < 1) {
2512     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2513     return;
2514   }
2515
2516   strncpy (init_view_ret, value_start, value_length_max);
2517   init_view_ret[value_length] = '\0';
2518
2519   *value = strtol (init_view_ret, &endptr, 10);
2520   if (endptr == init_view_ret) {
2521     GST_ERROR_OBJECT (qtdemux, "error: no digits were found\n");
2522     return;
2523   }
2524
2525   return;
2526 }
2527
2528 static void
2529 _get_string_value_from_xml_string (GstQTDemux * qtdemux,
2530     const char *xml_str, const char *param_name, char **value)
2531 {
2532   char *value_start, *value_end;
2533   const short value_length_max = 256;
2534   int value_length = 0;
2535
2536   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2537
2538   if (!value_start) {
2539     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2540         param_name);
2541     return;
2542   }
2543
2544   value_start += strlen (param_name);
2545   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2546     value_start++;
2547
2548   value_end = strchr (value_start, '<');
2549   if (!value_end) {
2550     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2551     return;
2552   }
2553
2554   value_length = value_end - value_start;
2555   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2556           || (value_start[value_length - 1] == '\t')))
2557     value_length--;
2558
2559   if (value_length >= value_length_max || value_length < 1) {
2560     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2561     return;
2562   }
2563
2564   *value = (char *) malloc (value_length);
2565
2566   if (*value == NULL) {
2567     GST_ERROR_OBJECT (qtdemux, "error: malloc failed\n");
2568     return;
2569   }
2570
2571   strncpy (*value, value_start, value_length);
2572
2573   return;
2574 }
2575
2576 static void
2577 _get_bool_value_from_xml_string (GstQTDemux * qtdemux,
2578     const char *xml_str, const char *param_name, gboolean * value)
2579 {
2580   char *value_start, *value_end;
2581   int value_length = 0;
2582
2583   value_start = (xml_str && param_name) ? strstr (xml_str, param_name) : NULL;
2584
2585   if (!value_start) {
2586     GST_WARNING_OBJECT (qtdemux, "error: parameter does not exist: %s\n",
2587         param_name);
2588     return;
2589   }
2590
2591   value_start += strlen (param_name);
2592   while ((value_start[0] == ' ') || (value_start[0] == '\t'))
2593     value_start++;
2594
2595   value_end = strchr (value_start, '<');
2596   if (!value_end) {
2597     GST_ERROR_OBJECT (qtdemux, "error: incorrect XML\n");
2598     return;
2599   }
2600
2601   value_length = value_end - value_start;
2602   while ((value_length >= 1) && ((value_start[value_length - 1] == ' ')
2603           || (value_start[value_length - 1] == '\t')))
2604     value_length--;
2605
2606   if (value_length < 1) {
2607     GST_ERROR_OBJECT (qtdemux, "error: empty XML value or incorrect range\n");
2608     return;
2609   }
2610
2611   *value = strstr (value_start, "true") ? TRUE : FALSE;
2612
2613   return;
2614 }
2615
2616 static void
2617 _parse_spatial_video_metadata_from_xml_string (GstQTDemux * qtdemux,
2618     const char *xmlStr, QtDemuxSphericalMetadata * spherical_metadata)
2619 {
2620   const char is_spherical_str[] = "<GSpherical:Spherical>";
2621   const char is_stitched_str[] = "<GSpherical:Stitched>";
2622   const char stitching_software_str[] = "<GSpherical:StitchingSoftware>";
2623   const char projection_type_str[] = "<GSpherical:ProjectionType>";
2624   const char stereo_mode_str[] = "<GSpherical:StereoMode>";
2625   const char source_count_str[] = "<GSpherical:SourceCount>";
2626   const char init_view_heading_str[] = "<GSpherical:InitialViewHeadingDegrees>";
2627   const char init_view_pitch_str[] = "<GSpherical:InitialViewPitchDegrees>";
2628   const char init_view_roll_str[] = "<GSpherical:InitialViewRollDegrees>";
2629   const char timestamp_str[] = "<GSpherical:Timestamp>";
2630   const char full_pano_width_str[] = "<GSpherical:FullPanoWidthPixels>";
2631   const char full_pano_height_str[] = "<GSpherical:FullPanoHeightPixels>";
2632   const char cropped_area_image_width_str[] =
2633       "<GSpherical:CroppedAreaImageWidthPixels>";
2634   const char cropped_area_image_height_str[] =
2635       "<GSpherical:CroppedAreaImageHeightPixels>";
2636   const char cropped_area_left_str[] = "<GSpherical:CroppedAreaLeftPixels>";
2637   const char cropped_area_top_str[] = "<GSpherical:CroppedAreaTopPixels>";
2638
2639   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_spherical_str,
2640       (gboolean *) & spherical_metadata->is_spherical);
2641   _get_bool_value_from_xml_string (qtdemux, xmlStr, is_stitched_str,
2642       (gboolean *) & spherical_metadata->is_stitched);
2643
2644   if (spherical_metadata->is_spherical && spherical_metadata->is_stitched) {
2645     _get_string_value_from_xml_string (qtdemux, xmlStr,
2646         stitching_software_str, &spherical_metadata->stitching_software);
2647     _get_string_value_from_xml_string (qtdemux, xmlStr,
2648         projection_type_str, &spherical_metadata->projection_type);
2649     _get_string_value_from_xml_string (qtdemux, xmlStr, stereo_mode_str,
2650         &spherical_metadata->stereo_mode);
2651     _get_int_value_from_xml_string (qtdemux, xmlStr, source_count_str,
2652         &spherical_metadata->source_count);
2653     _get_int_value_from_xml_string (qtdemux, xmlStr,
2654         init_view_heading_str, &spherical_metadata->init_view_heading);
2655     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_pitch_str,
2656         &spherical_metadata->init_view_pitch);
2657     _get_int_value_from_xml_string (qtdemux, xmlStr, init_view_roll_str,
2658         &spherical_metadata->init_view_roll);
2659     _get_int_value_from_xml_string (qtdemux, xmlStr, timestamp_str,
2660         &spherical_metadata->timestamp);
2661     _get_int_value_from_xml_string (qtdemux, xmlStr, full_pano_width_str,
2662         &spherical_metadata->full_pano_width_pixels);
2663     _get_int_value_from_xml_string (qtdemux, xmlStr,
2664         full_pano_height_str, &spherical_metadata->full_pano_height_pixels);
2665     _get_int_value_from_xml_string (qtdemux, xmlStr,
2666         cropped_area_image_width_str,
2667         &spherical_metadata->cropped_area_image_width);
2668     _get_int_value_from_xml_string (qtdemux, xmlStr,
2669         cropped_area_image_height_str,
2670         &spherical_metadata->cropped_area_image_height);
2671     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_left_str,
2672         &spherical_metadata->cropped_area_left);
2673     _get_int_value_from_xml_string (qtdemux, xmlStr, cropped_area_top_str,
2674         &spherical_metadata->cropped_area_top);
2675   }
2676
2677   return;
2678 }
2679
2680 static void
2681 gst_tag_register_spherical_tags (void) {
2682   gst_tag_register ("is_spherical", GST_TAG_FLAG_META,
2683       G_TYPE_INT,
2684       _("tag-spherical"),
2685       _("Flag indicating if the video is a spherical video"),
2686       NULL);
2687   gst_tag_register ("is_stitched", GST_TAG_FLAG_META,
2688       G_TYPE_INT,
2689       _("tag-stitched"),
2690       _("Flag indicating if the video is stitched"),
2691       NULL);
2692   gst_tag_register ("stitching_software", GST_TAG_FLAG_META,
2693       G_TYPE_STRING,
2694       _("tag-stitching-software"),
2695       _("Software used to stitch the spherical video"),
2696       NULL);
2697   gst_tag_register ("projection_type", GST_TAG_FLAG_META,
2698       G_TYPE_STRING,
2699       _("tag-projection-type"),
2700       _("Projection type used in the video frames"),
2701       NULL);
2702   gst_tag_register ("stereo_mode", GST_TAG_FLAG_META,
2703       G_TYPE_STRING,
2704       _("tag-stereo-mode"),
2705       _("Description of stereoscopic 3D layout"),
2706       NULL);
2707   gst_tag_register ("source_count", GST_TAG_FLAG_META,
2708       G_TYPE_INT,
2709       _("tag-source-count"),
2710       _("Number of cameras used to create the spherical video"),
2711       NULL);
2712   gst_tag_register ("init_view_heading", GST_TAG_FLAG_META,
2713       G_TYPE_INT,
2714       _("tag-init-view-heading"),
2715       _("The heading angle of the initial view in degrees"),
2716       NULL);
2717   gst_tag_register ("init_view_pitch", GST_TAG_FLAG_META,
2718       G_TYPE_INT,
2719       _("tag-init-view-pitch"),
2720       _("The pitch angle of the initial view in degrees"),
2721       NULL);
2722   gst_tag_register ("init_view_roll", GST_TAG_FLAG_META,
2723       G_TYPE_INT,
2724       _("tag-init-view-roll"),
2725       _("The roll angle of the initial view in degrees"),
2726       NULL);
2727   gst_tag_register ("timestamp", GST_TAG_FLAG_META,
2728       G_TYPE_INT,
2729       _("tag-timestamp"),
2730       _("Epoch timestamp of when the first frame in the video was recorded"),
2731       NULL);
2732   gst_tag_register ("full_pano_width_pixels", GST_TAG_FLAG_META,
2733       G_TYPE_INT,
2734       _("tag-full-pano-width"),
2735       _("Width of the encoded video frame in pixels"),
2736       NULL);
2737   gst_tag_register ("full_pano_height_pixels", GST_TAG_FLAG_META,
2738       G_TYPE_INT,
2739       _("tag-full-pano-height"),
2740       _("Height of the encoded video frame in pixels"),
2741       NULL);
2742   gst_tag_register ("cropped_area_image_width", GST_TAG_FLAG_META,
2743       G_TYPE_INT,
2744       _("tag-cropped-area-image-width"),
2745       _("Width of the video frame to display (e.g. cropping)"),
2746       NULL);
2747   gst_tag_register ("cropped_area_image_height", GST_TAG_FLAG_META,
2748       G_TYPE_INT,
2749       _("tag-cropped-area-image-height"),
2750       _("Height of the video frame to display (e.g. cropping)"),
2751       NULL);
2752   gst_tag_register ("cropped_area_left", GST_TAG_FLAG_META,
2753       G_TYPE_INT,
2754       _("tag-cropped-area-left"),
2755       _("Column where the left edge of the image was cropped from the"
2756           " full sized panorama"),
2757       NULL);
2758   gst_tag_register ("cropped_area_top", GST_TAG_FLAG_META,
2759       G_TYPE_INT,
2760       _("tag-cropped-area-top"),
2761       _("Row where the top edge of the image was cropped from the"
2762           " full sized panorama"),
2763       NULL);
2764   gst_tag_register ("ambisonic_type", GST_TAG_FLAG_META,
2765       G_TYPE_INT,
2766       _("tag-ambisonic-type"),
2767       _("Specifies the type of ambisonic audio represented"),
2768       NULL);
2769   gst_tag_register ("ambisonic_format", GST_TAG_FLAG_META,
2770       G_TYPE_INT,
2771       _("tag-ambisonic-format"),
2772       _("Specifies the ambisonic audio format"),
2773       NULL);
2774   gst_tag_register ("ambisonic_order", GST_TAG_FLAG_META,
2775       G_TYPE_INT,
2776       _("tag-ambisonic-order"),
2777       _("Specifies the ambisonic audio channel order"),
2778       NULL);
2779
2780   return;
2781 }
2782
2783 static void
2784 _send_message_to_bus (GstQTDemux * qtdemux,
2785     QtDemuxSphericalMetadata * spherical_metadata)
2786 {
2787   GstTagList *taglist;
2788
2789   GST_DEBUG_OBJECT (qtdemux, "is_spherical = %d",
2790       spherical_metadata->is_spherical);
2791   GST_DEBUG_OBJECT (qtdemux, "is_stitched = %d",
2792       spherical_metadata->is_stitched);
2793   GST_DEBUG_OBJECT (qtdemux, "stitching_software = %s",
2794       spherical_metadata->stitching_software);
2795   GST_DEBUG_OBJECT (qtdemux, "projection_type = %s",
2796       spherical_metadata->projection_type);
2797   GST_DEBUG_OBJECT (qtdemux, "stereo_mode = %s",
2798       spherical_metadata->stereo_mode);
2799   GST_DEBUG_OBJECT (qtdemux, "source_count %d",
2800       spherical_metadata->source_count);
2801   GST_DEBUG_OBJECT (qtdemux, "init_view_heading = %d",
2802       spherical_metadata->init_view_heading);
2803   GST_DEBUG_OBJECT (qtdemux, "init_view_pitch = %d",
2804       spherical_metadata->init_view_pitch);
2805   GST_DEBUG_OBJECT (qtdemux, "init_view_roll = %d",
2806       spherical_metadata->init_view_roll);
2807   GST_DEBUG_OBJECT (qtdemux, "timestamp = %d", spherical_metadata->timestamp);
2808   GST_DEBUG_OBJECT (qtdemux, "full_pano_width_pixels = %d",
2809       spherical_metadata->full_pano_width_pixels);
2810   GST_DEBUG_OBJECT (qtdemux, "full_pano_height_pixels = %d",
2811       spherical_metadata->full_pano_height_pixels);
2812   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_width = %d",
2813       spherical_metadata->cropped_area_image_width);
2814   GST_DEBUG_OBJECT (qtdemux, "cropped_area_image_height = %d",
2815       spherical_metadata->cropped_area_image_height);
2816   GST_DEBUG_OBJECT (qtdemux, "cropped_area_left = %d",
2817       spherical_metadata->cropped_area_left);
2818   GST_DEBUG_OBJECT (qtdemux, "cropped_area_top = %d",
2819       spherical_metadata->cropped_area_top);
2820   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type = %d",
2821       spherical_metadata->ambisonic_type);
2822   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order = %d",
2823       spherical_metadata->ambisonic_order);
2824   GST_DEBUG_OBJECT (qtdemux, "ambisonic_format = %d",
2825       spherical_metadata->ambisonic_format);
2826
2827   taglist = gst_tag_list_new_empty ();
2828   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
2829       "is_spherical", spherical_metadata->is_spherical,
2830       "is_stitched", spherical_metadata->is_stitched,
2831       "source_count", spherical_metadata->source_count,
2832       "init_view_heading", spherical_metadata->init_view_heading,
2833       "init_view_pitch", spherical_metadata->init_view_pitch,
2834       "init_view_roll", spherical_metadata->init_view_roll,
2835       "timestamp", spherical_metadata->timestamp,
2836       "full_pano_width_pixels", spherical_metadata->full_pano_width_pixels,
2837       "full_pano_height_pixels", spherical_metadata->full_pano_height_pixels,
2838       "cropped_area_image_width", spherical_metadata->cropped_area_image_width,
2839       "cropped_area_image_height", spherical_metadata->cropped_area_image_height,
2840       "cropped_area_left", spherical_metadata->cropped_area_left,
2841       "cropped_area_top", spherical_metadata->cropped_area_top,
2842       "ambisonic_type", spherical_metadata->ambisonic_type,
2843       "ambisonic_format", spherical_metadata->ambisonic_format,
2844       "ambisonic_order", spherical_metadata->ambisonic_order,
2845       NULL);
2846
2847   if (spherical_metadata->stitching_software)
2848     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
2849         "stitching_software", spherical_metadata->stitching_software,
2850         NULL);
2851   if (spherical_metadata->projection_type)
2852     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
2853         "projection_type", spherical_metadata->projection_type,
2854         NULL);
2855   if (spherical_metadata->stereo_mode)
2856     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
2857         "stereo_mode", spherical_metadata->stereo_mode,
2858         NULL);
2859
2860   gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
2861           gst_message_new_tag (GST_OBJECT_CAST (qtdemux),
2862                   gst_tag_list_copy (taglist)));
2863
2864   gst_tag_list_unref(taglist);
2865
2866   return;
2867 }
2868
2869 static void
2870 qtdemux_parse_SA3D (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2871 {
2872   guint offset = 0;
2873
2874   guint8 version = 0;
2875   guint8 ambisonic_type  = 0;
2876   guint32 ambisonic_order = 0;
2877   guint8 ambisonic_channel_ordering = 0;
2878   guint8 ambisonic_normalization = 0;
2879   guint32 num_channels = 0;
2880   guint32 channel_map[49] = { 0 };      /* Up to 6th order */
2881
2882   int i;
2883
2884   GST_DEBUG_OBJECT (qtdemux, "qtdemux_parse_SA3D");
2885
2886   qtdemux->header_size += length;
2887   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2888
2889   if (length <= offset + 16) {
2890     GST_DEBUG_OBJECT (qtdemux, "SA3D atom is too short, skipping");
2891     return;
2892   }
2893
2894   version = QT_UINT8 (buffer + offset);
2895   ambisonic_type = QT_UINT8 (buffer + offset + 1);
2896   ambisonic_order = QT_UINT32 (buffer + offset + 2);
2897   ambisonic_channel_ordering = QT_UINT8 (buffer + offset + 6);
2898   ambisonic_normalization = QT_UINT8 (buffer + offset + 7);
2899   num_channels = QT_UINT32 (buffer + offset + 8);
2900   for (i = 0; i < num_channels; ++i)
2901     channel_map[i] = QT_UINT32 (buffer + offset + 12 + i * 4);
2902
2903   GST_DEBUG_OBJECT (qtdemux, "version: %d", version);
2904   GST_DEBUG_OBJECT (qtdemux, "ambisonic_type: %d", ambisonic_type);
2905   GST_DEBUG_OBJECT (qtdemux, "ambisonic_order: %d", ambisonic_order);
2906   GST_DEBUG_OBJECT (qtdemux, "ambisonic_channel_ordering: %d",
2907       ambisonic_channel_ordering);
2908   GST_DEBUG_OBJECT (qtdemux, "ambisonic_normalization: %d",
2909       ambisonic_normalization);
2910   GST_DEBUG_OBJECT (qtdemux, "num_channels: %d", num_channels);
2911   for (i = 0; i < num_channels; ++i)
2912     GST_DEBUG_OBJECT (qtdemux, "channel_map: %d", channel_map[i]);
2913
2914   if (version == RFC_AMBISONIC_SA3DBOX_VERSION_SUPPORTED) {
2915     if (ambisonic_type == RFC_AMBISONIC_TYPE_PERIPHONIC)
2916       spherical_metadata->ambisonic_type = QTDEMUX_AMBISONIC_TYPE_PERIPHONIC;
2917
2918     if (ambisonic_order == RFC_AMBISONIC_ORDER_FOA) {
2919       if (num_channels == 4) {
2920         spherical_metadata->ambisonic_order = QTDEMUX_AMBISONIC_ORDER_FOA;
2921
2922         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_ACN)
2923             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_SN3D)
2924             && (channel_map[0] == 0) && (channel_map[1] == 1)
2925             && (channel_map[2] == 2) && (channel_map[3] == 3))
2926           spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMBIX;
2927
2928         if ((ambisonic_channel_ordering == RFC_AMBISONIC_CHANNEL_ORDERING_FUMA)
2929             && (ambisonic_normalization == RFC_AMBISONIC_NORMALIZATION_FUMA)
2930             && (channel_map[0] == 0) && (channel_map[1] == 3)
2931             && (channel_map[2] == 1) && (channel_map[3] == 2))
2932           spherical_metadata->ambisonic_format = QTDEMUX_AMBISONIC_FORMAT_AMB;
2933       }
2934     }
2935   }
2936
2937   return;
2938 }
2939 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
2940
2941 static void
2942 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2943 {
2944   static const guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2945     0x97, 0xA9, 0x42, 0xE8,
2946     0x9C, 0x71, 0x99, 0x94,
2947     0x91, 0xE3, 0xAF, 0xAC
2948   };
2949   static const guint8 playready_uuid[] = {
2950     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2951     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2952   };
2953
2954 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
2955   static const guint8 spherical_uuid[] = {
2956     0xff, 0xcc, 0x82, 0x63, 0xf8, 0x55, 0x4a, 0x93,
2957     0x88, 0x14, 0x58, 0x7a, 0x02, 0x52, 0x1f, 0xdd
2958   };
2959 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
2960
2961   guint offset;
2962
2963   /* counts as header data */
2964   qtdemux->header_size += length;
2965
2966   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2967
2968   if (length <= offset + 16) {
2969     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2970     return;
2971   }
2972
2973 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
2974   if (memcmp (buffer + offset, spherical_uuid, 16) == 0) {
2975     const char *contents;
2976
2977     GST_DEBUG_OBJECT (qtdemux, "spherical uuid was found");
2978     contents = (char *) (buffer + offset + 16);
2979     GST_DEBUG_OBJECT (qtdemux, "contents: %s\n", contents);
2980
2981     if (spherical_metadata)
2982       _parse_spatial_video_metadata_from_xml_string (qtdemux, contents,
2983           spherical_metadata);
2984
2985     return;
2986   }
2987 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
2988
2989   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2990     GstBuffer *buf;
2991     GstTagList *taglist;
2992
2993     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2994         length - offset - 16, NULL);
2995     taglist = gst_tag_list_from_xmp_buffer (buf);
2996     gst_buffer_unref (buf);
2997
2998     qtdemux_handle_xmp_taglist (qtdemux, qtdemux->tag_list, taglist);
2999
3000   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
3001     int len;
3002     const gunichar2 *s_utf16;
3003     char *contents;
3004
3005     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
3006     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
3007     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
3008     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
3009
3010     g_free (contents);
3011
3012     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
3013         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
3014         (NULL));
3015   } else {
3016     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
3017         GST_READ_UINT32_LE (buffer + offset),
3018         GST_READ_UINT32_LE (buffer + offset + 4),
3019         GST_READ_UINT32_LE (buffer + offset + 8),
3020         GST_READ_UINT32_LE (buffer + offset + 12));
3021   }
3022 }
3023
3024 static void
3025 qtdemux_parse_sidx (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
3026 {
3027   GstSidxParser sidx_parser;
3028   GstIsoffParserResult res;
3029   guint consumed;
3030
3031   gst_isoff_qt_sidx_parser_init (&sidx_parser);
3032
3033   res =
3034       gst_isoff_qt_sidx_parser_add_data (&sidx_parser, buffer, length,
3035       &consumed);
3036   GST_DEBUG_OBJECT (qtdemux, "sidx parse result: %d", res);
3037   if (res == GST_ISOFF_QT_PARSER_DONE) {
3038     check_update_duration (qtdemux, sidx_parser.cumulative_pts);
3039   }
3040   gst_isoff_qt_sidx_parser_clear (&sidx_parser);
3041 }
3042
3043 /* caller verifies at least 8 bytes in buf */
3044 static void
3045 extract_initial_length_and_fourcc (const guint8 * data, guint size,
3046     guint64 * plength, guint32 * pfourcc)
3047 {
3048   guint64 length;
3049   guint32 fourcc;
3050
3051   length = QT_UINT32 (data);
3052   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3053   fourcc = QT_FOURCC (data + 4);
3054   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
3055
3056   if (length == 0) {
3057     length = G_MAXUINT64;
3058   } else if (length == 1 && size >= 16) {
3059     /* this means we have an extended size, which is the 64 bit value of
3060      * the next 8 bytes */
3061     length = QT_UINT64 (data + 8);
3062     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
3063   }
3064
3065   if (plength)
3066     *plength = length;
3067   if (pfourcc)
3068     *pfourcc = fourcc;
3069 }
3070
3071 static gboolean
3072 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
3073 {
3074   guint32 version = 0;
3075   GstClockTime duration = 0;
3076
3077   if (!gst_byte_reader_get_uint32_be (br, &version))
3078     goto failed;
3079
3080   version >>= 24;
3081   if (version == 1) {
3082     if (!gst_byte_reader_get_uint64_be (br, &duration))
3083       goto failed;
3084   } else {
3085     guint32 dur = 0;
3086
3087     if (!gst_byte_reader_get_uint32_be (br, &dur))
3088       goto failed;
3089     duration = dur;
3090   }
3091
3092   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
3093   qtdemux->duration = duration;
3094
3095   return TRUE;
3096
3097 failed:
3098   {
3099     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
3100     return FALSE;
3101   }
3102 }
3103
3104 static gboolean
3105 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
3106     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
3107 {
3108   if (!stream->parsed_trex && qtdemux->moov_node) {
3109     GNode *mvex, *trex;
3110     GstByteReader trex_data;
3111
3112     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
3113     if (mvex) {
3114       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
3115           &trex_data);
3116       while (trex) {
3117         guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
3118
3119         /* skip version/flags */
3120         if (!gst_byte_reader_skip (&trex_data, 4))
3121           goto next;
3122         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
3123           goto next;
3124         if (id != stream->track_id)
3125           goto next;
3126         /* sample description index; ignore */
3127         if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
3128           goto next;
3129         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
3130           goto next;
3131         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
3132           goto next;
3133         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
3134           goto next;
3135
3136         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
3137             "duration %d,  size %d, flags 0x%x", stream->track_id,
3138             dur, size, flags);
3139
3140         stream->parsed_trex = TRUE;
3141         stream->def_sample_duration = dur;
3142         stream->def_sample_size = size;
3143         stream->def_sample_flags = flags;
3144
3145       next:
3146         /* iterate all siblings */
3147         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
3148             &trex_data);
3149       }
3150     }
3151   }
3152
3153   *ds_duration = stream->def_sample_duration;
3154   *ds_size = stream->def_sample_size;
3155   *ds_flags = stream->def_sample_flags;
3156
3157   /* even then, above values are better than random ... */
3158   if (G_UNLIKELY (!stream->parsed_trex)) {
3159     GST_WARNING_OBJECT (qtdemux,
3160         "failed to find fragment defaults for stream %d", stream->track_id);
3161     return FALSE;
3162   }
3163
3164   return TRUE;
3165 }
3166
3167 /* This method should be called whenever a more accurate duration might
3168  * have been found. It will update all relevant variables if/where needed
3169  */
3170 static void
3171 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
3172 {
3173   guint i;
3174   guint64 movdur;
3175   GstClockTime prevdur;
3176
3177   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
3178
3179   if (movdur > qtdemux->duration) {
3180     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
3181     GST_DEBUG_OBJECT (qtdemux,
3182         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
3183         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
3184     qtdemux->duration = movdur;
3185     GST_DEBUG_OBJECT (qtdemux,
3186         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
3187         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
3188         GST_TIME_ARGS (qtdemux->segment.stop));
3189     if (qtdemux->segment.duration == prevdur) {
3190       /* If the current segment has duration/stop identical to previous duration
3191        * update them also (because they were set at that point in time with
3192        * the wrong duration */
3193       /* We convert the value *from* the timescale version to avoid rounding errors */
3194       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
3195       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
3196       qtdemux->segment.duration = fixeddur;
3197       qtdemux->segment.stop = fixeddur;
3198     }
3199   }
3200   for (i = 0; i < qtdemux->n_streams; i++) {
3201     QtDemuxStream *stream = qtdemux->streams[i];
3202     if (stream) {
3203       movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
3204       if (movdur > stream->duration) {
3205         GST_DEBUG_OBJECT (qtdemux,
3206             "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
3207             GST_TIME_ARGS (duration));
3208         stream->duration = movdur;
3209         if (stream->dummy_segment) {
3210           /* Update all dummy values to new duration */
3211           stream->segments[0].stop_time = duration;
3212           stream->segments[0].duration = duration;
3213           stream->segments[0].media_stop = duration;
3214         }
3215       }
3216     }
3217   }
3218 }
3219
3220 static gboolean
3221 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
3222     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
3223     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
3224     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
3225 {
3226   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
3227   guint64 timestamp;
3228   gint32 data_offset = 0;
3229   guint32 flags = 0, first_flags = 0, samples_count = 0;
3230   gint i;
3231   guint8 *data;
3232   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
3233   QtDemuxSample *sample;
3234   gboolean ismv = FALSE;
3235
3236   GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
3237       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
3238       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
3239       d_sample_size, d_sample_flags, *base_offset, decode_ts);
3240
3241   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
3242     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
3243     return TRUE;
3244   }
3245
3246   /* presence of stss or not can't really tell us much,
3247    * and flags and so on tend to be marginally reliable in these files */
3248   if (stream->subtype == FOURCC_soun) {
3249     GST_DEBUG_OBJECT (qtdemux,
3250         "sound track in fragmented file; marking all keyframes");
3251     stream->all_keyframe = TRUE;
3252   }
3253
3254   if (!gst_byte_reader_skip (trun, 1) ||
3255       !gst_byte_reader_get_uint24_be (trun, &flags))
3256     goto fail;
3257
3258   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
3259     goto fail;
3260
3261   if (flags & TR_DATA_OFFSET) {
3262     /* note this is really signed */
3263     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
3264       goto fail;
3265     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
3266     /* default base offset = first byte of moof */
3267     if (*base_offset == -1) {
3268       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
3269       *base_offset = moof_offset;
3270     }
3271     *running_offset = *base_offset + data_offset;
3272   } else {
3273     /* if no offset at all, that would mean data starts at moof start,
3274      * which is a bit wrong and is ismv crappy way, so compensate
3275      * assuming data is in mdat following moof */
3276     if (*base_offset == -1) {
3277       *base_offset = moof_offset + moof_length + 8;
3278       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
3279       ismv = TRUE;
3280     }
3281     if (*running_offset == -1)
3282       *running_offset = *base_offset;
3283   }
3284
3285   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
3286       *running_offset);
3287   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
3288       data_offset, flags, samples_count);
3289
3290   if (flags & TR_FIRST_SAMPLE_FLAGS) {
3291     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
3292       GST_DEBUG_OBJECT (qtdemux,
3293           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
3294       flags ^= TR_FIRST_SAMPLE_FLAGS;
3295     } else {
3296       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
3297         goto fail;
3298       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
3299     }
3300   }
3301
3302   /* FIXME ? spec says other bits should also be checked to determine
3303    * entry size (and prefix size for that matter) */
3304   entry_size = 0;
3305   dur_offset = size_offset = 0;
3306   if (flags & TR_SAMPLE_DURATION) {
3307     GST_LOG_OBJECT (qtdemux, "entry duration present");
3308     dur_offset = entry_size;
3309     entry_size += 4;
3310   }
3311   if (flags & TR_SAMPLE_SIZE) {
3312     GST_LOG_OBJECT (qtdemux, "entry size present");
3313     size_offset = entry_size;
3314     entry_size += 4;
3315   }
3316   if (flags & TR_SAMPLE_FLAGS) {
3317     GST_LOG_OBJECT (qtdemux, "entry flags present");
3318     flags_offset = entry_size;
3319     entry_size += 4;
3320   }
3321   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3322     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
3323     ct_offset = entry_size;
3324     entry_size += 4;
3325   }
3326
3327   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
3328     goto fail;
3329   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
3330
3331   if (stream->n_samples + samples_count >=
3332       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
3333     goto index_too_big;
3334
3335   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
3336       stream->n_samples + samples_count, (guint) sizeof (QtDemuxSample),
3337       (stream->n_samples + samples_count) *
3338       sizeof (QtDemuxSample) / (1024.0 * 1024.0));
3339
3340   /* create a new array of samples if it's the first sample parsed */
3341   if (stream->n_samples == 0) {
3342     g_assert (stream->samples == NULL);
3343     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
3344     /* or try to reallocate it with space enough to insert the new samples */
3345   } else
3346     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
3347         stream->n_samples + samples_count);
3348   if (stream->samples == NULL)
3349     goto out_of_memory;
3350
3351   if (qtdemux->fragment_start != -1) {
3352     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
3353     qtdemux->fragment_start = -1;
3354   } else {
3355     if (stream->n_samples == 0) {
3356       if (decode_ts > 0) {
3357         timestamp = decode_ts;
3358       } else if (stream->pending_seek != NULL) {
3359         /* if we don't have a timestamp from a tfdt box, we'll use the one
3360          * from the mfra seek table */
3361         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
3362             GST_TIME_ARGS (stream->pending_seek->ts));
3363
3364         /* FIXME: this is not fully correct, the timestamp refers to the random
3365          * access sample refered to in the tfra entry, which may not necessarily
3366          * be the first sample in the tfrag/trun (but hopefully/usually is) */
3367         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
3368       } else {
3369         timestamp = 0;
3370       }
3371
3372       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3373       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
3374           GST_TIME_ARGS (gst_ts));
3375     } else {
3376       /* subsequent fragments extend stream */
3377       timestamp =
3378           stream->samples[stream->n_samples - 1].timestamp +
3379           stream->samples[stream->n_samples - 1].duration;
3380
3381       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
3382       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
3383           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
3384     }
3385   }
3386
3387   sample = stream->samples + stream->n_samples;
3388   for (i = 0; i < samples_count; i++) {
3389     guint32 dur, size, sflags, ct;
3390
3391     /* first read sample data */
3392     if (flags & TR_SAMPLE_DURATION) {
3393       dur = QT_UINT32 (data + dur_offset);
3394     } else {
3395       dur = d_sample_duration;
3396     }
3397     if (flags & TR_SAMPLE_SIZE) {
3398       size = QT_UINT32 (data + size_offset);
3399     } else {
3400       size = d_sample_size;
3401     }
3402     if (flags & TR_FIRST_SAMPLE_FLAGS) {
3403       if (i == 0) {
3404         sflags = first_flags;
3405       } else {
3406         sflags = d_sample_flags;
3407       }
3408     } else if (flags & TR_SAMPLE_FLAGS) {
3409       sflags = QT_UINT32 (data + flags_offset);
3410     } else {
3411       sflags = d_sample_flags;
3412     }
3413     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
3414       ct = QT_UINT32 (data + ct_offset);
3415     } else {
3416       ct = 0;
3417     }
3418     data += entry_size;
3419
3420     /* fill the sample information */
3421     sample->offset = *running_offset;
3422     sample->pts_offset = ct;
3423     sample->size = size;
3424     sample->timestamp = timestamp;
3425     sample->duration = dur;
3426     /* sample-is-difference-sample */
3427     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
3428      * now idea how it relates to bitfield other than massive LE/BE confusion */
3429     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
3430     *running_offset += size;
3431     timestamp += dur;
3432     sample++;
3433   }
3434
3435   /* Update total duration if needed */
3436   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
3437
3438   stream->n_samples += samples_count;
3439
3440   if (stream->pending_seek != NULL)
3441     stream->pending_seek = NULL;
3442
3443   return TRUE;
3444
3445 fail:
3446   {
3447     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
3448     return FALSE;
3449   }
3450 out_of_memory:
3451   {
3452     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
3453         stream->n_samples);
3454     return FALSE;
3455   }
3456 index_too_big:
3457   {
3458     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
3459         "be larger than %uMB (broken file?)", stream->n_samples,
3460         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
3461     return FALSE;
3462   }
3463 }
3464
3465 /* find stream with @id */
3466 static inline QtDemuxStream *
3467 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
3468 {
3469   QtDemuxStream *stream;
3470   gint i;
3471
3472   /* check */
3473   if (G_UNLIKELY (!id)) {
3474     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
3475     return NULL;
3476   }
3477
3478   /* try to get it fast and simple */
3479   if (G_LIKELY (id <= qtdemux->n_streams)) {
3480     stream = qtdemux->streams[id - 1];
3481     if (G_LIKELY (stream->track_id == id))
3482       return stream;
3483   }
3484
3485   /* linear search otherwise */
3486   for (i = 0; i < qtdemux->n_streams; i++) {
3487     stream = qtdemux->streams[i];
3488     if (stream->track_id == id)
3489       return stream;
3490   }
3491   if (qtdemux->mss_mode) {
3492     /* mss should have only 1 stream anyway */
3493     return qtdemux->streams[0];
3494   }
3495
3496   return NULL;
3497 }
3498
3499 static gboolean
3500 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
3501     guint32 * fragment_number)
3502 {
3503   if (!gst_byte_reader_skip (mfhd, 4))
3504     goto fail;
3505   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
3506     goto fail;
3507   return TRUE;
3508 fail:
3509   {
3510     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
3511     return FALSE;
3512   }
3513 }
3514
3515 static gboolean
3516 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
3517     QtDemuxStream ** stream, guint32 * default_sample_duration,
3518     guint32 * default_sample_size, guint32 * default_sample_flags,
3519     gint64 * base_offset)
3520 {
3521   guint32 flags = 0;
3522   guint32 track_id = 0;
3523
3524   if (!gst_byte_reader_skip (tfhd, 1) ||
3525       !gst_byte_reader_get_uint24_be (tfhd, &flags))
3526     goto invalid_track;
3527
3528   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
3529     goto invalid_track;
3530
3531   *stream = qtdemux_find_stream (qtdemux, track_id);
3532   if (G_UNLIKELY (!*stream))
3533     goto unknown_stream;
3534
3535   if (flags & TF_DEFAULT_BASE_IS_MOOF)
3536     *base_offset = qtdemux->moof_offset;
3537
3538   if (flags & TF_BASE_DATA_OFFSET)
3539     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
3540       goto invalid_track;
3541
3542   /* obtain stream defaults */
3543   qtdemux_parse_trex (qtdemux, *stream,
3544       default_sample_duration, default_sample_size, default_sample_flags);
3545
3546   /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
3547   if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
3548     if (!gst_byte_reader_skip (tfhd, 4))
3549       goto invalid_track;
3550
3551   if (flags & TF_DEFAULT_SAMPLE_DURATION)
3552     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
3553       goto invalid_track;
3554
3555   if (flags & TF_DEFAULT_SAMPLE_SIZE)
3556     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
3557       goto invalid_track;
3558
3559   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
3560     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
3561       goto invalid_track;
3562
3563   return TRUE;
3564
3565 invalid_track:
3566   {
3567     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
3568     return FALSE;
3569   }
3570 unknown_stream:
3571   {
3572     GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
3573     return TRUE;
3574   }
3575 }
3576
3577 static gboolean
3578 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
3579     guint64 * decode_time)
3580 {
3581   guint32 version = 0;
3582
3583   if (!gst_byte_reader_get_uint32_be (br, &version))
3584     return FALSE;
3585
3586   version >>= 24;
3587   if (version == 1) {
3588     if (!gst_byte_reader_get_uint64_be (br, decode_time))
3589       goto failed;
3590   } else {
3591     guint32 dec_time = 0;
3592     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
3593       goto failed;
3594     *decode_time = dec_time;
3595   }
3596
3597   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
3598       *decode_time);
3599
3600   return TRUE;
3601
3602 failed:
3603   {
3604     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
3605     return FALSE;
3606   }
3607 }
3608
3609 /* Returns a pointer to a GstStructure containing the properties of
3610  * the stream sample identified by @sample_index. The caller must unref
3611  * the returned object after use. Returns NULL if unsuccessful. */
3612 static GstStructure *
3613 qtdemux_get_cenc_sample_properties (GstQTDemux * qtdemux,
3614     QtDemuxStream * stream, guint sample_index)
3615 {
3616   QtDemuxCencSampleSetInfo *info = NULL;
3617
3618   g_return_val_if_fail (stream != NULL, NULL);
3619   g_return_val_if_fail (stream->protected, NULL);
3620   g_return_val_if_fail (stream->protection_scheme_info != NULL, NULL);
3621
3622   info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3623
3624   /* Currently, cenc properties for groups of samples are not supported, so
3625    * simply return a copy of the default sample properties */
3626   return gst_structure_copy (info->default_properties);
3627 }
3628
3629 /* Parses the sizes of sample auxiliary information contained within a stream,
3630  * as given in a saiz box. Returns array of sample_count guint8 size values,
3631  * or NULL on failure */
3632 static guint8 *
3633 qtdemux_parse_saiz (GstQTDemux * qtdemux, QtDemuxStream * stream,
3634     GstByteReader * br, guint32 * sample_count)
3635 {
3636   guint32 flags = 0;
3637   guint8 *info_sizes;
3638   guint8 default_info_size;
3639
3640   g_return_val_if_fail (qtdemux != NULL, NULL);
3641   g_return_val_if_fail (stream != NULL, NULL);
3642   g_return_val_if_fail (br != NULL, NULL);
3643   g_return_val_if_fail (sample_count != NULL, NULL);
3644
3645   if (!gst_byte_reader_get_uint32_be (br, &flags))
3646     return NULL;
3647
3648   if (flags & 0x1) {
3649     /* aux_info_type and aux_info_type_parameter are ignored */
3650     if (!gst_byte_reader_skip (br, 8))
3651       return NULL;
3652   }
3653
3654   if (!gst_byte_reader_get_uint8 (br, &default_info_size))
3655     return NULL;
3656   GST_DEBUG_OBJECT (qtdemux, "default_info_size: %u", default_info_size);
3657
3658   if (!gst_byte_reader_get_uint32_be (br, sample_count))
3659     return NULL;
3660   GST_DEBUG_OBJECT (qtdemux, "sample_count: %u", *sample_count);
3661
3662
3663   if (default_info_size == 0) {
3664     if (!gst_byte_reader_dup_data (br, *sample_count, &info_sizes)) {
3665       return NULL;
3666     }
3667   } else {
3668     info_sizes = g_new (guint8, *sample_count);
3669     memset (info_sizes, default_info_size, *sample_count);
3670   }
3671
3672   return info_sizes;
3673 }
3674
3675 /* Parses the offset of sample auxiliary information contained within a stream,
3676  * as given in a saio box. Returns TRUE if successful; FALSE otherwise. */
3677 static gboolean
3678 qtdemux_parse_saio (GstQTDemux * qtdemux, QtDemuxStream * stream,
3679     GstByteReader * br, guint32 * info_type, guint32 * info_type_parameter,
3680     guint64 * offset)
3681 {
3682   guint8 version = 0;
3683   guint32 flags = 0;
3684   guint32 aux_info_type = 0;
3685   guint32 aux_info_type_parameter = 0;
3686   guint32 entry_count;
3687   guint32 off_32;
3688   guint64 off_64;
3689
3690   g_return_val_if_fail (qtdemux != NULL, FALSE);
3691   g_return_val_if_fail (stream != NULL, FALSE);
3692   g_return_val_if_fail (br != NULL, FALSE);
3693   g_return_val_if_fail (offset != NULL, FALSE);
3694
3695   if (!gst_byte_reader_get_uint8 (br, &version))
3696     return FALSE;
3697
3698   if (!gst_byte_reader_get_uint24_be (br, &flags))
3699     return FALSE;
3700
3701   if (flags & 0x1) {
3702     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type))
3703       return FALSE;
3704     if (!gst_byte_reader_get_uint32_be (br, &aux_info_type_parameter))
3705       return FALSE;
3706   } else if (stream->protected) {
3707     aux_info_type = stream->protection_scheme_type;
3708   } else {
3709     aux_info_type = stream->fourcc;
3710   }
3711
3712   if (info_type)
3713     *info_type = aux_info_type;
3714   if (info_type_parameter)
3715     *info_type_parameter = aux_info_type_parameter;
3716
3717   GST_DEBUG_OBJECT (qtdemux, "aux_info_type: '%" GST_FOURCC_FORMAT "', "
3718       "aux_info_type_parameter:  %#06x",
3719       GST_FOURCC_ARGS (aux_info_type), aux_info_type_parameter);
3720
3721   if (!gst_byte_reader_get_uint32_be (br, &entry_count))
3722     return FALSE;
3723
3724   if (entry_count != 1) {
3725     GST_ERROR_OBJECT (qtdemux, "multiple offsets are not supported");
3726     return FALSE;
3727   }
3728
3729   if (version == 0) {
3730     if (!gst_byte_reader_get_uint32_be (br, &off_32))
3731       return FALSE;
3732     *offset = (guint64) off_32;
3733   } else {
3734     if (!gst_byte_reader_get_uint64_be (br, &off_64))
3735       return FALSE;
3736     *offset = off_64;
3737   }
3738
3739   GST_DEBUG_OBJECT (qtdemux, "offset: %" G_GUINT64_FORMAT, *offset);
3740   return TRUE;
3741 }
3742
3743 static void
3744 qtdemux_gst_structure_free (GstStructure * gststructure)
3745 {
3746   if (gststructure) {
3747     gst_structure_free (gststructure);
3748   }
3749 }
3750
3751 /* Parses auxiliary information relating to samples protected using Common
3752  * Encryption (cenc); the format of this information is defined in
3753  * ISO/IEC 23001-7. Returns TRUE if successful; FALSE otherwise. */
3754 static gboolean
3755 qtdemux_parse_cenc_aux_info (GstQTDemux * qtdemux, QtDemuxStream * stream,
3756     GstByteReader * br, guint8 * info_sizes, guint32 sample_count)
3757 {
3758   QtDemuxCencSampleSetInfo *ss_info = NULL;
3759   guint8 size;
3760   gint i;
3761
3762   g_return_val_if_fail (qtdemux != NULL, FALSE);
3763   g_return_val_if_fail (stream != NULL, FALSE);
3764   g_return_val_if_fail (br != NULL, FALSE);
3765   g_return_val_if_fail (stream->protected, FALSE);
3766   g_return_val_if_fail (stream->protection_scheme_info != NULL, FALSE);
3767
3768   ss_info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
3769
3770   if (ss_info->crypto_info) {
3771     GST_LOG_OBJECT (qtdemux, "unreffing existing crypto_info");
3772     g_ptr_array_free (ss_info->crypto_info, TRUE);
3773   }
3774
3775   ss_info->crypto_info =
3776       g_ptr_array_new_full (sample_count,
3777       (GDestroyNotify) qtdemux_gst_structure_free);
3778
3779   for (i = 0; i < sample_count; ++i) {
3780     GstStructure *properties;
3781     guint16 n_subsamples;
3782     guint8 *data;
3783     guint iv_size;
3784     GstBuffer *buf;
3785
3786     properties = qtdemux_get_cenc_sample_properties (qtdemux, stream, i);
3787     if (properties == NULL) {
3788       GST_ERROR_OBJECT (qtdemux, "failed to get properties for sample %u", i);
3789       return FALSE;
3790     }
3791     if (!gst_structure_get_uint (properties, "iv_size", &iv_size)) {
3792       GST_ERROR_OBJECT (qtdemux, "failed to get iv_size for sample %u", i);
3793       gst_structure_free (properties);
3794       return FALSE;
3795     }
3796     if (!gst_byte_reader_dup_data (br, iv_size, &data)) {
3797       GST_ERROR_OBJECT (qtdemux, "failed to get IV for sample %u", i);
3798       gst_structure_free (properties);
3799       return FALSE;
3800     }
3801     buf = gst_buffer_new_wrapped (data, iv_size);
3802     gst_structure_set (properties, "iv", GST_TYPE_BUFFER, buf, NULL);
3803     size = info_sizes[i];
3804     if (size > iv_size) {
3805       if (!gst_byte_reader_get_uint16_be (br, &n_subsamples)
3806           || !(n_subsamples > 0)) {
3807         gst_structure_free (properties);
3808         GST_ERROR_OBJECT (qtdemux,
3809             "failed to get subsample count for sample %u", i);
3810         return FALSE;
3811       }
3812       GST_LOG_OBJECT (qtdemux, "subsample count: %u", n_subsamples);
3813       if (!gst_byte_reader_dup_data (br, n_subsamples * 6, &data)) {
3814         GST_ERROR_OBJECT (qtdemux, "failed to get subsample data for sample %u",
3815             i);
3816         gst_structure_free (properties);
3817         return FALSE;
3818       }
3819       buf = gst_buffer_new_wrapped (data, n_subsamples * 6);
3820       if (!buf) {
3821         gst_structure_free (properties);
3822         return FALSE;
3823       }
3824       gst_structure_set (properties,
3825           "subsample_count", G_TYPE_UINT, n_subsamples,
3826           "subsamples", GST_TYPE_BUFFER, buf, NULL);
3827     } else {
3828       gst_structure_set (properties, "subsample_count", G_TYPE_UINT, 0, NULL);
3829     }
3830     g_ptr_array_add (ss_info->crypto_info, properties);
3831   }
3832   return TRUE;
3833 }
3834
3835 /* Converts a UUID in raw byte form to a string representation, as defined in
3836  * RFC 4122. The caller takes ownership of the returned string and is
3837  * responsible for freeing it after use. */
3838 static gchar *
3839 qtdemux_uuid_bytes_to_string (gconstpointer uuid_bytes)
3840 {
3841   const guint8 *uuid = (const guint8 *) uuid_bytes;
3842
3843   return g_strdup_printf ("%02x%02x%02x%02x-%02x%02x-%02x%02x-"
3844       "%02x%02x-%02x%02x%02x%02x%02x%02x",
3845       uuid[0], uuid[1], uuid[2], uuid[3],
3846       uuid[4], uuid[5], uuid[6], uuid[7],
3847       uuid[8], uuid[9], uuid[10], uuid[11],
3848       uuid[12], uuid[13], uuid[14], uuid[15]);
3849 }
3850
3851 /* Parses a Protection System Specific Header box (pssh), as defined in the
3852  * Common Encryption (cenc) standard (ISO/IEC 23001-7), which contains
3853  * information needed by a specific content protection system in order to
3854  * decrypt cenc-protected tracks. Returns TRUE if successful; FALSE
3855  * otherwise. */
3856 static gboolean
3857 qtdemux_parse_pssh (GstQTDemux * qtdemux, GNode * node)
3858 {
3859   gchar *sysid_string;
3860   guint32 pssh_size = QT_UINT32 (node->data);
3861   GstBuffer *pssh = NULL;
3862   GstEvent *event = NULL;
3863   guint32 parent_box_type;
3864   gint i;
3865
3866   if (G_UNLIKELY (pssh_size < 32U)) {
3867     GST_ERROR_OBJECT (qtdemux, "invalid box size");
3868     return FALSE;
3869   }
3870
3871   sysid_string =
3872       qtdemux_uuid_bytes_to_string ((const guint8 *) node->data + 12);
3873
3874   gst_qtdemux_append_protection_system_id (qtdemux, sysid_string);
3875
3876   pssh = gst_buffer_new_wrapped (g_memdup (node->data, pssh_size), pssh_size);
3877   GST_LOG_OBJECT (qtdemux, "cenc pssh size: %" G_GSIZE_FORMAT,
3878       gst_buffer_get_size (pssh));
3879
3880   parent_box_type = QT_FOURCC ((const guint8 *) node->parent->data + 4);
3881
3882   /* Push an event containing the pssh box onto the queues of all streams. */
3883   event = gst_event_new_protection (sysid_string, pssh,
3884       (parent_box_type == FOURCC_moov) ? "isobmff/moov" : "isobmff/moof");
3885   for (i = 0; i < qtdemux->n_streams; ++i) {
3886     g_queue_push_tail (&qtdemux->streams[i]->protection_scheme_event_queue,
3887         gst_event_ref (event));
3888   }
3889   g_free (sysid_string);
3890   gst_event_unref (event);
3891   gst_buffer_unref (pssh);
3892   return TRUE;
3893 }
3894
3895 static gboolean
3896 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
3897     guint64 moof_offset, QtDemuxStream * stream)
3898 {
3899   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
3900   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
3901   GNode *saiz_node, *saio_node, *pssh_node;
3902   GstByteReader saiz_data, saio_data;
3903   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
3904   gint64 base_offset, running_offset;
3905   guint32 frag_num;
3906
3907   /* NOTE @stream ignored */
3908
3909   moof_node = g_node_new ((guint8 *) buffer);
3910   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
3911   qtdemux_node_dump (qtdemux, moof_node);
3912
3913   /* Get fragment number from mfhd and check it's valid */
3914   mfhd_node =
3915       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
3916   if (mfhd_node == NULL)
3917     goto missing_mfhd;
3918   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
3919     goto fail;
3920   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
3921
3922   /* unknown base_offset to start with */
3923   base_offset = running_offset = -1;
3924   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
3925   while (traf_node) {
3926     guint64 decode_time = 0;
3927
3928     /* Fragment Header node */
3929     tfhd_node =
3930         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
3931         &tfhd_data);
3932     if (!tfhd_node)
3933       goto missing_tfhd;
3934     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
3935             &ds_size, &ds_flags, &base_offset))
3936       goto missing_tfhd;
3937
3938     /* The following code assumes at most a single set of sample auxiliary
3939      * data in the fragment (consisting of a saiz box and a corresponding saio
3940      * box); in theory, however, there could be multiple sets of sample
3941      * auxiliary data in a fragment. */
3942     saiz_node =
3943         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saiz,
3944         &saiz_data);
3945     if (saiz_node) {
3946       guint8 *info_sizes;
3947       guint32 sample_count;
3948       guint32 info_type = 0;
3949       guint64 offset = 0;
3950       guint32 info_type_parameter = 0;
3951
3952       info_sizes = qtdemux_parse_saiz (qtdemux, stream, &saiz_data,
3953           &sample_count);
3954       if (G_UNLIKELY (info_sizes == NULL)) {
3955         GST_ERROR_OBJECT (qtdemux, "failed to parse saiz box");
3956         goto fail;
3957       }
3958       saio_node =
3959           qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_saio,
3960           &saio_data);
3961       if (!saio_node) {
3962         GST_ERROR_OBJECT (qtdemux, "saiz box without a corresponding saio box");
3963         goto fail;
3964       }
3965
3966       if (G_UNLIKELY (!qtdemux_parse_saio (qtdemux, stream, &saio_data,
3967                   &info_type, &info_type_parameter, &offset))) {
3968         GST_ERROR_OBJECT (qtdemux, "failed to parse saio box");
3969         g_free (info_sizes);
3970         goto fail;
3971       }
3972       if (base_offset > qtdemux->moof_offset)
3973         offset += (guint64) (base_offset - qtdemux->moof_offset);
3974       if (info_type == FOURCC_cenc && info_type_parameter == 0U) {
3975         GstByteReader br;
3976         if (offset > length) {
3977           GST_ERROR_OBJECT (qtdemux, "cenc auxiliary info outside moof "
3978               "boxes is not supported");
3979           g_free (info_sizes);
3980           goto fail;
3981         }
3982         gst_byte_reader_init (&br, buffer + offset, length - offset);
3983         if (!qtdemux_parse_cenc_aux_info (qtdemux, stream, &br,
3984                 info_sizes, sample_count)) {
3985           GST_ERROR_OBJECT (qtdemux, "failed to parse cenc auxiliary info");
3986           goto fail;
3987         }
3988       }
3989       g_free (info_sizes);
3990     }
3991
3992     tfdt_node =
3993         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
3994         &tfdt_data);
3995     if (tfdt_node) {
3996       GstClockTime decode_time_ts;
3997
3998       /* We'll use decode_time to interpolate timestamps
3999        * in case the input timestamps are missing */
4000       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
4001
4002       decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
4003
4004       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
4005           " (%" GST_TIME_FORMAT ")", decode_time,
4006           GST_TIME_ARGS (decode_time_ts));
4007
4008       /* Discard the fragment buffer timestamp info to avoid using it.
4009        * Rely on tfdt instead as it is more accurate than the timestamp
4010        * that is fetched from a manifest/playlist and is usually
4011        * less accurate. */
4012       qtdemux->fragment_start = -1;
4013     }
4014
4015     if (G_UNLIKELY (!stream)) {
4016       /* we lost track of offset, we'll need to regain it,
4017        * but can delay complaining until later or avoid doing so altogether */
4018       base_offset = -2;
4019       goto next;
4020     }
4021     if (G_UNLIKELY (base_offset < -1))
4022       goto lost_offset;
4023
4024     if (qtdemux->upstream_format_is_time)
4025       gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
4026
4027     /* Track Run node */
4028     trun_node =
4029         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
4030         &trun_data);
4031     while (trun_node) {
4032       qtdemux_parse_trun (qtdemux, &trun_data, stream,
4033           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
4034           &running_offset, decode_time);
4035       /* iterate all siblings */
4036       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
4037           &trun_data);
4038     }
4039     /* if no new base_offset provided for next traf,
4040      * base is end of current traf */
4041     base_offset = running_offset;
4042     running_offset = -1;
4043   next:
4044     /* iterate all siblings */
4045     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
4046   }
4047
4048   /* parse any protection system info */
4049   pssh_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_pssh);
4050   while (pssh_node) {
4051     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
4052     qtdemux_parse_pssh (qtdemux, pssh_node);
4053     pssh_node = qtdemux_tree_get_sibling_by_type (pssh_node, FOURCC_pssh);
4054   }
4055
4056   g_node_destroy (moof_node);
4057   return TRUE;
4058
4059 missing_tfhd:
4060   {
4061     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
4062     goto fail;
4063   }
4064 missing_mfhd:
4065   {
4066     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
4067     goto fail;
4068   }
4069 lost_offset:
4070   {
4071     GST_DEBUG_OBJECT (qtdemux, "lost offset");
4072     goto fail;
4073   }
4074 fail:
4075   {
4076     g_node_destroy (moof_node);
4077     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4078         (_("This file is corrupt and cannot be played.")), (NULL));
4079     return FALSE;
4080   }
4081 }
4082
4083 #if 0
4084 /* might be used if some day we actually use mfra & co
4085  * for random access to fragments,
4086  * but that will require quite some modifications and much less relying
4087  * on a sample array */
4088 #endif
4089
4090 static gboolean
4091 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
4092 {
4093   QtDemuxStream *stream;
4094   guint32 ver_flags, track_id, len, num_entries, i;
4095   guint value_size, traf_size, trun_size, sample_size;
4096   guint64 time = 0, moof_offset = 0;
4097 #if 0
4098   GstBuffer *buf = NULL;
4099   GstFlowReturn ret;
4100 #endif
4101   GstByteReader tfra;
4102
4103   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
4104
4105   if (!gst_byte_reader_skip (&tfra, 8))
4106     return FALSE;
4107
4108   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
4109     return FALSE;
4110
4111   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
4112       || !gst_byte_reader_get_uint32_be (&tfra, &len)
4113       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
4114     return FALSE;
4115
4116   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
4117
4118   stream = qtdemux_find_stream (qtdemux, track_id);
4119   if (stream == NULL)
4120     goto unknown_trackid;
4121
4122   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
4123   sample_size = (len & 3) + 1;
4124   trun_size = ((len & 12) >> 2) + 1;
4125   traf_size = ((len & 48) >> 4) + 1;
4126
4127   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
4128       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
4129
4130   if (num_entries == 0)
4131     goto no_samples;
4132
4133   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
4134           value_size + value_size + traf_size + trun_size + sample_size))
4135     goto corrupt_file;
4136
4137   g_free (stream->ra_entries);
4138   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
4139   stream->n_ra_entries = num_entries;
4140
4141   for (i = 0; i < num_entries; i++) {
4142     qt_atom_parser_get_offset (&tfra, value_size, &time);
4143     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
4144     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
4145     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
4146     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
4147
4148     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
4149
4150     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
4151         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
4152
4153     stream->ra_entries[i].ts = time;
4154     stream->ra_entries[i].moof_offset = moof_offset;
4155
4156     /* don't want to go through the entire file and read all moofs at startup */
4157 #if 0
4158     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
4159     if (ret != GST_FLOW_OK)
4160       goto corrupt_file;
4161     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
4162         moof_offset, stream);
4163     gst_buffer_unref (buf);
4164 #endif
4165   }
4166
4167   check_update_duration (qtdemux, time);
4168
4169   return TRUE;
4170
4171 /* ERRORS */
4172 unknown_trackid:
4173   {
4174     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
4175     return FALSE;
4176   }
4177 corrupt_file:
4178   {
4179     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
4180     return FALSE;
4181   }
4182 no_samples:
4183   {
4184     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
4185     return FALSE;
4186   }
4187 }
4188
4189 static gboolean
4190 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
4191 {
4192   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
4193   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
4194   GstBuffer *mfro = NULL, *mfra = NULL;
4195   GstFlowReturn flow;
4196   gboolean ret = FALSE;
4197   GNode *mfra_node, *tfra_node;
4198   guint64 mfra_offset = 0;
4199   guint32 fourcc, mfra_size;
4200   gint64 len;
4201
4202   /* query upstream size in bytes */
4203   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
4204     goto size_query_failed;
4205
4206   /* mfro box should be at the very end of the file */
4207   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
4208   if (flow != GST_FLOW_OK)
4209     goto exit;
4210
4211   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
4212
4213   fourcc = QT_FOURCC (mfro_map.data + 4);
4214   if (fourcc != FOURCC_mfro)
4215     goto exit;
4216
4217   GST_INFO_OBJECT (qtdemux, "Found mfro box");
4218   if (mfro_map.size < 16)
4219     goto invalid_mfro_size;
4220
4221   mfra_size = QT_UINT32 (mfro_map.data + 12);
4222   if (mfra_size >= len)
4223     goto invalid_mfra_size;
4224
4225   mfra_offset = len - mfra_size;
4226
4227   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
4228       mfra_offset, mfra_size);
4229
4230   /* now get and parse mfra box */
4231   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
4232   if (flow != GST_FLOW_OK)
4233     goto broken_file;
4234
4235   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
4236
4237   mfra_node = g_node_new ((guint8 *) mfra_map.data);
4238   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
4239
4240   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
4241
4242   while (tfra_node) {
4243     qtdemux_parse_tfra (qtdemux, tfra_node);
4244     /* iterate all siblings */
4245     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
4246   }
4247   g_node_destroy (mfra_node);
4248
4249   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
4250   ret = TRUE;
4251
4252 exit:
4253
4254   if (mfro) {
4255     if (mfro_map.memory != NULL)
4256       gst_buffer_unmap (mfro, &mfro_map);
4257     gst_buffer_unref (mfro);
4258   }
4259   if (mfra) {
4260     if (mfra_map.memory != NULL)
4261       gst_buffer_unmap (mfra, &mfra_map);
4262     gst_buffer_unref (mfra);
4263   }
4264   return ret;
4265
4266 /* ERRORS */
4267 size_query_failed:
4268   {
4269     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
4270     goto exit;
4271   }
4272 invalid_mfro_size:
4273   {
4274     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
4275     goto exit;
4276   }
4277 invalid_mfra_size:
4278   {
4279     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
4280     goto exit;
4281   }
4282 broken_file:
4283   {
4284     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
4285     goto exit;
4286   }
4287 }
4288
4289 static guint64
4290 add_offset (guint64 offset, guint64 advance)
4291 {
4292   /* Avoid 64-bit overflow by clamping */
4293   if (offset > G_MAXUINT64 - advance)
4294     return G_MAXUINT64;
4295   return offset + advance;
4296 }
4297
4298 static GstFlowReturn
4299 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
4300 {
4301   guint64 length = 0;
4302   guint32 fourcc = 0;
4303   GstBuffer *buf = NULL;
4304   GstFlowReturn ret = GST_FLOW_OK;
4305   guint64 cur_offset = qtdemux->offset;
4306   GstMapInfo map;
4307
4308   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
4309   if (G_UNLIKELY (ret != GST_FLOW_OK))
4310     goto beach;
4311   gst_buffer_map (buf, &map, GST_MAP_READ);
4312   if (G_LIKELY (map.size >= 8))
4313     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
4314   gst_buffer_unmap (buf, &map);
4315   gst_buffer_unref (buf);
4316
4317   /* maybe we already got most we needed, so only consider this eof */
4318   if (G_UNLIKELY (length == 0)) {
4319     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
4320         (_("Invalid atom size.")),
4321         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
4322             GST_FOURCC_ARGS (fourcc)));
4323     ret = GST_FLOW_EOS;
4324     goto beach;
4325   }
4326
4327   switch (fourcc) {
4328     case FOURCC_moof:
4329       /* record for later parsing when needed */
4330       if (!qtdemux->moof_offset) {
4331         qtdemux->moof_offset = qtdemux->offset;
4332       }
4333       if (qtdemux_pull_mfro_mfra (qtdemux)) {
4334         /* FIXME */
4335       } else {
4336         qtdemux->offset += length;      /* skip moof and keep going */
4337       }
4338       if (qtdemux->got_moov) {
4339         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
4340         ret = GST_FLOW_EOS;
4341         goto beach;
4342       }
4343       break;
4344     case FOURCC_mdat:
4345     case FOURCC_free:
4346     case FOURCC_wide:
4347     case FOURCC_PICT:
4348     case FOURCC_pnot:
4349     {
4350       GST_LOG_OBJECT (qtdemux,
4351           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
4352           GST_FOURCC_ARGS (fourcc), cur_offset);
4353       qtdemux->offset = add_offset (qtdemux->offset, length);
4354       break;
4355     }
4356     case FOURCC_moov:
4357     {
4358       GstBuffer *moov = NULL;
4359
4360       if (qtdemux->got_moov) {
4361         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
4362         qtdemux->offset = add_offset (qtdemux->offset, length);
4363         goto beach;
4364       }
4365
4366       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
4367       if (ret != GST_FLOW_OK)
4368         goto beach;
4369       gst_buffer_map (moov, &map, GST_MAP_READ);
4370
4371       if (length != map.size) {
4372         /* Some files have a 'moov' atom at the end of the file which contains
4373          * a terminal 'free' atom where the body of the atom is missing.
4374          * Check for, and permit, this special case.
4375          */
4376         if (map.size >= 8) {
4377           guint8 *final_data = map.data + (map.size - 8);
4378           guint32 final_length = QT_UINT32 (final_data);
4379           guint32 final_fourcc = QT_FOURCC (final_data + 4);
4380
4381           if (final_fourcc == FOURCC_free
4382               && map.size + final_length - 8 == length) {
4383             /* Ok, we've found that special case. Allocate a new buffer with
4384              * that free atom actually present. */
4385             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
4386             gst_buffer_fill (newmoov, 0, map.data, map.size);
4387             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
4388             gst_buffer_unmap (moov, &map);
4389             gst_buffer_unref (moov);
4390             moov = newmoov;
4391             gst_buffer_map (moov, &map, GST_MAP_READ);
4392           }
4393         }
4394       }
4395
4396       if (length != map.size) {
4397         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
4398             (_("This file is incomplete and cannot be played.")),
4399             ("We got less than expected (received %" G_GSIZE_FORMAT
4400                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
4401                 (guint) length, cur_offset));
4402         gst_buffer_unmap (moov, &map);
4403         gst_buffer_unref (moov);
4404         ret = GST_FLOW_ERROR;
4405         goto beach;
4406       }
4407       qtdemux->offset += length;
4408
4409       qtdemux_parse_moov (qtdemux, map.data, length);
4410       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
4411
4412       qtdemux_parse_tree (qtdemux);
4413       g_node_destroy (qtdemux->moov_node);
4414       gst_buffer_unmap (moov, &map);
4415       gst_buffer_unref (moov);
4416       qtdemux->moov_node = NULL;
4417       qtdemux->got_moov = TRUE;
4418
4419       break;
4420     }
4421     case FOURCC_ftyp:
4422     {
4423       GstBuffer *ftyp = NULL;
4424
4425       /* extract major brand; might come in handy for ISO vs QT issues */
4426       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
4427       if (ret != GST_FLOW_OK)
4428         goto beach;
4429       qtdemux->offset += length;
4430       gst_buffer_map (ftyp, &map, GST_MAP_READ);
4431       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
4432       gst_buffer_unmap (ftyp, &map);
4433       gst_buffer_unref (ftyp);
4434       break;
4435     }
4436     case FOURCC_uuid:
4437     {
4438       GstBuffer *uuid = NULL;
4439
4440       /* uuid are extension atoms */
4441       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
4442       if (ret != GST_FLOW_OK)
4443         goto beach;
4444       qtdemux->offset += length;
4445       gst_buffer_map (uuid, &map, GST_MAP_READ);
4446       qtdemux_parse_uuid (qtdemux, map.data, map.size);
4447       gst_buffer_unmap (uuid, &map);
4448       gst_buffer_unref (uuid);
4449       break;
4450     }
4451     case FOURCC_sidx:
4452     {
4453       GstBuffer *sidx = NULL;
4454       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &sidx);
4455       if (ret != GST_FLOW_OK)
4456         goto beach;
4457       qtdemux->offset += length;
4458       gst_buffer_map (sidx, &map, GST_MAP_READ);
4459       qtdemux_parse_sidx (qtdemux, map.data, map.size);
4460       gst_buffer_unmap (sidx, &map);
4461       gst_buffer_unref (sidx);
4462       break;
4463     }
4464     default:
4465     {
4466       GstBuffer *unknown = NULL;
4467
4468       GST_LOG_OBJECT (qtdemux,
4469           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
4470           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
4471           cur_offset);
4472       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
4473       if (ret != GST_FLOW_OK)
4474         goto beach;
4475       gst_buffer_map (unknown, &map, GST_MAP_READ);
4476       GST_MEMDUMP ("Unknown tag", map.data, map.size);
4477       gst_buffer_unmap (unknown, &map);
4478       gst_buffer_unref (unknown);
4479       qtdemux->offset += length;
4480       break;
4481     }
4482   }
4483
4484 beach:
4485   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
4486     /* digested all data, show what we have */
4487 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
4488     if (spherical_metadata)
4489       _send_message_to_bus (qtdemux, spherical_metadata);
4490 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
4491     qtdemux_prepare_streams (qtdemux);
4492     ret = qtdemux_expose_streams (qtdemux);
4493
4494     qtdemux->state = QTDEMUX_STATE_MOVIE;
4495     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
4496         qtdemux->state);
4497     return ret;
4498   }
4499   return ret;
4500 }
4501
4502 /* Seeks to the previous keyframe of the indexed stream and
4503  * aligns other streams with respect to the keyframe timestamp
4504  * of indexed stream. Only called in case of Reverse Playback
4505  */
4506 static GstFlowReturn
4507 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
4508 {
4509   guint8 n = 0;
4510   guint32 seg_idx = 0, k_index = 0;
4511   guint32 ref_seg_idx, ref_k_index;
4512   GstClockTime k_pos = 0, last_stop = 0;
4513   QtDemuxSegment *seg = NULL;
4514   QtDemuxStream *ref_str = NULL;
4515   guint64 seg_media_start_mov;  /* segment media start time in mov format */
4516   guint64 target_ts;
4517
4518   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
4519    * and finally align all the other streams on that timestamp with their
4520    * respective keyframes */
4521   for (n = 0; n < qtdemux->n_streams; n++) {
4522     QtDemuxStream *str = qtdemux->streams[n];
4523
4524     /* No candidate yet, take the first stream */
4525     if (!ref_str) {
4526       ref_str = str;
4527       continue;
4528     }
4529
4530     /* So that stream has a segment, we prefer video streams */
4531     if (str->subtype == FOURCC_vide) {
4532       ref_str = str;
4533       break;
4534     }
4535   }
4536
4537   if (G_UNLIKELY (!ref_str)) {
4538     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
4539     goto eos;
4540   }
4541
4542   if (G_UNLIKELY (!ref_str->from_sample)) {
4543     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
4544     goto eos;
4545   }
4546
4547   /* So that stream has been playing from from_sample to to_sample. We will
4548    * get the timestamp of the previous sample and search for a keyframe before
4549    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
4550   if (ref_str->subtype == FOURCC_vide) {
4551     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
4552         ref_str->from_sample - 1);
4553   } else {
4554     if (ref_str->from_sample >= 10)
4555       k_index = ref_str->from_sample - 10;
4556     else
4557       k_index = 0;
4558   }
4559
4560   target_ts =
4561       ref_str->samples[k_index].timestamp +
4562       ref_str->samples[k_index].pts_offset;
4563
4564   /* get current segment for that stream */
4565   seg = &ref_str->segments[ref_str->segment_index];
4566   /* Use segment start in original timescale for comparisons */
4567   seg_media_start_mov = seg->trak_media_start;
4568
4569   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
4570       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
4571       k_index, target_ts, seg_media_start_mov,
4572       GST_TIME_ARGS (seg->media_start));
4573
4574   /* Crawl back through segments to find the one containing this I frame */
4575   while (target_ts < seg_media_start_mov) {
4576     GST_DEBUG_OBJECT (qtdemux,
4577         "keyframe position (sample %u) is out of segment %u " " target %"
4578         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
4579         ref_str->segment_index, target_ts, seg_media_start_mov);
4580
4581     if (G_UNLIKELY (!ref_str->segment_index)) {
4582       /* Reached first segment, let's consider it's EOS */
4583       goto eos;
4584     }
4585     ref_str->segment_index--;
4586     seg = &ref_str->segments[ref_str->segment_index];
4587     /* Use segment start in original timescale for comparisons */
4588     seg_media_start_mov = seg->trak_media_start;
4589   }
4590   /* Calculate time position of the keyframe and where we should stop */
4591   k_pos =
4592       QTSTREAMTIME_TO_GSTTIME (ref_str,
4593       target_ts - seg->trak_media_start) + seg->time;
4594   last_stop =
4595       QTSTREAMTIME_TO_GSTTIME (ref_str,
4596       ref_str->samples[ref_str->from_sample].timestamp -
4597       seg->trak_media_start) + seg->time;
4598
4599   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
4600       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
4601       k_index, GST_TIME_ARGS (k_pos));
4602
4603   /* Set last_stop with the keyframe timestamp we pushed of that stream */
4604   qtdemux->segment.position = last_stop;
4605   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
4606       GST_TIME_ARGS (last_stop));
4607
4608   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
4609     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
4610     goto eos;
4611   }
4612
4613   ref_seg_idx = ref_str->segment_index;
4614   ref_k_index = k_index;
4615
4616   /* Align them all on this */
4617   for (n = 0; n < qtdemux->n_streams; n++) {
4618     guint32 index = 0;
4619     GstClockTime seg_time = 0;
4620     QtDemuxStream *str = qtdemux->streams[n];
4621
4622     /* aligning reference stream again might lead to backing up to yet another
4623      * keyframe (due to timestamp rounding issues),
4624      * potentially putting more load on downstream; so let's try to avoid */
4625     if (str == ref_str) {
4626       seg_idx = ref_seg_idx;
4627       seg = &str->segments[seg_idx];
4628       k_index = ref_k_index;
4629       GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
4630           "sample at index %d", n, ref_str->segment_index, k_index);
4631     } else {
4632       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
4633       GST_DEBUG_OBJECT (qtdemux,
4634           "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
4635           seg_idx, GST_TIME_ARGS (k_pos));
4636
4637       /* get segment and time in the segment */
4638       seg = &str->segments[seg_idx];
4639       seg_time = k_pos - seg->time;
4640
4641       /* get the media time in the segment.
4642        * No adjustment for empty "filler" segments */
4643       if (seg->media_start != GST_CLOCK_TIME_NONE)
4644         seg_time += seg->media_start;
4645
4646       /* get the index of the sample with media time */
4647       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
4648       GST_DEBUG_OBJECT (qtdemux,
4649           "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
4650           GST_TIME_ARGS (seg_time), index);
4651
4652       /* find previous keyframe */
4653       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
4654     }
4655
4656     /* Remember until where we want to go */
4657     str->to_sample = str->from_sample - 1;
4658     /* Define our time position */
4659     target_ts =
4660         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
4661     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
4662     if (seg->media_start != GST_CLOCK_TIME_NONE)
4663       str->time_position -= seg->media_start;
4664
4665     /* Now seek back in time */
4666     gst_qtdemux_move_stream (qtdemux, str, k_index);
4667     GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
4668         GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
4669         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
4670   }
4671
4672   return GST_FLOW_OK;
4673
4674 eos:
4675   return GST_FLOW_EOS;
4676 }
4677
4678 /* activate the given segment number @seg_idx of @stream at time @offset.
4679  * @offset is an absolute global position over all the segments.
4680  *
4681  * This will push out a NEWSEGMENT event with the right values and
4682  * position the stream index to the first decodable sample before
4683  * @offset.
4684  *
4685  * PULL-BASED
4686  */
4687 static gboolean
4688 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4689     guint32 seg_idx, GstClockTime offset)
4690 {
4691   GstEvent *event;
4692   QtDemuxSegment *segment;
4693   guint32 index, kf_index;
4694   GstClockTime seg_time;
4695   GstClockTime start, stop, time;
4696   gdouble rate;
4697
4698   GST_LOG_OBJECT (stream->pad, "activate segment %d, offset %" GST_TIME_FORMAT,
4699       seg_idx, GST_TIME_ARGS (offset));
4700
4701   /* update the current segment */
4702   stream->segment_index = seg_idx;
4703
4704   /* get the segment */
4705   segment = &stream->segments[seg_idx];
4706
4707   if (G_UNLIKELY (offset < segment->time)) {
4708     GST_WARNING_OBJECT (stream->pad, "offset < segment->time %" GST_TIME_FORMAT,
4709         GST_TIME_ARGS (segment->time));
4710     return FALSE;
4711   }
4712
4713   /* segment lies beyond total indicated duration */
4714   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
4715           segment->time > qtdemux->segment.duration)) {
4716     GST_WARNING_OBJECT (stream->pad, "file duration %" GST_TIME_FORMAT
4717         " < segment->time %" GST_TIME_FORMAT,
4718         GST_TIME_ARGS (qtdemux->segment.duration),
4719         GST_TIME_ARGS (segment->time));
4720     return FALSE;
4721   }
4722
4723   /* get time in this segment */
4724   seg_time = offset - segment->time;
4725
4726   GST_LOG_OBJECT (stream->pad, "seg_time %" GST_TIME_FORMAT,
4727       GST_TIME_ARGS (seg_time));
4728
4729   if (G_UNLIKELY (seg_time > segment->duration)) {
4730     GST_LOG_OBJECT (stream->pad,
4731         "seg_time > segment->duration %" GST_TIME_FORMAT,
4732         GST_TIME_ARGS (segment->duration));
4733     seg_time = segment->duration;
4734   }
4735
4736   /* qtdemux->segment.stop is in outside-time-realm, whereas
4737    * segment->media_stop is in track-time-realm.
4738    *
4739    * In order to compare the two, we need to bring segment.stop
4740    * into the track-time-realm */
4741
4742   stop = qtdemux->segment.stop;
4743   if (stop == GST_CLOCK_TIME_NONE)
4744     stop = qtdemux->segment.duration;
4745   if (stop == GST_CLOCK_TIME_NONE)
4746     stop = segment->media_stop;
4747   else
4748     stop =
4749         MIN (segment->media_stop, stop - segment->time + segment->media_start);
4750
4751   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
4752     start = segment->time + seg_time;
4753     time = offset;
4754     stop = start - seg_time + segment->duration;
4755   } else if (qtdemux->segment.rate >= 0) {
4756     start = MIN (segment->media_start + seg_time, stop);
4757     time = offset;
4758   } else {
4759     if (segment->media_start >= qtdemux->segment.start) {
4760       time = segment->time;
4761     } else {
4762       time = segment->time + (qtdemux->segment.start - segment->media_start);
4763     }
4764
4765     start = MAX (segment->media_start, qtdemux->segment.start);
4766     stop = MIN (segment->media_start + seg_time, stop);
4767   }
4768
4769   GST_DEBUG_OBJECT (stream->pad, "new segment %d from %" GST_TIME_FORMAT
4770       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
4771       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
4772
4773   /* combine global rate with that of the segment */
4774   rate = segment->rate * qtdemux->segment.rate;
4775
4776   /* Copy flags from main segment */
4777   stream->segment.flags = qtdemux->segment.flags;
4778
4779   /* update the segment values used for clipping */
4780   stream->segment.offset = qtdemux->segment.offset;
4781   stream->segment.base = qtdemux->segment.base + stream->accumulated_base;
4782   stream->segment.applied_rate = qtdemux->segment.applied_rate;
4783   stream->segment.rate = rate;
4784   stream->segment.start = start + QTSTREAMTIME_TO_GSTTIME (stream,
4785       stream->cslg_shift);
4786   stream->segment.stop = stop + QTSTREAMTIME_TO_GSTTIME (stream,
4787       stream->cslg_shift);
4788   stream->segment.time = time;
4789   stream->segment.position = stream->segment.start;
4790
4791   GST_DEBUG_OBJECT (stream->pad, "New segment: %" GST_SEGMENT_FORMAT,
4792       &stream->segment);
4793
4794   /* now prepare and send the segment */
4795   if (stream->pad) {
4796     event = gst_event_new_segment (&stream->segment);
4797     if (stream->segment_seqnum) {
4798       gst_event_set_seqnum (event, stream->segment_seqnum);
4799     }
4800     gst_pad_push_event (stream->pad, event);
4801     /* assume we can send more data now */
4802     GST_PAD_LAST_FLOW_RETURN (stream->pad) = GST_FLOW_OK;
4803     /* clear to send tags on this pad now */
4804     gst_qtdemux_push_tags (qtdemux, stream);
4805   }
4806
4807   /* in the fragmented case, we pick a fragment that starts before our
4808    * desired position and rely on downstream to wait for a keyframe
4809    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
4810    * tfra entries tells us which trun/sample the key unit is in, but we don't
4811    * make use of this additional information at the moment) */
4812   if (qtdemux->fragmented) {
4813     stream->to_sample = G_MAXUINT32;
4814     return TRUE;
4815   }
4816
4817   /* and move to the keyframe before the indicated media time of the
4818    * segment */
4819   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
4820     if (qtdemux->segment.rate >= 0) {
4821       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
4822       stream->to_sample = G_MAXUINT32;
4823       GST_DEBUG_OBJECT (stream->pad,
4824           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4825           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
4826           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4827     } else {
4828       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
4829       stream->to_sample = index;
4830       GST_DEBUG_OBJECT (stream->pad,
4831           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
4832           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
4833           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
4834     }
4835   } else {
4836     GST_DEBUG_OBJECT (stream->pad, "No need to look for keyframe, "
4837         "this is an empty segment");
4838     return TRUE;
4839   }
4840
4841   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
4842    * encountered an error and printed a message so we return appropriately */
4843   if (index == -1)
4844     return FALSE;
4845
4846   /* we're at the right spot */
4847   if (index == stream->sample_index) {
4848     GST_DEBUG_OBJECT (stream->pad, "we are at the right index");
4849     return TRUE;
4850   }
4851
4852   /* find keyframe of the target index */
4853   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
4854
4855 /* *INDENT-OFF* */
4856 /* indent does stupid stuff with stream->samples[].timestamp */
4857
4858   /* if we move forwards, we don't have to go back to the previous
4859    * keyframe since we already sent that. We can also just jump to
4860    * the keyframe right before the target index if there is one. */
4861   if (index > stream->sample_index) {
4862     /* moving forwards check if we move past a keyframe */
4863     if (kf_index > stream->sample_index) {
4864       GST_DEBUG_OBJECT (stream->pad,
4865            "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4866            GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4867            GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4868       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4869     } else {
4870       GST_DEBUG_OBJECT (stream->pad,
4871           "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
4872           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
4873           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
4874     }
4875   } else {
4876     GST_DEBUG_OBJECT (stream->pad,
4877         "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
4878         GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
4879         GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
4880     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
4881   }
4882
4883 /* *INDENT-ON* */
4884
4885   return TRUE;
4886 }
4887
4888 /* prepare to get the current sample of @stream, getting essential values.
4889  *
4890  * This function will also prepare and send the segment when needed.
4891  *
4892  * Return FALSE if the stream is EOS.
4893  *
4894  * PULL-BASED
4895  */
4896 static gboolean
4897 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
4898     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
4899     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
4900     gboolean * keyframe)
4901 {
4902   QtDemuxSample *sample;
4903   GstClockTime time_position;
4904   guint32 seg_idx;
4905
4906   g_return_val_if_fail (stream != NULL, FALSE);
4907
4908   time_position = stream->time_position;
4909   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
4910     goto eos;
4911
4912   seg_idx = stream->segment_index;
4913   if (G_UNLIKELY (seg_idx == -1)) {
4914     /* find segment corresponding to time_position if we are looking
4915      * for a segment. */
4916     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
4917   }
4918
4919   /* different segment, activate it, sample_index will be set. */
4920   if (G_UNLIKELY (stream->segment_index != seg_idx))
4921     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
4922
4923   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
4924                   segment_index]))) {
4925     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
4926
4927     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
4928         " prepare empty sample");
4929
4930     *empty = TRUE;
4931     *pts = *dts = time_position;
4932     *duration = seg->duration - (time_position - seg->time);
4933
4934     return TRUE;
4935   }
4936
4937   *empty = FALSE;
4938
4939   if (stream->sample_index == -1)
4940     stream->sample_index = 0;
4941
4942   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
4943       stream->sample_index, stream->n_samples);
4944
4945   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
4946     if (!qtdemux->fragmented)
4947       goto eos;
4948
4949     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
4950     do {
4951       GstFlowReturn flow;
4952
4953       GST_OBJECT_LOCK (qtdemux);
4954       flow = qtdemux_add_fragmented_samples (qtdemux);
4955       GST_OBJECT_UNLOCK (qtdemux);
4956
4957       if (flow != GST_FLOW_OK)
4958         goto eos;
4959     }
4960     while (stream->sample_index >= stream->n_samples);
4961   }
4962
4963   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
4964     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
4965         stream->sample_index);
4966     return FALSE;
4967   }
4968
4969   /* now get the info for the sample we're at */
4970   sample = &stream->samples[stream->sample_index];
4971
4972   *dts = QTSAMPLE_DTS (stream, sample);
4973   *pts = QTSAMPLE_PTS (stream, sample);
4974   *offset = sample->offset;
4975   *size = sample->size;
4976   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
4977   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
4978
4979   return TRUE;
4980
4981   /* special cases */
4982 eos:
4983   {
4984     stream->time_position = GST_CLOCK_TIME_NONE;
4985     return FALSE;
4986   }
4987 }
4988
4989 /* move to the next sample in @stream.
4990  *
4991  * Moves to the next segment when needed.
4992  */
4993 static void
4994 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
4995 {
4996   QtDemuxSample *sample;
4997   QtDemuxSegment *segment;
4998
4999   /* get current segment */
5000   segment = &stream->segments[stream->segment_index];
5001
5002   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
5003     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
5004     goto next_segment;
5005   }
5006
5007   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
5008     /* Mark the stream as EOS */
5009     GST_DEBUG_OBJECT (qtdemux,
5010         "reached max allowed sample %u, mark EOS", stream->to_sample);
5011     stream->time_position = GST_CLOCK_TIME_NONE;
5012     return;
5013   }
5014
5015   /* move to next sample */
5016   stream->sample_index++;
5017   stream->offset_in_sample = 0;
5018
5019   /* reached the last sample, we need the next segment */
5020   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
5021     goto next_segment;
5022
5023   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
5024     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
5025         stream->sample_index);
5026     return;
5027   }
5028
5029   /* get next sample */
5030   sample = &stream->samples[stream->sample_index];
5031
5032   /* see if we are past the segment */
5033   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
5034     goto next_segment;
5035
5036   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
5037     /* inside the segment, update time_position, looks very familiar to
5038      * GStreamer segments, doesn't it? */
5039     stream->time_position =
5040         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
5041   } else {
5042     /* not yet in segment, time does not yet increment. This means
5043      * that we are still prerolling keyframes to the decoder so it can
5044      * decode the first sample of the segment. */
5045     stream->time_position = segment->time;
5046   }
5047   return;
5048
5049   /* move to the next segment */
5050 next_segment:
5051   {
5052     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
5053
5054     if (stream->segment_index == stream->n_segments - 1) {
5055       /* are we at the end of the last segment, we're EOS */
5056       stream->time_position = GST_CLOCK_TIME_NONE;
5057     } else {
5058       /* else we're only at the end of the current segment */
5059       stream->time_position = segment->stop_time;
5060     }
5061     /* make sure we select a new segment */
5062
5063     /* accumulate previous segments */
5064     if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
5065       stream->accumulated_base +=
5066           (stream->segment.stop -
5067           stream->segment.start) / ABS (stream->segment.rate);
5068
5069     stream->segment_index = -1;
5070   }
5071 }
5072
5073 static void
5074 gst_qtdemux_sync_streams (GstQTDemux * demux)
5075 {
5076   gint i;
5077
5078   if (demux->n_streams <= 1)
5079     return;
5080
5081   for (i = 0; i < demux->n_streams; i++) {
5082     QtDemuxStream *stream;
5083     GstClockTime end_time;
5084
5085     stream = demux->streams[i];
5086
5087     if (!stream->pad)
5088       continue;
5089
5090     /* TODO advance time on subtitle streams here, if any some day */
5091
5092     /* some clips/trailers may have unbalanced streams at the end,
5093      * so send EOS on shorter stream to prevent stalling others */
5094
5095     /* do not mess with EOS if SEGMENT seeking */
5096     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
5097       continue;
5098
5099     if (demux->pullbased) {
5100       /* loop mode is sample time based */
5101       if (!STREAM_IS_EOS (stream))
5102         continue;
5103     } else {
5104       /* push mode is byte position based */
5105       if (stream->n_samples &&
5106           stream->samples[stream->n_samples - 1].offset >= demux->offset)
5107         continue;
5108     }
5109
5110     if (stream->sent_eos)
5111       continue;
5112
5113     /* only act if some gap */
5114     end_time = stream->segments[stream->n_segments - 1].stop_time;
5115     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
5116         ", stream end: %" GST_TIME_FORMAT,
5117         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
5118     if (GST_CLOCK_TIME_IS_VALID (end_time)
5119         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
5120       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
5121           GST_PAD_NAME (stream->pad));
5122       stream->sent_eos = TRUE;
5123       gst_pad_push_event (stream->pad, gst_event_new_eos ());
5124     }
5125   }
5126 }
5127
5128 /* EOS and NOT_LINKED need to be combined. This means that we return:
5129  *
5130  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
5131  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
5132  */
5133 static GstFlowReturn
5134 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
5135     GstFlowReturn ret)
5136 {
5137   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
5138
5139   if (stream->pad)
5140     ret = gst_flow_combiner_update_pad_flow (demux->flowcombiner, stream->pad,
5141         ret);
5142   else
5143     ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
5144
5145   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
5146   return ret;
5147 }
5148
5149 /* the input buffer metadata must be writable. Returns NULL when the buffer is
5150  * completely clipped
5151  *
5152  * Should be used only with raw buffers */
5153 static GstBuffer *
5154 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5155     GstBuffer * buf)
5156 {
5157   guint64 start, stop, cstart, cstop, diff;
5158   GstClockTime pts, duration;
5159   gsize size, osize;
5160   gint num_rate, denom_rate;
5161   gint frame_size;
5162   gboolean clip_data;
5163   guint offset;
5164
5165   osize = size = gst_buffer_get_size (buf);
5166   offset = 0;
5167
5168   /* depending on the type, setup the clip parameters */
5169   if (stream->subtype == FOURCC_soun) {
5170     frame_size = stream->bytes_per_frame;
5171     num_rate = GST_SECOND;
5172     denom_rate = (gint) stream->rate;
5173     clip_data = TRUE;
5174   } else if (stream->subtype == FOURCC_vide) {
5175     frame_size = size;
5176     num_rate = stream->fps_n;
5177     denom_rate = stream->fps_d;
5178     clip_data = FALSE;
5179   } else
5180     goto wrong_type;
5181
5182   if (frame_size <= 0)
5183     goto bad_frame_size;
5184
5185   /* we can only clip if we have a valid pts */
5186   pts = GST_BUFFER_PTS (buf);
5187   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
5188     goto no_pts;
5189
5190   duration = GST_BUFFER_DURATION (buf);
5191
5192   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
5193     duration =
5194         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
5195   }
5196
5197   start = pts;
5198   stop = start + duration;
5199
5200   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
5201               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
5202     goto clipped;
5203
5204   /* see if some clipping happened */
5205   diff = cstart - start;
5206   if (diff > 0) {
5207     pts += diff;
5208     duration -= diff;
5209
5210     if (clip_data) {
5211       /* bring clipped time to samples and to bytes */
5212       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5213       diff *= frame_size;
5214
5215       GST_DEBUG_OBJECT (qtdemux,
5216           "clipping start to %" GST_TIME_FORMAT " %"
5217           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
5218
5219       offset = diff;
5220       size -= diff;
5221     }
5222   }
5223   diff = stop - cstop;
5224   if (diff > 0) {
5225     duration -= diff;
5226
5227     if (clip_data) {
5228       /* bring clipped time to samples and then to bytes */
5229       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
5230       diff *= frame_size;
5231       GST_DEBUG_OBJECT (qtdemux,
5232           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
5233           " bytes", GST_TIME_ARGS (cstop), diff);
5234       size -= diff;
5235     }
5236   }
5237
5238   if (offset != 0 || size != osize)
5239     gst_buffer_resize (buf, offset, size);
5240
5241   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
5242   GST_BUFFER_PTS (buf) = pts;
5243   GST_BUFFER_DURATION (buf) = duration;
5244
5245   return buf;
5246
5247   /* dropped buffer */
5248 wrong_type:
5249   {
5250     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
5251     return buf;
5252   }
5253 bad_frame_size:
5254   {
5255     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
5256     return buf;
5257   }
5258 no_pts:
5259   {
5260     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
5261     return buf;
5262   }
5263 clipped:
5264   {
5265     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
5266     gst_buffer_unref (buf);
5267     return NULL;
5268   }
5269 }
5270
5271 /* the input buffer metadata must be writable,
5272  * but time/duration etc not yet set and need not be preserved */
5273 static GstBuffer *
5274 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
5275     GstBuffer * buf)
5276 {
5277   GstMapInfo map;
5278   guint nsize = 0;
5279   gchar *str;
5280
5281   /* not many cases for now */
5282   if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
5283     /* send a one time dvd clut event */
5284     if (stream->pending_event && stream->pad)
5285       gst_pad_push_event (stream->pad, stream->pending_event);
5286     stream->pending_event = NULL;
5287   }
5288
5289   if (G_UNLIKELY (stream->subtype != FOURCC_text
5290           && stream->subtype != FOURCC_sbtl &&
5291           stream->subtype != FOURCC_subp)) {
5292     return buf;
5293   }
5294
5295   gst_buffer_map (buf, &map, GST_MAP_READ);
5296
5297   /* empty buffer is sent to terminate previous subtitle */
5298   if (map.size <= 2) {
5299     gst_buffer_unmap (buf, &map);
5300     gst_buffer_unref (buf);
5301     return NULL;
5302   }
5303   if (stream->subtype == FOURCC_subp) {
5304     /* That's all the processing needed for subpictures */
5305     gst_buffer_unmap (buf, &map);
5306     return buf;
5307   }
5308
5309   nsize = GST_READ_UINT16_BE (map.data);
5310   nsize = MIN (nsize, map.size - 2);
5311
5312   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
5313       nsize, map.size);
5314
5315   /* takes care of UTF-8 validation or UTF-16 recognition,
5316    * no other encoding expected */
5317   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
5318   gst_buffer_unmap (buf, &map);
5319   if (str) {
5320     gst_buffer_unref (buf);
5321     buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
5322   } else {
5323     /* this should not really happen unless the subtitle is corrupted */
5324     gst_buffer_unref (buf);
5325     buf = NULL;
5326   }
5327
5328   /* FIXME ? convert optional subsequent style info to markup */
5329
5330   return buf;
5331 }
5332
5333 /* Sets a buffer's attributes properly and pushes it downstream.
5334  * Also checks for additional actions and custom processing that may
5335  * need to be done first.
5336  */
5337 static GstFlowReturn
5338 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
5339     QtDemuxStream * stream, GstBuffer * buf,
5340     GstClockTime dts, GstClockTime pts, GstClockTime duration,
5341     gboolean keyframe, GstClockTime position, guint64 byte_position)
5342 {
5343   GstFlowReturn ret = GST_FLOW_OK;
5344
5345   /* offset the timestamps according to the edit list */
5346
5347   if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
5348     gchar *url;
5349     GstMapInfo map;
5350
5351     gst_buffer_map (buf, &map, GST_MAP_READ);
5352     url = g_strndup ((gchar *) map.data, map.size);
5353     gst_buffer_unmap (buf, &map);
5354     if (url != NULL && strlen (url) != 0) {
5355       /* we have RTSP redirect now */
5356       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5357           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
5358               gst_structure_new ("redirect",
5359                   "new-location", G_TYPE_STRING, url, NULL)));
5360       qtdemux->posted_redirect = TRUE;
5361     } else {
5362       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
5363           "posting");
5364     }
5365     g_free (url);
5366   }
5367
5368   /* position reporting */
5369   if (qtdemux->segment.rate >= 0) {
5370     qtdemux->segment.position = position;
5371     gst_qtdemux_sync_streams (qtdemux);
5372   }
5373
5374   if (G_UNLIKELY (!stream->pad)) {
5375     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
5376     gst_buffer_unref (buf);
5377     goto exit;
5378   }
5379
5380   /* send out pending buffers */
5381   while (stream->buffers) {
5382     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
5383
5384     if (G_UNLIKELY (stream->discont)) {
5385       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5386       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
5387       stream->discont = FALSE;
5388     } else {
5389       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5390     }
5391
5392     gst_pad_push (stream->pad, buffer);
5393
5394     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
5395   }
5396
5397   /* we're going to modify the metadata */
5398   buf = gst_buffer_make_writable (buf);
5399
5400   if (G_UNLIKELY (stream->need_process))
5401     buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
5402
5403   if (!buf) {
5404     goto exit;
5405   }
5406
5407   GST_BUFFER_DTS (buf) = dts;
5408   GST_BUFFER_PTS (buf) = pts;
5409   GST_BUFFER_DURATION (buf) = duration;
5410   GST_BUFFER_OFFSET (buf) = -1;
5411   GST_BUFFER_OFFSET_END (buf) = -1;
5412
5413   if (G_UNLIKELY (stream->rgb8_palette))
5414     gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
5415
5416   if (G_UNLIKELY (stream->padding)) {
5417     gst_buffer_resize (buf, stream->padding, -1);
5418   }
5419 #if 0
5420   if (G_UNLIKELY (qtdemux->element_index)) {
5421     GstClockTime stream_time;
5422
5423     stream_time =
5424         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
5425         timestamp);
5426     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
5427       GST_LOG_OBJECT (qtdemux,
5428           "adding association %" GST_TIME_FORMAT "-> %"
5429           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
5430       gst_index_add_association (qtdemux->element_index,
5431           qtdemux->index_id,
5432           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5433           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
5434           GST_FORMAT_BYTES, byte_position, NULL);
5435     }
5436   }
5437 #endif
5438
5439   if (stream->need_clip)
5440     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
5441
5442   if (G_UNLIKELY (buf == NULL))
5443     goto exit;
5444
5445   if (G_UNLIKELY (stream->discont)) {
5446     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
5447     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5448     stream->discont = FALSE;
5449   } else {
5450     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5451   }
5452
5453   if (!keyframe) {
5454     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5455     stream->on_keyframe = FALSE;
5456   } else {
5457     stream->on_keyframe = TRUE;
5458   }
5459
5460
5461   GST_LOG_OBJECT (qtdemux,
5462       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
5463       ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
5464       GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
5465       GST_PAD_NAME (stream->pad));
5466
5467   if (stream->protected && stream->protection_scheme_type == FOURCC_cenc) {
5468     GstStructure *crypto_info;
5469     QtDemuxCencSampleSetInfo *info =
5470         (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
5471     gint index;
5472     GstEvent *event;
5473
5474     while ((event = g_queue_pop_head (&stream->protection_scheme_event_queue))) {
5475       gst_pad_push_event (stream->pad, event);
5476     }
5477
5478     index = stream->sample_index - (stream->n_samples - info->crypto_info->len);
5479     if (G_LIKELY (index >= 0 && index < info->crypto_info->len)) {
5480       /* steal structure from array */
5481       crypto_info = g_ptr_array_index (info->crypto_info, index);
5482       g_ptr_array_index (info->crypto_info, index) = NULL;
5483       GST_LOG_OBJECT (qtdemux, "attaching cenc metadata [%u]", index);
5484       if (!crypto_info || !gst_buffer_add_protection_meta (buf, crypto_info))
5485         GST_ERROR_OBJECT (qtdemux, "failed to attach cenc metadata to buffer");
5486     }
5487   }
5488
5489   ret = gst_pad_push (stream->pad, buf);
5490
5491   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
5492     /* mark position in stream, we'll need this to know when to send GAP event */
5493     stream->segment.position = pts + duration;
5494   }
5495
5496 exit:
5497   return ret;
5498 }
5499
5500 static const QtDemuxRandomAccessEntry *
5501 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
5502     GstClockTime pos, gboolean after)
5503 {
5504   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
5505   guint n_entries = stream->n_ra_entries;
5506   guint i;
5507
5508   /* we assume the table is sorted */
5509   for (i = 0; i < n_entries; ++i) {
5510     if (entries[i].ts > pos)
5511       break;
5512   }
5513
5514   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
5515    * probably okay to assume that the index lists the very first fragment */
5516   if (i == 0)
5517     return &entries[0];
5518
5519   if (after)
5520     return &entries[i];
5521   else
5522     return &entries[i - 1];
5523 }
5524
5525 static gboolean
5526 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
5527 {
5528   const QtDemuxRandomAccessEntry *best_entry = NULL;
5529   guint i;
5530
5531   GST_OBJECT_LOCK (qtdemux);
5532
5533   g_assert (qtdemux->n_streams > 0);
5534
5535   for (i = 0; i < qtdemux->n_streams; i++) {
5536     const QtDemuxRandomAccessEntry *entry;
5537     QtDemuxStream *stream;
5538     gboolean is_audio_or_video;
5539
5540     stream = qtdemux->streams[i];
5541
5542     g_free (stream->samples);
5543     stream->samples = NULL;
5544     stream->n_samples = 0;
5545     stream->stbl_index = -1;    /* no samples have yet been parsed */
5546     stream->sample_index = -1;
5547
5548     if (stream->ra_entries == NULL)
5549       continue;
5550
5551     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
5552       is_audio_or_video = TRUE;
5553     else
5554       is_audio_or_video = FALSE;
5555
5556     entry =
5557         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
5558         stream->time_position, !is_audio_or_video);
5559
5560     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
5561         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
5562
5563     stream->pending_seek = entry;
5564
5565     /* decide position to jump to just based on audio/video tracks, not subs */
5566     if (!is_audio_or_video)
5567       continue;
5568
5569     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
5570       best_entry = entry;
5571   }
5572
5573   if (best_entry == NULL) {
5574     GST_OBJECT_UNLOCK (qtdemux);
5575     return FALSE;
5576   }
5577
5578   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
5579       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
5580       GST_TIME_ARGS (qtdemux->streams[0]->time_position),
5581       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
5582
5583   qtdemux->moof_offset = best_entry->moof_offset;
5584
5585   qtdemux_add_fragmented_samples (qtdemux);
5586
5587   GST_OBJECT_UNLOCK (qtdemux);
5588   return TRUE;
5589 }
5590
5591 static GstFlowReturn
5592 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
5593 {
5594   GstFlowReturn ret = GST_FLOW_OK;
5595   GstBuffer *buf = NULL;
5596   QtDemuxStream *stream;
5597   GstClockTime min_time;
5598   guint64 offset = 0;
5599   GstClockTime dts = GST_CLOCK_TIME_NONE;
5600   GstClockTime pts = GST_CLOCK_TIME_NONE;
5601   GstClockTime duration = 0;
5602   gboolean keyframe = FALSE;
5603   guint sample_size = 0;
5604   gboolean empty = 0;
5605   guint size;
5606   gint index;
5607   gint i;
5608
5609   gst_qtdemux_push_pending_newsegment (qtdemux);
5610
5611   if (qtdemux->fragmented_seek_pending) {
5612     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
5613     gst_qtdemux_do_fragmented_seek (qtdemux);
5614     GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
5615     qtdemux->fragmented_seek_pending = FALSE;
5616   }
5617
5618   /* Figure out the next stream sample to output, min_time is expressed in
5619    * global time and runs over the edit list segments. */
5620   min_time = G_MAXUINT64;
5621   index = -1;
5622   for (i = 0; i < qtdemux->n_streams; i++) {
5623     GstClockTime position;
5624
5625     stream = qtdemux->streams[i];
5626     position = stream->time_position;
5627
5628     /* position of -1 is EOS */
5629     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
5630       min_time = position;
5631       index = i;
5632     }
5633   }
5634   /* all are EOS */
5635   if (G_UNLIKELY (index == -1)) {
5636     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
5637     goto eos;
5638   }
5639
5640   /* check for segment end */
5641   if (G_UNLIKELY (qtdemux->segment.stop != -1
5642           && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
5643               || (qtdemux->segment.rate < 0
5644                   && qtdemux->segment.start > min_time))
5645           && qtdemux->streams[index]->on_keyframe)) {
5646     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
5647     qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
5648     goto eos_stream;
5649   }
5650
5651   /* gap events for subtitle streams */
5652   for (i = 0; i < qtdemux->n_streams; i++) {
5653     stream = qtdemux->streams[i];
5654     if (stream->pad && (stream->subtype == FOURCC_subp
5655             || stream->subtype == FOURCC_text
5656             || stream->subtype == FOURCC_sbtl)) {
5657       /* send one second gap events until the stream catches up */
5658       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
5659       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
5660           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
5661           stream->segment.position + GST_SECOND < min_time) {
5662         GstEvent *gap =
5663             gst_event_new_gap (stream->segment.position, GST_SECOND);
5664         gst_pad_push_event (stream->pad, gap);
5665         stream->segment.position += GST_SECOND;
5666       }
5667     }
5668   }
5669
5670   stream = qtdemux->streams[index];
5671   if (stream->new_caps) {
5672     gst_qtdemux_configure_stream (qtdemux, stream);
5673     qtdemux_do_allocation (qtdemux, stream);
5674   }
5675
5676   /* fetch info for the current sample of this stream */
5677   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
5678               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
5679     goto eos_stream;
5680
5681   /* If we're doing a keyframe-only trickmode, only push keyframes on video streams */
5682   if (G_UNLIKELY (qtdemux->
5683           segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)) {
5684     if (stream->subtype == FOURCC_vide && !keyframe) {
5685       GST_LOG_OBJECT (qtdemux, "Skipping non-keyframe on stream %d", index);
5686       goto next;
5687     }
5688   }
5689
5690   GST_DEBUG_OBJECT (qtdemux,
5691       "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
5692       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
5693       ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
5694       GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
5695
5696   if (G_UNLIKELY (empty)) {
5697     /* empty segment, push a gap and move to the next one */
5698     gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
5699     stream->segment.position = pts + duration;
5700     goto next;
5701   }
5702
5703   /* hmm, empty sample, skip and move to next sample */
5704   if (G_UNLIKELY (sample_size <= 0))
5705     goto next;
5706
5707   /* last pushed sample was out of boundary, goto next sample */
5708   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
5709     goto next;
5710
5711   if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
5712     size = sample_size;
5713   } else {
5714     GST_DEBUG_OBJECT (qtdemux,
5715         "size %d larger than stream max_buffer_size %d, trimming",
5716         sample_size, stream->max_buffer_size);
5717     size =
5718         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
5719   }
5720
5721   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
5722       offset);
5723
5724   if (stream->use_allocator) {
5725     /* if we have a per-stream allocator, use it */
5726     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
5727   }
5728
5729   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
5730       size, &buf);
5731   if (G_UNLIKELY (ret != GST_FLOW_OK))
5732     goto beach;
5733
5734   if (size != sample_size) {
5735     pts += gst_util_uint64_scale_int (GST_SECOND,
5736         stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5737     dts += gst_util_uint64_scale_int (GST_SECOND,
5738         stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
5739     duration = gst_util_uint64_scale_int (GST_SECOND,
5740         size / stream->bytes_per_frame, stream->timescale);
5741   }
5742
5743   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
5744       dts, pts, duration, keyframe, min_time, offset);
5745
5746   if (size != sample_size) {
5747     QtDemuxSample *sample = &stream->samples[stream->sample_index];
5748     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
5749
5750     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
5751         sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
5752     if (time_position >= segment->media_start) {
5753       /* inside the segment, update time_position, looks very familiar to
5754        * GStreamer segments, doesn't it? */
5755       stream->time_position = (time_position - segment->media_start) +
5756           segment->time;
5757     } else {
5758       /* not yet in segment, time does not yet increment. This means
5759        * that we are still prerolling keyframes to the decoder so it can
5760        * decode the first sample of the segment. */
5761       stream->time_position = segment->time;
5762     }
5763   }
5764
5765   /* combine flows */
5766   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
5767   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
5768    * we have no more data for the pad to push */
5769   if (ret == GST_FLOW_EOS)
5770     ret = GST_FLOW_OK;
5771
5772   stream->offset_in_sample += size;
5773   if (stream->offset_in_sample >= sample_size) {
5774     gst_qtdemux_advance_sample (qtdemux, stream);
5775   }
5776   goto beach;
5777
5778 next:
5779   gst_qtdemux_advance_sample (qtdemux, stream);
5780
5781 beach:
5782   return ret;
5783
5784   /* special cases */
5785 eos:
5786   {
5787     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
5788     ret = GST_FLOW_EOS;
5789     goto beach;
5790   }
5791 eos_stream:
5792   {
5793     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
5794     /* EOS will be raised if all are EOS */
5795     ret = GST_FLOW_OK;
5796     goto beach;
5797   }
5798 }
5799
5800 static void
5801 gst_qtdemux_loop (GstPad * pad)
5802 {
5803   GstQTDemux *qtdemux;
5804   guint64 cur_offset;
5805   GstFlowReturn ret;
5806
5807   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
5808
5809   cur_offset = qtdemux->offset;
5810   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
5811       cur_offset, qtdemux->state);
5812
5813   switch (qtdemux->state) {
5814     case QTDEMUX_STATE_INITIAL:
5815     case QTDEMUX_STATE_HEADER:
5816       ret = gst_qtdemux_loop_state_header (qtdemux);
5817       break;
5818     case QTDEMUX_STATE_MOVIE:
5819       ret = gst_qtdemux_loop_state_movie (qtdemux);
5820       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
5821         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
5822       }
5823       break;
5824     default:
5825       /* ouch */
5826       goto invalid_state;
5827   }
5828
5829   /* if something went wrong, pause */
5830   if (ret != GST_FLOW_OK)
5831     goto pause;
5832
5833 done:
5834   gst_object_unref (qtdemux);
5835   return;
5836
5837   /* ERRORS */
5838 invalid_state:
5839   {
5840     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5841         (NULL), ("streaming stopped, invalid state"));
5842     gst_pad_pause_task (pad);
5843     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5844     goto done;
5845   }
5846 pause:
5847   {
5848     const gchar *reason = gst_flow_get_name (ret);
5849
5850     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
5851
5852     gst_pad_pause_task (pad);
5853
5854     /* fatal errors need special actions */
5855     /* check EOS */
5856     if (ret == GST_FLOW_EOS) {
5857       if (qtdemux->n_streams == 0) {
5858         /* we have no streams, post an error */
5859         gst_qtdemux_post_no_playable_stream_error (qtdemux);
5860       }
5861       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5862         gint64 stop;
5863
5864         if ((stop = qtdemux->segment.stop) == -1)
5865           stop = qtdemux->segment.duration;
5866
5867         if (qtdemux->segment.rate >= 0) {
5868           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
5869           gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5870               gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5871                   GST_FORMAT_TIME, stop));
5872           gst_qtdemux_push_event (qtdemux,
5873               gst_event_new_segment_done (GST_FORMAT_TIME, stop));
5874         } else {
5875           /*  For Reverse Playback */
5876           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
5877           gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
5878               gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
5879                   GST_FORMAT_TIME, qtdemux->segment.start));
5880           gst_qtdemux_push_event (qtdemux,
5881               gst_event_new_segment_done (GST_FORMAT_TIME,
5882                   qtdemux->segment.start));
5883         }
5884       } else {
5885         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
5886         gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5887       }
5888     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
5889       GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
5890           (NULL), ("streaming stopped, reason %s", reason));
5891       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
5892     }
5893     goto done;
5894   }
5895 }
5896
5897 /*
5898  * has_next_entry
5899  *
5900  * Returns if there are samples to be played.
5901  */
5902 static gboolean
5903 has_next_entry (GstQTDemux * demux)
5904 {
5905   QtDemuxStream *stream;
5906   int i;
5907
5908   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
5909
5910   for (i = 0; i < demux->n_streams; i++) {
5911     stream = demux->streams[i];
5912
5913     if (stream->sample_index == -1) {
5914       stream->sample_index = 0;
5915       stream->offset_in_sample = 0;
5916     }
5917
5918     if (stream->sample_index >= stream->n_samples) {
5919       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5920       continue;
5921     }
5922     GST_DEBUG_OBJECT (demux, "Found a sample");
5923     return TRUE;
5924   }
5925
5926   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
5927   return FALSE;
5928 }
5929
5930 /*
5931  * next_entry_size
5932  *
5933  * Returns the size of the first entry at the current offset.
5934  * If -1, there are none (which means EOS or empty file).
5935  */
5936 static guint64
5937 next_entry_size (GstQTDemux * demux)
5938 {
5939   QtDemuxStream *stream;
5940   int i;
5941   int smallidx = -1;
5942   guint64 smalloffs = (guint64) - 1;
5943   QtDemuxSample *sample;
5944
5945   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
5946       demux->offset);
5947
5948   for (i = 0; i < demux->n_streams; i++) {
5949     stream = demux->streams[i];
5950
5951     if (stream->sample_index == -1) {
5952       stream->sample_index = 0;
5953       stream->offset_in_sample = 0;
5954     }
5955
5956     if (stream->sample_index >= stream->n_samples) {
5957       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
5958       continue;
5959     }
5960
5961     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
5962       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
5963           stream->sample_index);
5964       return -1;
5965     }
5966
5967     sample = &stream->samples[stream->sample_index];
5968
5969     GST_LOG_OBJECT (demux,
5970         "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5971         " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
5972         sample->offset, sample->size);
5973
5974     if (((smalloffs == -1)
5975             || (sample->offset < smalloffs)) && (sample->size)) {
5976       smallidx = i;
5977       smalloffs = sample->offset;
5978     }
5979   }
5980
5981   GST_LOG_OBJECT (demux,
5982       "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
5983       G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
5984
5985   if (smallidx == -1)
5986     return -1;
5987
5988   stream = demux->streams[smallidx];
5989   sample = &stream->samples[stream->sample_index];
5990
5991   if (sample->offset >= demux->offset) {
5992     demux->todrop = sample->offset - demux->offset;
5993     return sample->size + demux->todrop;
5994   }
5995
5996   GST_DEBUG_OBJECT (demux,
5997       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
5998   return -1;
5999 }
6000
6001 static void
6002 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
6003 {
6004   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
6005
6006   gst_element_post_message (GST_ELEMENT_CAST (demux),
6007       gst_message_new_element (GST_OBJECT_CAST (demux),
6008           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
6009 }
6010
6011 static gboolean
6012 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
6013 {
6014   GstEvent *event;
6015   gboolean res = 0;
6016
6017   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
6018
6019   event =
6020       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
6021       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
6022       GST_SEEK_TYPE_NONE, -1);
6023
6024   res = gst_pad_push_event (demux->sinkpad, event);
6025
6026   return res;
6027 }
6028
6029 /* check for seekable upstream, above and beyond a mere query */
6030 static void
6031 gst_qtdemux_check_seekability (GstQTDemux * demux)
6032 {
6033   GstQuery *query;
6034   gboolean seekable = FALSE;
6035   gint64 start = -1, stop = -1;
6036
6037   if (demux->upstream_size)
6038     return;
6039
6040   query = gst_query_new_seeking (GST_FORMAT_BYTES);
6041   if (!gst_pad_peer_query (demux->sinkpad, query)) {
6042     GST_DEBUG_OBJECT (demux, "seeking query failed");
6043     goto done;
6044   }
6045
6046   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
6047
6048   /* try harder to query upstream size if we didn't get it the first time */
6049   if (seekable && stop == -1) {
6050     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
6051     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
6052   }
6053
6054   /* if upstream doesn't know the size, it's likely that it's not seekable in
6055    * practice even if it technically may be seekable */
6056   if (seekable && (start != 0 || stop <= start)) {
6057     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
6058     seekable = FALSE;
6059   }
6060
6061 done:
6062   gst_query_unref (query);
6063
6064   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
6065       G_GUINT64_FORMAT ")", seekable, start, stop);
6066   demux->upstream_seekable = seekable;
6067   demux->upstream_size = seekable ? stop : -1;
6068 }
6069
6070 static void
6071 gst_qtdemux_drop_data (GstQTDemux * demux, gint bytes)
6072 {
6073   g_return_if_fail (bytes <= demux->todrop);
6074
6075   GST_LOG_OBJECT (demux, "Dropping %d bytes", bytes);
6076   gst_adapter_flush (demux->adapter, bytes);
6077   demux->neededbytes -= bytes;
6078   demux->offset += bytes;
6079   demux->todrop -= bytes;
6080 }
6081
6082 static GstFlowReturn
6083 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
6084 {
6085   GstQTDemux *demux;
6086
6087   demux = GST_QTDEMUX (parent);
6088
6089   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
6090     gint i;
6091
6092     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
6093
6094     for (i = 0; i < demux->n_streams; i++) {
6095       demux->streams[i]->discont = TRUE;
6096     }
6097
6098     /* Reverse fragmented playback, need to flush all we have before
6099      * consuming a new fragment.
6100      * The samples array have the timestamps calculated by accumulating the
6101      * durations but this won't work for reverse playback of fragments as
6102      * the timestamps of a subsequent fragment should be smaller than the
6103      * previously received one. */
6104     if (demux->fragmented && demux->segment.rate < 0) {
6105       gst_qtdemux_process_adapter (demux, TRUE);
6106       for (i = 0; i < demux->n_streams; i++)
6107         gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
6108     }
6109   }
6110
6111   gst_adapter_push (demux->adapter, inbuf);
6112
6113   GST_DEBUG_OBJECT (demux,
6114       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
6115       demux->neededbytes, gst_adapter_available (demux->adapter));
6116
6117   return gst_qtdemux_process_adapter (demux, FALSE);
6118 }
6119
6120 static GstFlowReturn
6121 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
6122 {
6123   GstFlowReturn ret = GST_FLOW_OK;
6124
6125   /* we never really mean to buffer that much */
6126   if (demux->neededbytes == -1) {
6127     goto eos;
6128   }
6129
6130   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
6131       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
6132
6133     GST_DEBUG_OBJECT (demux,
6134         "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
6135         demux->state, demux->neededbytes, demux->offset);
6136
6137     switch (demux->state) {
6138       case QTDEMUX_STATE_INITIAL:{
6139         const guint8 *data;
6140         guint32 fourcc;
6141         guint64 size;
6142
6143         gst_qtdemux_check_seekability (demux);
6144
6145         data = gst_adapter_map (demux->adapter, demux->neededbytes);
6146
6147         /* get fourcc/length, set neededbytes */
6148         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
6149             &size, &fourcc);
6150         gst_adapter_unmap (demux->adapter);
6151         data = NULL;
6152         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
6153             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
6154         if (size == 0) {
6155           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6156               (_("This file is invalid and cannot be played.")),
6157               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
6158                   GST_FOURCC_ARGS (fourcc)));
6159           ret = GST_FLOW_ERROR;
6160           break;
6161         }
6162         if (fourcc == FOURCC_mdat) {
6163           gint next_entry = next_entry_size (demux);
6164           if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
6165             /* we have the headers, start playback */
6166             demux->state = QTDEMUX_STATE_MOVIE;
6167             demux->neededbytes = next_entry;
6168             demux->mdatleft = size;
6169           } else {
6170             /* no headers yet, try to get them */
6171             guint bs;
6172             gboolean res;
6173             guint64 old, target;
6174
6175           buffer_data:
6176             old = demux->offset;
6177             target = old + size;
6178
6179             /* try to jump over the atom with a seek */
6180             /* only bother if it seems worth doing so,
6181              * and avoids possible upstream/server problems */
6182             if (demux->upstream_seekable &&
6183                 demux->upstream_size > 4 * (1 << 20)) {
6184               res = qtdemux_seek_offset (demux, target);
6185             } else {
6186               GST_DEBUG_OBJECT (demux, "skipping seek");
6187               res = FALSE;
6188             }
6189
6190             if (res) {
6191               GST_DEBUG_OBJECT (demux, "seek success");
6192               /* remember the offset fo the first mdat so we can seek back to it
6193                * after we have the headers */
6194               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
6195                 demux->first_mdat = old;
6196                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
6197                     demux->first_mdat);
6198               }
6199               /* seek worked, continue reading */
6200               demux->offset = target;
6201               demux->neededbytes = 16;
6202               demux->state = QTDEMUX_STATE_INITIAL;
6203             } else {
6204               /* seek failed, need to buffer */
6205               demux->offset = old;
6206               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
6207               /* there may be multiple mdat (or alike) buffers */
6208               /* sanity check */
6209               if (demux->mdatbuffer)
6210                 bs = gst_buffer_get_size (demux->mdatbuffer);
6211               else
6212                 bs = 0;
6213               if (size + bs > 10 * (1 << 20))
6214                 goto no_moov;
6215               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
6216               demux->neededbytes = size;
6217               if (!demux->mdatbuffer)
6218                 demux->mdatoffset = demux->offset;
6219             }
6220           }
6221         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
6222           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6223               (_("This file is invalid and cannot be played.")),
6224               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
6225                   GST_FOURCC_ARGS (fourcc), size));
6226           ret = GST_FLOW_ERROR;
6227           break;
6228         } else {
6229           /* this means we already started buffering and still no moov header,
6230            * let's continue buffering everything till we get moov */
6231           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
6232                   || fourcc == FOURCC_moof))
6233             goto buffer_data;
6234           demux->neededbytes = size;
6235           demux->state = QTDEMUX_STATE_HEADER;
6236         }
6237         break;
6238       }
6239       case QTDEMUX_STATE_HEADER:{
6240         const guint8 *data;
6241         guint32 fourcc;
6242
6243         GST_DEBUG_OBJECT (demux, "In header");
6244
6245         data = gst_adapter_map (demux->adapter, demux->neededbytes);
6246
6247         /* parse the header */
6248         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
6249             &fourcc);
6250         if (fourcc == FOURCC_moov) {
6251           /* in usual fragmented setup we could try to scan for more
6252            * and end up at the the moov (after mdat) again */
6253           if (demux->got_moov && demux->n_streams > 0 &&
6254               (!demux->fragmented
6255                   || demux->last_moov_offset == demux->offset)) {
6256             GST_DEBUG_OBJECT (demux,
6257                 "Skipping moov atom as we have (this) one already");
6258           } else {
6259             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
6260
6261             if (demux->got_moov && demux->fragmented) {
6262               GST_DEBUG_OBJECT (demux,
6263                   "Got a second moov, clean up data from old one");
6264               if (demux->moov_node)
6265                 g_node_destroy (demux->moov_node);
6266               demux->moov_node = NULL;
6267               demux->moov_node_compressed = NULL;
6268             } else {
6269               /* prepare newsegment to send when streaming actually starts */
6270               if (!demux->pending_newsegment)
6271                 demux->pending_newsegment =
6272                     gst_event_new_segment (&demux->segment);
6273             }
6274
6275             demux->last_moov_offset = demux->offset;
6276
6277             qtdemux_parse_moov (demux, data, demux->neededbytes);
6278             qtdemux_node_dump (demux, demux->moov_node);
6279             qtdemux_parse_tree (demux);
6280             qtdemux_prepare_streams (demux);
6281             if (!demux->got_moov)
6282               qtdemux_expose_streams (demux);
6283             else {
6284               gint n;
6285
6286               for (n = 0; n < demux->n_streams; n++) {
6287                 QtDemuxStream *stream = demux->streams[n];
6288
6289                 gst_qtdemux_configure_stream (demux, stream);
6290               }
6291             }
6292
6293             demux->got_moov = TRUE;
6294
6295             g_node_destroy (demux->moov_node);
6296             demux->moov_node = NULL;
6297             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
6298           }
6299         } else if (fourcc == FOURCC_moof) {
6300           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
6301             guint64 dist = 0;
6302             GstClockTime prev_pts;
6303             guint64 prev_offset;
6304
6305             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
6306
6307             /*
6308              * The timestamp of the moof buffer is relevant as some scenarios
6309              * won't have the initial timestamp in the atoms. Whenever a new
6310              * buffer has started, we get that buffer's PTS and use it as a base
6311              * timestamp for the trun entries.
6312              *
6313              * To keep track of the current buffer timestamp and starting point
6314              * we use gst_adapter_prev_pts that gives us the PTS and the distance
6315              * from the beggining of the buffer, with the distance and demux->offset
6316              * we know if it is still the same buffer or not.
6317              */
6318             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
6319             prev_offset = demux->offset - dist;
6320             if (demux->fragment_start_offset == -1
6321                 || prev_offset > demux->fragment_start_offset) {
6322               demux->fragment_start_offset = prev_offset;
6323               demux->fragment_start = prev_pts;
6324               GST_DEBUG_OBJECT (demux,
6325                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
6326                   GST_TIME_FORMAT, demux->fragment_start_offset,
6327                   GST_TIME_ARGS (demux->fragment_start));
6328             }
6329
6330             demux->moof_offset = demux->offset;
6331             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
6332                     demux->offset, NULL)) {
6333               gst_adapter_unmap (demux->adapter);
6334               ret = GST_FLOW_ERROR;
6335               goto done;
6336             }
6337             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
6338             if (demux->mss_mode && !demux->exposed) {
6339               if (!demux->pending_newsegment) {
6340                 GstSegment segment;
6341                 gst_segment_init (&segment, GST_FORMAT_TIME);
6342                 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
6343                 demux->pending_newsegment = gst_event_new_segment (&segment);
6344               }
6345               qtdemux_expose_streams (demux);
6346             }
6347           } else {
6348             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
6349           }
6350         } else if (fourcc == FOURCC_ftyp) {
6351           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
6352           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
6353         } else if (fourcc == FOURCC_uuid) {
6354           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
6355           qtdemux_parse_uuid (demux, data, demux->neededbytes);
6356         } else if (fourcc == FOURCC_sidx) {
6357           GST_DEBUG_OBJECT (demux, "Parsing [sidx]");
6358           qtdemux_parse_sidx (demux, data, demux->neededbytes);
6359         } else {
6360           GST_WARNING_OBJECT (demux,
6361               "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
6362               GST_FOURCC_ARGS (fourcc));
6363           /* Let's jump that one and go back to initial state */
6364         }
6365         gst_adapter_unmap (demux->adapter);
6366         data = NULL;
6367
6368         if (demux->mdatbuffer && demux->n_streams) {
6369           gsize remaining_data_size = 0;
6370
6371           /* the mdat was before the header */
6372           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
6373               demux->n_streams, demux->mdatbuffer);
6374           /* restore our adapter/offset view of things with upstream;
6375            * put preceding buffered data ahead of current moov data.
6376            * This should also handle evil mdat, moov, mdat cases and alike */
6377           gst_adapter_flush (demux->adapter, demux->neededbytes);
6378
6379           /* Store any remaining data after the mdat for later usage */
6380           remaining_data_size = gst_adapter_available (demux->adapter);
6381           if (remaining_data_size > 0) {
6382             g_assert (demux->restoredata_buffer == NULL);
6383             demux->restoredata_buffer =
6384                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
6385             demux->restoredata_offset = demux->offset + demux->neededbytes;
6386             GST_DEBUG_OBJECT (demux,
6387                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
6388                 G_GUINT64_FORMAT, remaining_data_size,
6389                 demux->restoredata_offset);
6390           }
6391
6392           gst_adapter_push (demux->adapter, demux->mdatbuffer);
6393           demux->mdatbuffer = NULL;
6394           demux->offset = demux->mdatoffset;
6395           demux->neededbytes = next_entry_size (demux);
6396           demux->state = QTDEMUX_STATE_MOVIE;
6397           demux->mdatleft = gst_adapter_available (demux->adapter);
6398         } else {
6399           GST_DEBUG_OBJECT (demux, "Carrying on normally");
6400           gst_adapter_flush (demux->adapter, demux->neededbytes);
6401
6402           /* only go back to the mdat if there are samples to play */
6403           if (demux->got_moov && demux->first_mdat != -1
6404               && has_next_entry (demux)) {
6405             gboolean res;
6406
6407             /* we need to seek back */
6408             res = qtdemux_seek_offset (demux, demux->first_mdat);
6409             if (res) {
6410               demux->offset = demux->first_mdat;
6411             } else {
6412               GST_DEBUG_OBJECT (demux, "Seek back failed");
6413             }
6414           } else {
6415             demux->offset += demux->neededbytes;
6416           }
6417           demux->neededbytes = 16;
6418           demux->state = QTDEMUX_STATE_INITIAL;
6419         }
6420
6421         break;
6422       }
6423       case QTDEMUX_STATE_BUFFER_MDAT:{
6424         GstBuffer *buf;
6425         guint8 fourcc[4];
6426
6427         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
6428             demux->offset);
6429         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6430         gst_buffer_extract (buf, 0, fourcc, 4);
6431         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
6432             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
6433         if (demux->mdatbuffer)
6434           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
6435         else
6436           demux->mdatbuffer = buf;
6437         demux->offset += demux->neededbytes;
6438         demux->neededbytes = 16;
6439         demux->state = QTDEMUX_STATE_INITIAL;
6440         gst_qtdemux_post_progress (demux, 1, 1);
6441
6442         break;
6443       }
6444       case QTDEMUX_STATE_MOVIE:{
6445         QtDemuxStream *stream = NULL;
6446         QtDemuxSample *sample;
6447         int i = -1;
6448         GstClockTime dts, pts, duration;
6449         gboolean keyframe;
6450
6451         GST_DEBUG_OBJECT (demux,
6452             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
6453
6454         if (demux->fragmented) {
6455           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
6456               demux->mdatleft);
6457           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
6458             /* if needed data starts within this atom,
6459              * then it should not exceed this atom */
6460             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
6461               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
6462                   (_("This file is invalid and cannot be played.")),
6463                   ("sample data crosses atom boundary"));
6464               ret = GST_FLOW_ERROR;
6465               break;
6466             }
6467             demux->mdatleft -= demux->neededbytes;
6468           } else {
6469             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
6470             /* so we are dropping more than left in this atom */
6471             gst_qtdemux_drop_data (demux, demux->mdatleft);
6472             demux->mdatleft = 0;
6473
6474             /* need to resume atom parsing so we do not miss any other pieces */
6475             demux->state = QTDEMUX_STATE_INITIAL;
6476             demux->neededbytes = 16;
6477
6478             /* check if there was any stored post mdat data from previous buffers */
6479             if (demux->restoredata_buffer) {
6480               g_assert (gst_adapter_available (demux->adapter) == 0);
6481
6482               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
6483               demux->restoredata_buffer = NULL;
6484               demux->offset = demux->restoredata_offset;
6485             }
6486
6487             break;
6488           }
6489         }
6490
6491         if (demux->todrop) {
6492           gst_qtdemux_drop_data (demux, demux->todrop);
6493         }
6494
6495         /* first buffer? */
6496         /* initial newsegment sent here after having added pads,
6497          * possible others in sink_event */
6498         if (G_UNLIKELY (demux->pending_newsegment)) {
6499           gst_qtdemux_push_pending_newsegment (demux);
6500           /* clear to send tags on all streams */
6501           for (i = 0; i < demux->n_streams; i++) {
6502             stream = demux->streams[i];
6503             gst_qtdemux_push_tags (demux, stream);
6504             if (stream->sparse) {
6505               GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
6506               gst_pad_push_event (stream->pad,
6507                   gst_event_new_gap (stream->segment.position,
6508                       GST_CLOCK_TIME_NONE));
6509             }
6510           }
6511         }
6512
6513         /* Figure out which stream this packet belongs to */
6514         for (i = 0; i < demux->n_streams; i++) {
6515           stream = demux->streams[i];
6516           if (stream->sample_index >= stream->n_samples)
6517             continue;
6518           GST_LOG_OBJECT (demux,
6519               "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
6520               " / size:%d)", i, stream->sample_index,
6521               stream->samples[stream->sample_index].offset,
6522               stream->samples[stream->sample_index].size);
6523
6524           if (stream->samples[stream->sample_index].offset == demux->offset)
6525             break;
6526         }
6527
6528         if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
6529           goto unknown_stream;
6530
6531         if (stream->new_caps) {
6532           gst_qtdemux_configure_stream (demux, stream);
6533         }
6534
6535         /* Put data in a buffer, set timestamps, caps, ... */
6536         sample = &stream->samples[stream->sample_index];
6537
6538         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
6539           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
6540               GST_FOURCC_ARGS (stream->fourcc));
6541
6542           dts = QTSAMPLE_DTS (stream, sample);
6543           pts = QTSAMPLE_PTS (stream, sample);
6544           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
6545           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
6546
6547           /* check for segment end */
6548           if (G_UNLIKELY (demux->segment.stop != -1
6549                   && demux->segment.stop <= pts && stream->on_keyframe)) {
6550             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
6551             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
6552
6553             /* skip this data, stream is EOS */
6554             gst_adapter_flush (demux->adapter, demux->neededbytes);
6555
6556             /* check if all streams are eos */
6557             ret = GST_FLOW_EOS;
6558             for (i = 0; i < demux->n_streams; i++) {
6559               if (!STREAM_IS_EOS (demux->streams[i])) {
6560                 ret = GST_FLOW_OK;
6561                 break;
6562               }
6563             }
6564
6565             if (ret == GST_FLOW_EOS) {
6566               GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
6567               goto eos;
6568             }
6569           } else {
6570             GstBuffer *outbuf;
6571
6572             outbuf =
6573                 gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
6574
6575             /* FIXME: should either be an assert or a plain check */
6576             g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
6577
6578             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
6579                 dts, pts, duration, keyframe, dts, demux->offset);
6580           }
6581
6582           /* combine flows */
6583           ret = gst_qtdemux_combine_flows (demux, stream, ret);
6584         } else {
6585           /* skip this data, stream is EOS */
6586           gst_adapter_flush (demux->adapter, demux->neededbytes);
6587         }
6588
6589         stream->sample_index++;
6590         stream->offset_in_sample = 0;
6591
6592         /* update current offset and figure out size of next buffer */
6593         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
6594             demux->offset, demux->neededbytes);
6595         demux->offset += demux->neededbytes;
6596         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
6597             demux->offset);
6598
6599         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
6600           if (demux->fragmented) {
6601             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
6602             /* there may be more to follow, only finish this atom */
6603             demux->todrop = demux->mdatleft;
6604             demux->neededbytes = demux->todrop;
6605             break;
6606           }
6607           goto eos;
6608         }
6609         break;
6610       }
6611       default:
6612         goto invalid_state;
6613     }
6614   }
6615
6616   /* when buffering movie data, at least show user something is happening */
6617   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
6618       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
6619     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
6620         demux->neededbytes);
6621   }
6622 done:
6623
6624   return ret;
6625
6626   /* ERRORS */
6627 unknown_stream:
6628   {
6629     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
6630     ret = GST_FLOW_ERROR;
6631     goto done;
6632   }
6633 eos:
6634   {
6635     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
6636     ret = GST_FLOW_EOS;
6637     goto done;
6638   }
6639 invalid_state:
6640   {
6641     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6642         (NULL), ("qtdemuxer invalid state %d", demux->state));
6643     ret = GST_FLOW_ERROR;
6644     goto done;
6645   }
6646 no_moov:
6647   {
6648     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
6649         (NULL), ("no 'moov' atom within the first 10 MB"));
6650     ret = GST_FLOW_ERROR;
6651     goto done;
6652   }
6653 }
6654
6655 static gboolean
6656 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
6657 {
6658   GstQuery *query;
6659   gboolean pull_mode;
6660
6661   query = gst_query_new_scheduling ();
6662
6663   if (!gst_pad_peer_query (sinkpad, query)) {
6664     gst_query_unref (query);
6665     goto activate_push;
6666   }
6667
6668   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
6669       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
6670   gst_query_unref (query);
6671
6672   if (!pull_mode)
6673     goto activate_push;
6674
6675   GST_DEBUG_OBJECT (sinkpad, "activating pull");
6676   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
6677
6678 activate_push:
6679   {
6680     GST_DEBUG_OBJECT (sinkpad, "activating push");
6681     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
6682   }
6683 }
6684
6685 static gboolean
6686 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
6687     GstPadMode mode, gboolean active)
6688 {
6689   gboolean res;
6690   GstQTDemux *demux = GST_QTDEMUX (parent);
6691
6692   switch (mode) {
6693     case GST_PAD_MODE_PUSH:
6694       demux->pullbased = FALSE;
6695       res = TRUE;
6696       break;
6697     case GST_PAD_MODE_PULL:
6698       if (active) {
6699         demux->pullbased = TRUE;
6700         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
6701             sinkpad, NULL);
6702       } else {
6703         res = gst_pad_stop_task (sinkpad);
6704       }
6705       break;
6706     default:
6707       res = FALSE;
6708       break;
6709   }
6710   return res;
6711 }
6712
6713 #ifdef HAVE_ZLIB
6714 static void *
6715 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
6716 {
6717   return g_malloc (items * size);
6718 }
6719
6720 static void
6721 qtdemux_zfree (void *opaque, void *addr)
6722 {
6723   g_free (addr);
6724 }
6725
6726 static void *
6727 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
6728 {
6729   guint8 *buffer;
6730   z_stream *z;
6731   int ret;
6732
6733   z = g_new0 (z_stream, 1);
6734   z->zalloc = qtdemux_zalloc;
6735   z->zfree = qtdemux_zfree;
6736   z->opaque = NULL;
6737
6738   z->next_in = z_buffer;
6739   z->avail_in = z_length;
6740
6741   buffer = (guint8 *) g_malloc (length);
6742   ret = inflateInit (z);
6743   while (z->avail_in > 0) {
6744     if (z->avail_out == 0) {
6745       length += 1024;
6746       buffer = (guint8 *) g_realloc (buffer, length);
6747       z->next_out = buffer + z->total_out;
6748       z->avail_out = 1024;
6749     }
6750     ret = inflate (z, Z_SYNC_FLUSH);
6751     if (ret != Z_OK)
6752       break;
6753   }
6754   if (ret != Z_STREAM_END) {
6755     g_warning ("inflate() returned %d", ret);
6756   }
6757
6758   g_free (z);
6759   return buffer;
6760 }
6761 #endif /* HAVE_ZLIB */
6762
6763 static gboolean
6764 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
6765 {
6766   GNode *cmov;
6767
6768   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
6769
6770   /* counts as header data */
6771   qtdemux->header_size += length;
6772
6773   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
6774   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
6775
6776   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
6777   if (cmov) {
6778     guint32 method;
6779     GNode *dcom;
6780     GNode *cmvd;
6781
6782     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
6783     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
6784     if (dcom == NULL || cmvd == NULL)
6785       goto invalid_compression;
6786
6787     method = QT_FOURCC ((guint8 *) dcom->data + 8);
6788     switch (method) {
6789 #ifdef HAVE_ZLIB
6790       case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
6791         guint uncompressed_length;
6792         guint compressed_length;
6793         guint8 *buf;
6794
6795         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
6796         compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
6797         GST_LOG ("length = %u", uncompressed_length);
6798
6799         buf =
6800             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
6801             compressed_length, uncompressed_length);
6802
6803         qtdemux->moov_node_compressed = qtdemux->moov_node;
6804         qtdemux->moov_node = g_node_new (buf);
6805
6806         qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
6807             uncompressed_length);
6808         break;
6809       }
6810 #endif /* HAVE_ZLIB */
6811       default:
6812         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
6813             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
6814         break;
6815     }
6816   }
6817   return TRUE;
6818
6819   /* ERRORS */
6820 invalid_compression:
6821   {
6822     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
6823     return FALSE;
6824   }
6825 }
6826
6827 static gboolean
6828 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
6829     const guint8 * end)
6830 {
6831   while (G_UNLIKELY (buf < end)) {
6832     GNode *child;
6833     guint32 len;
6834
6835     if (G_UNLIKELY (buf + 4 > end)) {
6836       GST_LOG_OBJECT (qtdemux, "buffer overrun");
6837       break;
6838     }
6839     len = QT_UINT32 (buf);
6840     if (G_UNLIKELY (len == 0)) {
6841       GST_LOG_OBJECT (qtdemux, "empty container");
6842       break;
6843     }
6844     if (G_UNLIKELY (len < 8)) {
6845       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
6846       break;
6847     }
6848     if (G_UNLIKELY (len > (end - buf))) {
6849       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
6850           (gint) (end - buf));
6851       break;
6852     }
6853
6854     child = g_node_new ((guint8 *) buf);
6855     g_node_append (node, child);
6856     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
6857     qtdemux_parse_node (qtdemux, child, buf, len);
6858
6859     buf += len;
6860   }
6861   return TRUE;
6862 }
6863
6864 static gboolean
6865 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
6866     GNode * xdxt)
6867 {
6868   int len = QT_UINT32 (xdxt->data);
6869   guint8 *buf = xdxt->data;
6870   guint8 *end = buf + len;
6871   GstBuffer *buffer;
6872
6873   /* skip size and type */
6874   buf += 8;
6875   end -= 8;
6876
6877   while (buf < end) {
6878     gint size;
6879     guint32 type;
6880
6881     size = QT_UINT32 (buf);
6882     type = QT_FOURCC (buf + 4);
6883
6884     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
6885
6886     if (buf + size > end || size <= 0)
6887       break;
6888
6889     buf += 8;
6890     size -= 8;
6891
6892     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
6893         GST_FOURCC_ARGS (type));
6894
6895     switch (type) {
6896       case FOURCC_tCtH:
6897         buffer = gst_buffer_new_and_alloc (size);
6898         gst_buffer_fill (buffer, 0, buf, size);
6899         stream->buffers = g_slist_append (stream->buffers, buffer);
6900         GST_LOG_OBJECT (qtdemux, "parsing theora header");
6901         break;
6902       case FOURCC_tCt_:
6903         buffer = gst_buffer_new_and_alloc (size);
6904         gst_buffer_fill (buffer, 0, buf, size);
6905         stream->buffers = g_slist_append (stream->buffers, buffer);
6906         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
6907         break;
6908       case FOURCC_tCtC:
6909         buffer = gst_buffer_new_and_alloc (size);
6910         gst_buffer_fill (buffer, 0, buf, size);
6911         stream->buffers = g_slist_append (stream->buffers, buffer);
6912         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
6913         break;
6914       default:
6915         GST_WARNING_OBJECT (qtdemux,
6916             "unknown theora cookie %" GST_FOURCC_FORMAT,
6917             GST_FOURCC_ARGS (type));
6918         break;
6919     }
6920     buf += size;
6921   }
6922   return TRUE;
6923 }
6924
6925 static gboolean
6926 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
6927     guint length)
6928 {
6929   guint32 fourcc = 0;
6930   guint32 node_length = 0;
6931   const QtNodeType *type;
6932   const guint8 *end;
6933
6934   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
6935
6936   if (G_UNLIKELY (length < 8))
6937     goto not_enough_data;
6938
6939   node_length = QT_UINT32 (buffer);
6940   fourcc = QT_FOURCC (buffer + 4);
6941
6942   /* ignore empty nodes */
6943   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
6944     return TRUE;
6945
6946   type = qtdemux_type_get (fourcc);
6947
6948   end = buffer + length;
6949
6950   GST_LOG_OBJECT (qtdemux,
6951       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
6952       GST_FOURCC_ARGS (fourcc), node_length, type->name);
6953
6954   if (node_length > length)
6955     goto broken_atom_size;
6956
6957   if (type->flags & QT_FLAG_CONTAINER) {
6958     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
6959   } else {
6960     switch (fourcc) {
6961       case FOURCC_stsd:
6962       {
6963         if (node_length < 20) {
6964           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
6965           break;
6966         }
6967         GST_DEBUG_OBJECT (qtdemux,
6968             "parsing stsd (sample table, sample description) atom");
6969         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
6970         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
6971         break;
6972       }
6973       case FOURCC_mp4a:
6974       case FOURCC_alac:
6975       {
6976         guint32 version;
6977         guint32 offset;
6978         guint min_size;
6979
6980         /* also read alac (or whatever) in stead of mp4a in the following,
6981          * since a similar layout is used in other cases as well */
6982         if (fourcc == FOURCC_mp4a)
6983           min_size = 20;
6984         else
6985           min_size = 40;
6986
6987         /* There are two things we might encounter here: a true mp4a atom, and
6988            an mp4a entry in an stsd atom. The latter is what we're interested
6989            in, and it looks like an atom, but isn't really one. The true mp4a
6990            atom is short, so we detect it based on length here. */
6991         if (length < min_size) {
6992           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
6993               GST_FOURCC_ARGS (fourcc));
6994           break;
6995         }
6996
6997         /* 'version' here is the sound sample description version. Types 0 and
6998            1 are documented in the QTFF reference, but type 2 is not: it's
6999            described in Apple header files instead (struct SoundDescriptionV2
7000            in Movies.h) */
7001         version = QT_UINT16 (buffer + 16);
7002
7003         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
7004             GST_FOURCC_ARGS (fourcc), version);
7005
7006         /* parse any esds descriptors */
7007         switch (version) {
7008           case 0:
7009             offset = 0x24;
7010             break;
7011           case 1:
7012             offset = 0x34;
7013             break;
7014           case 2:
7015             offset = 0x48;
7016             break;
7017           default:
7018             GST_WARNING_OBJECT (qtdemux,
7019                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
7020                 GST_FOURCC_ARGS (fourcc), version);
7021             offset = 0;
7022             break;
7023         }
7024         if (offset)
7025           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7026         break;
7027       }
7028       case FOURCC_mp4v:
7029       case FOURCC_MP4V:
7030       case FOURCC_fmp4:
7031       case FOURCC_FMP4:
7032       case FOURCC_apcs:
7033       case FOURCC_apch:
7034       case FOURCC_apcn:
7035       case FOURCC_apco:
7036       case FOURCC_ap4h:
7037       {
7038         const guint8 *buf;
7039         guint32 version;
7040         int tlen;
7041
7042         /* codec_data is contained inside these atoms, which all have
7043          * the same format. */
7044
7045         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
7046             GST_FOURCC_ARGS (fourcc));
7047         version = QT_UINT32 (buffer + 16);
7048         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
7049         if (1 || version == 0x00000000) {
7050           buf = buffer + 0x32;
7051
7052           /* FIXME Quicktime uses PASCAL string while
7053            * the iso format uses C strings. Check the file
7054            * type before attempting to parse the string here. */
7055           tlen = QT_UINT8 (buf);
7056           GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
7057           buf++;
7058           GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
7059           /* the string has a reserved space of 32 bytes so skip
7060            * the remaining 31 */
7061           buf += 31;
7062           buf += 4;             /* and 4 bytes reserved */
7063
7064           GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
7065
7066           qtdemux_parse_container (qtdemux, node, buf, end);
7067         }
7068         break;
7069       }
7070       case FOURCC_H264:
7071       {
7072         GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
7073         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7074         break;
7075       }
7076       case FOURCC_avc1:
7077       {
7078         GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
7079         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7080         break;
7081       }
7082       case FOURCC_avc3:
7083       {
7084         GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
7085         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7086         break;
7087       }
7088       case FOURCC_H265:
7089       {
7090         GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
7091         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7092         break;
7093       }
7094       case FOURCC_hvc1:
7095       {
7096         GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
7097         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7098         break;
7099       }
7100       case FOURCC_hev1:
7101       {
7102         GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
7103         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
7104         break;
7105       }
7106       case FOURCC_mjp2:
7107       {
7108         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7109         break;
7110       }
7111       case FOURCC_meta:
7112       {
7113         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
7114         qtdemux_parse_container (qtdemux, node, buffer + 12, end);
7115         break;
7116       }
7117       case FOURCC_mp4s:
7118       {
7119         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
7120         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
7121         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
7122         break;
7123       }
7124       case FOURCC_XiTh:
7125       {
7126         guint32 version;
7127         guint32 offset;
7128
7129         version = QT_UINT32 (buffer + 12);
7130         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
7131
7132         switch (version) {
7133           case 0x00000001:
7134             offset = 0x62;
7135             break;
7136           default:
7137             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
7138             offset = 0;
7139             break;
7140         }
7141         if (offset)
7142           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
7143         break;
7144       }
7145       case FOURCC_in24:
7146       {
7147         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
7148         break;
7149       }
7150       case FOURCC_uuid:
7151       {
7152         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
7153         break;
7154       }
7155       case FOURCC_encv:
7156       {
7157         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
7158         break;
7159       }
7160       case FOURCC_enca:
7161       {
7162         qtdemux_parse_container (qtdemux, node, buffer + 36, end);
7163         break;
7164       }
7165 #ifdef TIZEN_FEATURE_QTDEMUX_MODIFICATION
7166       case FOURCC_SA3D:
7167       {
7168         qtdemux_parse_SA3D (qtdemux, buffer, end - buffer);
7169         break;
7170       }
7171 #endif /* TIZEN_FEATURE_QTDEMUX_MODIFICATION */
7172       default:
7173         if (!strcmp (type->name, "unknown"))
7174           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
7175         break;
7176     }
7177   }
7178   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
7179       GST_FOURCC_ARGS (fourcc));
7180   return TRUE;
7181
7182 /* ERRORS */
7183 not_enough_data:
7184   {
7185     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7186         (_("This file is corrupt and cannot be played.")),
7187         ("Not enough data for an atom header, got only %u bytes", length));
7188     return FALSE;
7189   }
7190 broken_atom_size:
7191   {
7192     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7193         (_("This file is corrupt and cannot be played.")),
7194         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
7195             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
7196             length));
7197     return FALSE;
7198   }
7199 }
7200
7201 static GNode *
7202 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
7203 {
7204   GNode *child;
7205   guint8 *buffer;
7206   guint32 child_fourcc;
7207
7208   for (child = g_node_first_child (node); child;
7209       child = g_node_next_sibling (child)) {
7210     buffer = (guint8 *) child->data;
7211
7212     child_fourcc = QT_FOURCC (buffer + 4);
7213
7214     if (G_UNLIKELY (child_fourcc == fourcc)) {
7215       return child;
7216     }
7217   }
7218   return NULL;
7219 }
7220
7221 static GNode *
7222 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
7223     GstByteReader * parser)
7224 {
7225   GNode *child;
7226   guint8 *buffer;
7227   guint32 child_fourcc, child_len;
7228
7229   for (child = g_node_first_child (node); child;
7230       child = g_node_next_sibling (child)) {
7231     buffer = (guint8 *) child->data;
7232
7233     child_len = QT_UINT32 (buffer);
7234     child_fourcc = QT_FOURCC (buffer + 4);
7235
7236     if (G_UNLIKELY (child_fourcc == fourcc)) {
7237       if (G_UNLIKELY (child_len < (4 + 4)))
7238         return NULL;
7239       /* FIXME: must verify if atom length < parent atom length */
7240       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7241       return child;
7242     }
7243   }
7244   return NULL;
7245 }
7246
7247 static GNode *
7248 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
7249     GstByteReader * parser)
7250 {
7251   GNode *child;
7252   guint8 *buffer;
7253   guint32 child_fourcc, child_len;
7254
7255   for (child = g_node_next_sibling (node); child;
7256       child = g_node_next_sibling (child)) {
7257     buffer = (guint8 *) child->data;
7258
7259     child_fourcc = QT_FOURCC (buffer + 4);
7260
7261     if (child_fourcc == fourcc) {
7262       if (parser) {
7263         child_len = QT_UINT32 (buffer);
7264         if (G_UNLIKELY (child_len < (4 + 4)))
7265           return NULL;
7266         /* FIXME: must verify if atom length < parent atom length */
7267         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
7268       }
7269       return child;
7270     }
7271   }
7272   return NULL;
7273 }
7274
7275 static GNode *
7276 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
7277 {
7278   return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
7279 }
7280
7281 static void
7282 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
7283 {
7284 /* FIXME: This can only reliably work if demuxers have a
7285  * separate streaming thread per srcpad. This should be
7286  * done in a demuxer base class, which integrates parts
7287  * of multiqueue
7288  *
7289  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
7290  */
7291 #if 0
7292   GstQuery *query;
7293
7294   query = gst_query_new_allocation (stream->caps, FALSE);
7295
7296   if (!gst_pad_peer_query (stream->pad, query)) {
7297     /* not a problem, just debug a little */
7298     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
7299   }
7300
7301   if (stream->allocator)
7302     gst_object_unref (stream->allocator);
7303
7304   if (gst_query_get_n_allocation_params (query) > 0) {
7305     /* try the allocator */
7306     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
7307         &stream->params);
7308     stream->use_allocator = TRUE;
7309   } else {
7310     stream->allocator = NULL;
7311     gst_allocation_params_init (&stream->params);
7312     stream->use_allocator = FALSE;
7313   }
7314   gst_query_unref (query);
7315 #endif
7316 }
7317
7318 static gboolean
7319 gst_qtdemux_configure_protected_caps (GstQTDemux * qtdemux,
7320     QtDemuxStream * stream)
7321 {
7322   GstStructure *s;
7323   const gchar *selected_system;
7324
7325   g_return_val_if_fail (qtdemux != NULL, FALSE);
7326   g_return_val_if_fail (stream != NULL, FALSE);
7327   g_return_val_if_fail (gst_caps_get_size (stream->caps) == 1, FALSE);
7328
7329   if (stream->protection_scheme_type != FOURCC_cenc) {
7330     GST_ERROR_OBJECT (qtdemux, "unsupported protection scheme");
7331     return FALSE;
7332   }
7333   if (qtdemux->protection_system_ids == NULL) {
7334     GST_ERROR_OBJECT (qtdemux, "stream is protected using cenc, but no "
7335         "cenc protection system information has been found");
7336     return FALSE;
7337   }
7338   g_ptr_array_add (qtdemux->protection_system_ids, NULL);
7339   selected_system = gst_protection_select_system ((const gchar **)
7340       qtdemux->protection_system_ids->pdata);
7341   g_ptr_array_remove_index (qtdemux->protection_system_ids,
7342       qtdemux->protection_system_ids->len - 1);
7343   if (!selected_system) {
7344     GST_ERROR_OBJECT (qtdemux, "stream is protected, but no "
7345         "suitable decryptor element has been found");
7346     return FALSE;
7347   }
7348
7349   s = gst_caps_get_structure (stream->caps, 0);
7350   gst_structure_set (s,
7351       "original-media-type", G_TYPE_STRING, gst_structure_get_name (s),
7352       GST_PROTECTION_SYSTEM_ID_CAPS_FIELD, G_TYPE_STRING, selected_system,
7353       NULL);
7354   gst_structure_set_name (s, "application/x-cenc");
7355   return TRUE;
7356 }
7357
7358 static gboolean
7359 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
7360 {
7361   if (stream->subtype == FOURCC_vide) {
7362     /* fps is calculated base on the duration of the average framerate since
7363      * qt does not have a fixed framerate. */
7364     if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
7365       /* still frame */
7366       stream->fps_n = 0;
7367       stream->fps_d = 1;
7368     } else {
7369       if (stream->duration == 0 || stream->n_samples < 2) {
7370         stream->fps_n = stream->timescale;
7371         stream->fps_d = 1;
7372       } else {
7373         /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
7374         /* stream->duration is guint64, timescale, n_samples are guint32 */
7375         GstClockTime avg_duration =
7376             gst_util_uint64_scale_round (stream->duration -
7377             stream->first_duration, GST_SECOND,
7378             (guint64) (stream->timescale) * (stream->n_samples - 1));
7379
7380         GST_LOG_OBJECT (qtdemux,
7381             "Calculating avg sample duration based on stream duration %"
7382             G_GUINT64_FORMAT
7383             " minus first sample %u, leaving %d samples gives %"
7384             GST_TIME_FORMAT, stream->duration, stream->first_duration,
7385             stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
7386
7387         gst_video_guess_framerate (avg_duration, &stream->fps_n,
7388             &stream->fps_d);
7389       }
7390       GST_DEBUG_OBJECT (qtdemux,
7391           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
7392           stream->timescale, stream->fps_n, stream->fps_d);
7393     }
7394
7395     if (stream->caps) {
7396       stream->caps = gst_caps_make_writable (stream->caps);
7397
7398       gst_caps_set_simple (stream->caps,
7399           "width", G_TYPE_INT, stream->width,
7400           "height", G_TYPE_INT, stream->height,
7401           "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
7402
7403       /* calculate pixel-aspect-ratio using display width and height */
7404       GST_DEBUG_OBJECT (qtdemux,
7405           "video size %dx%d, target display size %dx%d", stream->width,
7406           stream->height, stream->display_width, stream->display_height);
7407       /* qt file might have pasp atom */
7408       if (stream->par_w > 0 && stream->par_h > 0) {
7409         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
7410         gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7411             GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7412       } else if (stream->display_width > 0 && stream->display_height > 0 &&
7413           stream->width > 0 && stream->height > 0) {
7414         gint n, d;
7415
7416         /* calculate the pixel aspect ratio using the display and pixel w/h */
7417         n = stream->display_width * stream->height;
7418         d = stream->display_height * stream->width;
7419         if (n == d)
7420           n = d = 1;
7421         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
7422         stream->par_w = n;
7423         stream->par_h = d;
7424         gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
7425             GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
7426       }
7427
7428       if (stream->multiview_mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
7429         guint par_w = 1, par_h = 1;
7430
7431         if (stream->par_w > 0 && stream->par_h > 0) {
7432           par_w = stream->par_w;
7433           par_h = stream->par_h;
7434         }
7435
7436         if (gst_video_multiview_guess_half_aspect (stream->multiview_mode,
7437                 stream->width, stream->height, par_w, par_h)) {
7438           stream->multiview_flags |= GST_VIDEO_MULTIVIEW_FLAGS_HALF_ASPECT;
7439         }
7440
7441         gst_caps_set_simple (stream->caps,
7442             "multiview-mode", G_TYPE_STRING,
7443             gst_video_multiview_mode_to_caps_string (stream->multiview_mode),
7444             "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
7445             stream->multiview_flags, GST_FLAG_SET_MASK_EXACT, NULL);
7446       }
7447     }
7448   }
7449
7450   else if (stream->subtype == FOURCC_soun) {
7451     if (stream->caps) {
7452       stream->caps = gst_caps_make_writable (stream->caps);
7453       if (stream->rate > 0)
7454         gst_caps_set_simple (stream->caps,
7455             "rate", G_TYPE_INT, (int) stream->rate, NULL);
7456       if (stream->n_channels > 0)
7457         gst_caps_set_simple (stream->caps,
7458             "channels", G_TYPE_INT, stream->n_channels, NULL);
7459       if (stream->n_channels > 2) {
7460         /* FIXME: Need to parse the 'chan' atom to get channel layouts
7461          * correctly; this is just the minimum we can do - assume
7462          * we don't actually have any channel positions. */
7463         gst_caps_set_simple (stream->caps,
7464             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
7465       }
7466     }
7467   }
7468
7469   if (stream->pad) {
7470     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
7471     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
7472     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
7473     gst_pad_set_active (stream->pad, TRUE);
7474
7475     gst_pad_use_fixed_caps (stream->pad);
7476
7477     if (stream->protected) {
7478       if (!gst_qtdemux_configure_protected_caps (qtdemux, stream)) {
7479         GST_ERROR_OBJECT (qtdemux,
7480             "Failed to configure protected stream caps.");
7481         return FALSE;
7482       }
7483     }
7484
7485     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
7486     if (stream->new_stream) {
7487       gchar *stream_id;
7488       GstEvent *event;
7489       GstStreamFlags stream_flags;
7490
7491       event =
7492           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
7493           0);
7494       if (event) {
7495         if (gst_event_parse_group_id (event, &qtdemux->group_id))
7496           qtdemux->have_group_id = TRUE;
7497         else
7498           qtdemux->have_group_id = FALSE;
7499         gst_event_unref (event);
7500       } else if (!qtdemux->have_group_id) {
7501         qtdemux->have_group_id = TRUE;
7502         qtdemux->group_id = gst_util_group_id_next ();
7503       }
7504
7505       stream->new_stream = FALSE;
7506       stream_id =
7507           gst_pad_create_stream_id_printf (stream->pad,
7508           GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
7509       event = gst_event_new_stream_start (stream_id);
7510       if (qtdemux->have_group_id)
7511         gst_event_set_group_id (event, qtdemux->group_id);
7512       stream_flags = GST_STREAM_FLAG_NONE;
7513       if (stream->disabled)
7514         stream_flags |= GST_STREAM_FLAG_UNSELECT;
7515       if (stream->sparse)
7516         stream_flags |= GST_STREAM_FLAG_SPARSE;
7517       gst_event_set_stream_flags (event, stream_flags);
7518       gst_pad_push_event (stream->pad, event);
7519       g_free (stream_id);
7520     }
7521     gst_pad_set_caps (stream->pad, stream->caps);
7522     stream->new_caps = FALSE;
7523   }
7524   return TRUE;
7525 }
7526
7527 static gboolean
7528 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
7529     QtDemuxStream * stream, GstTagList * list)
7530 {
7531   /* consistent default for push based mode */
7532   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
7533
7534   if (stream->subtype == FOURCC_vide) {
7535     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7536
7537     stream->pad =
7538         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7539     g_free (name);
7540
7541     gst_qtdemux_configure_stream (qtdemux, stream);
7542     qtdemux->n_video_streams++;
7543   } else if (stream->subtype == FOURCC_soun) {
7544     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
7545
7546     stream->pad =
7547         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
7548     g_free (name);
7549     gst_qtdemux_configure_stream (qtdemux, stream);
7550     qtdemux->n_audio_streams++;
7551   } else if (stream->subtype == FOURCC_strm) {
7552     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
7553   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
7554       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
7555     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
7556
7557     stream->pad =
7558         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
7559     g_free (name);
7560     gst_qtdemux_configure_stream (qtdemux, stream);
7561     qtdemux->n_sub_streams++;
7562   } else if (stream->caps) {
7563     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
7564
7565     stream->pad =
7566         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
7567     g_free (name);
7568     gst_qtdemux_configure_stream (qtdemux, stream);
7569     qtdemux->n_video_streams++;
7570   } else {
7571     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
7572     goto done;
7573   }
7574
7575   if (stream->pad) {
7576     GList *l;
7577
7578     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
7579         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
7580     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
7581     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
7582
7583     if (stream->pending_tags)
7584       gst_tag_list_unref (stream->pending_tags);
7585     stream->pending_tags = list;
7586     list = NULL;
7587     /* global tags go on each pad anyway */
7588     stream->send_global_tags = TRUE;
7589     /* send upstream GST_EVENT_PROTECTION events that were received before
7590        this source pad was created */
7591     for (l = qtdemux->protection_event_queue.head; l != NULL; l = l->next)
7592       gst_pad_push_event (stream->pad, gst_event_ref (l->data));
7593   }
7594 done:
7595   if (list)
7596     gst_tag_list_unref (list);
7597   return TRUE;
7598 }
7599
7600 /* find next atom with @fourcc starting at @offset */
7601 static GstFlowReturn
7602 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
7603     guint64 * length, guint32 fourcc)
7604 {
7605   GstFlowReturn ret;
7606   guint32 lfourcc;
7607   GstBuffer *buf;
7608
7609   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
7610       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
7611
7612   while (TRUE) {
7613     GstMapInfo map;
7614
7615     buf = NULL;
7616     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
7617     if (G_UNLIKELY (ret != GST_FLOW_OK))
7618       goto locate_failed;
7619     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
7620       /* likely EOF */
7621       ret = GST_FLOW_EOS;
7622       gst_buffer_unref (buf);
7623       goto locate_failed;
7624     }
7625     gst_buffer_map (buf, &map, GST_MAP_READ);
7626     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
7627     gst_buffer_unmap (buf, &map);
7628     gst_buffer_unref (buf);
7629
7630     if (G_UNLIKELY (*length == 0)) {
7631       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
7632       ret = GST_FLOW_ERROR;
7633       goto locate_failed;
7634     }
7635
7636     if (lfourcc == fourcc) {
7637       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
7638           *offset);
7639       break;
7640     } else {
7641       GST_LOG_OBJECT (qtdemux,
7642           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
7643           GST_FOURCC_ARGS (fourcc), *offset);
7644       *offset += *length;
7645     }
7646   }
7647
7648   return GST_FLOW_OK;
7649
7650 locate_failed:
7651   {
7652     /* might simply have had last one */
7653     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
7654     return ret;
7655   }
7656 }
7657
7658 /* should only do something in pull mode */
7659 /* call with OBJECT lock */
7660 static GstFlowReturn
7661 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
7662 {
7663   guint64 length, offset;
7664   GstBuffer *buf = NULL;
7665   GstFlowReturn ret = GST_FLOW_OK;
7666   GstFlowReturn res = GST_FLOW_OK;
7667   GstMapInfo map;
7668
7669   offset = qtdemux->moof_offset;
7670   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
7671
7672   if (!offset) {
7673     GST_DEBUG_OBJECT (qtdemux, "no next moof");
7674     return GST_FLOW_EOS;
7675   }
7676
7677   /* best not do pull etc with lock held */
7678   GST_OBJECT_UNLOCK (qtdemux);
7679
7680   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7681   if (ret != GST_FLOW_OK)
7682     goto flow_failed;
7683
7684   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
7685   if (G_UNLIKELY (ret != GST_FLOW_OK))
7686     goto flow_failed;
7687   gst_buffer_map (buf, &map, GST_MAP_READ);
7688   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
7689     gst_buffer_unmap (buf, &map);
7690     gst_buffer_unref (buf);
7691     buf = NULL;
7692     goto parse_failed;
7693   }
7694
7695   gst_buffer_unmap (buf, &map);
7696   gst_buffer_unref (buf);
7697   buf = NULL;
7698
7699   offset += length;
7700   /* look for next moof */
7701   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
7702   if (G_UNLIKELY (ret != GST_FLOW_OK))
7703     goto flow_failed;
7704
7705 exit:
7706   GST_OBJECT_LOCK (qtdemux);
7707
7708   qtdemux->moof_offset = offset;
7709
7710   return res;
7711
7712 parse_failed:
7713   {
7714     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
7715     offset = 0;
7716     res = GST_FLOW_ERROR;
7717     goto exit;
7718   }
7719 flow_failed:
7720   {
7721     /* maybe upstream temporarily flushing */
7722     if (ret != GST_FLOW_FLUSHING) {
7723       GST_DEBUG_OBJECT (qtdemux, "no next moof");
7724       offset = 0;
7725     } else {
7726       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
7727       /* resume at current position next time */
7728     }
7729     res = ret;
7730     goto exit;
7731   }
7732 }
7733
7734 /* initialise bytereaders for stbl sub-atoms */
7735 static gboolean
7736 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
7737 {
7738   stream->stbl_index = -1;      /* no samples have yet been parsed */
7739   stream->sample_index = -1;
7740
7741   /* time-to-sample atom */
7742   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
7743     goto corrupt_file;
7744
7745   /* copy atom data into a new buffer for later use */
7746   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
7747
7748   /* skip version + flags */
7749   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
7750       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
7751     goto corrupt_file;
7752   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
7753
7754   /* make sure there's enough data */
7755   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
7756     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
7757     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
7758         stream->n_sample_times);
7759     if (!stream->n_sample_times)
7760       goto corrupt_file;
7761   }
7762
7763   /* sync sample atom */
7764   stream->stps_present = FALSE;
7765   if ((stream->stss_present =
7766           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
7767               &stream->stss) ? TRUE : FALSE) == TRUE) {
7768     /* copy atom data into a new buffer for later use */
7769     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
7770
7771     /* skip version + flags */
7772     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
7773         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
7774       goto corrupt_file;
7775
7776     if (stream->n_sample_syncs) {
7777       /* make sure there's enough data */
7778       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
7779         goto corrupt_file;
7780     }
7781
7782     /* partial sync sample atom */
7783     if ((stream->stps_present =
7784             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
7785                 &stream->stps) ? TRUE : FALSE) == TRUE) {
7786       /* copy atom data into a new buffer for later use */
7787       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
7788
7789       /* skip version + flags */
7790       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
7791           !gst_byte_reader_get_uint32_be (&stream->stps,
7792               &stream->n_sample_partial_syncs))
7793         goto corrupt_file;
7794
7795       /* if there are no entries, the stss table contains the real
7796        * sync samples */
7797       if (stream->n_sample_partial_syncs) {
7798         /* make sure there's enough data */
7799         if (!qt_atom_parser_has_chunks (&stream->stps,
7800                 stream->n_sample_partial_syncs, 4))
7801           goto corrupt_file;
7802       }
7803     }
7804   }
7805
7806   /* sample size */
7807   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
7808     goto no_samples;
7809
7810   /* copy atom data into a new buffer for later use */
7811   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
7812
7813   /* skip version + flags */
7814   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
7815       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
7816     goto corrupt_file;
7817
7818   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
7819     goto corrupt_file;
7820
7821   if (!stream->n_samples)
7822     goto no_samples;
7823
7824   /* sample-to-chunk atom */
7825   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
7826     goto corrupt_file;
7827
7828   /* copy atom data into a new buffer for later use */
7829   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
7830
7831   /* skip version + flags */
7832   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
7833       !gst_byte_reader_get_uint32_be (&stream->stsc,
7834           &stream->n_samples_per_chunk))
7835     goto corrupt_file;
7836
7837   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
7838       stream->n_samples_per_chunk);
7839
7840   /* make sure there's enough data */
7841   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
7842           12))
7843     goto corrupt_file;
7844
7845
7846   /* chunk offset */
7847   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
7848     stream->co_size = sizeof (guint32);
7849   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
7850           &stream->stco))
7851     stream->co_size = sizeof (guint64);
7852   else
7853     goto corrupt_file;
7854
7855   /* copy atom data into a new buffer for later use */
7856   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
7857
7858   /* skip version + flags */
7859   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
7860     goto corrupt_file;
7861
7862   /* chunks_are_samples == TRUE means treat chunks as samples */
7863   stream->chunks_are_samples = stream->sample_size && !stream->sampled;
7864   if (stream->chunks_are_samples) {
7865     /* treat chunks as samples */
7866     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
7867       goto corrupt_file;
7868   } else {
7869     /* skip number of entries */
7870     if (!gst_byte_reader_skip (&stream->stco, 4))
7871       goto corrupt_file;
7872
7873     /* make sure there are enough data in the stsz atom */
7874     if (!stream->sample_size) {
7875       /* different sizes for each sample */
7876       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
7877         goto corrupt_file;
7878     }
7879   }
7880
7881   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
7882       stream->n_samples, (guint) sizeof (QtDemuxSample),
7883       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
7884
7885   if (stream->n_samples >=
7886       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
7887     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
7888         "be larger than %uMB (broken file?)", stream->n_samples,
7889         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
7890     return FALSE;
7891   }
7892
7893   g_assert (stream->samples == NULL);
7894   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
7895   if (!stream->samples) {
7896     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
7897         stream->n_samples);
7898     return FALSE;
7899   }
7900
7901   /* composition time-to-sample */
7902   if ((stream->ctts_present =
7903           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
7904               &stream->ctts) ? TRUE : FALSE) == TRUE) {
7905     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
7906
7907     /* copy atom data into a new buffer for later use */
7908     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
7909
7910     /* skip version + flags */
7911     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
7912         || !gst_byte_reader_get_uint32_be (&stream->ctts,
7913             &stream->n_composition_times))
7914       goto corrupt_file;
7915
7916     /* make sure there's enough data */
7917     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
7918             4 + 4))
7919       goto corrupt_file;
7920
7921     /* This is optional, if missing we iterate the ctts */
7922     if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_cslg, &cslg)) {
7923       if (!gst_byte_reader_skip (&cslg, 1 + 3)
7924           || !gst_byte_reader_get_uint32_be (&cslg, &stream->cslg_shift)) {
7925         g_free ((gpointer) cslg.data);
7926         goto corrupt_file;
7927       }
7928     } else {
7929       gint32 cslg_least = 0;
7930       guint num_entries, pos;
7931       gint i;
7932
7933       pos = gst_byte_reader_get_pos (&stream->ctts);
7934       num_entries = stream->n_composition_times;
7935
7936       stream->cslg_shift = 0;
7937
7938       for (i = 0; i < num_entries; i++) {
7939         gint32 offset;
7940
7941         gst_byte_reader_skip_unchecked (&stream->ctts, 4);
7942         offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7943
7944         if (offset < cslg_least)
7945           cslg_least = offset;
7946       }
7947
7948       if (cslg_least < 0)
7949         stream->cslg_shift = ABS (cslg_least);
7950       else
7951         stream->cslg_shift = 0;
7952
7953       /* reset the reader so we can generate sample table */
7954       gst_byte_reader_set_pos (&stream->ctts, pos);
7955     }
7956   } else {
7957     /* Ensure the cslg_shift value is consistent so we can use it
7958      * unconditionnally to produce TS and Segment */
7959     stream->cslg_shift = 0;
7960   }
7961
7962   return TRUE;
7963
7964 corrupt_file:
7965   {
7966     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7967         (_("This file is corrupt and cannot be played.")), (NULL));
7968     return FALSE;
7969   }
7970 no_samples:
7971   {
7972     gst_qtdemux_stbl_free (stream);
7973     if (!qtdemux->fragmented) {
7974       /* not quite good */
7975       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
7976       return FALSE;
7977     } else {
7978       /* may pick up samples elsewhere */
7979       return TRUE;
7980     }
7981   }
7982 }
7983
7984 /* collect samples from the next sample to be parsed up to sample @n for @stream
7985  * by reading the info from @stbl
7986  *
7987  * This code can be executed from both the streaming thread and the seeking
7988  * thread so it takes the object lock to protect itself
7989  */
7990 static gboolean
7991 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
7992 {
7993   gint i, j, k;
7994   QtDemuxSample *samples, *first, *cur, *last;
7995   guint32 n_samples_per_chunk;
7996   guint32 n_samples;
7997
7998   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
7999       GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
8000       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
8001
8002   n_samples = stream->n_samples;
8003
8004   if (n >= n_samples)
8005     goto out_of_samples;
8006
8007   GST_OBJECT_LOCK (qtdemux);
8008   if (n <= stream->stbl_index)
8009     goto already_parsed;
8010
8011   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
8012
8013   if (!stream->stsz.data) {
8014     /* so we already parsed and passed all the moov samples;
8015      * onto fragmented ones */
8016     g_assert (qtdemux->fragmented);
8017     goto done;
8018   }
8019
8020   /* pointer to the sample table */
8021   samples = stream->samples;
8022
8023   /* starts from -1, moves to the next sample index to parse */
8024   stream->stbl_index++;
8025
8026   /* keep track of the first and last sample to fill */
8027   first = &samples[stream->stbl_index];
8028   last = &samples[n];
8029
8030   if (!stream->chunks_are_samples) {
8031     /* set the sample sizes */
8032     if (stream->sample_size == 0) {
8033       /* different sizes for each sample */
8034       for (cur = first; cur <= last; cur++) {
8035         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
8036         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
8037             (guint) (cur - samples), cur->size);
8038       }
8039     } else {
8040       /* samples have the same size */
8041       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
8042       for (cur = first; cur <= last; cur++)
8043         cur->size = stream->sample_size;
8044     }
8045   }
8046
8047   n_samples_per_chunk = stream->n_samples_per_chunk;
8048   cur = first;
8049
8050   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
8051     guint32 last_chunk;
8052
8053     if (stream->stsc_chunk_index >= stream->last_chunk
8054         || stream->stsc_chunk_index < stream->first_chunk) {
8055       stream->first_chunk =
8056           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8057       stream->samples_per_chunk =
8058           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
8059       gst_byte_reader_skip_unchecked (&stream->stsc, 4);
8060
8061       /* chunk numbers are counted from 1 it seems */
8062       if (G_UNLIKELY (stream->first_chunk == 0))
8063         goto corrupt_file;
8064
8065       --stream->first_chunk;
8066
8067       /* the last chunk of each entry is calculated by taking the first chunk
8068        * of the next entry; except if there is no next, where we fake it with
8069        * INT_MAX */
8070       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
8071         stream->last_chunk = G_MAXUINT32;
8072       } else {
8073         stream->last_chunk =
8074             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
8075         if (G_UNLIKELY (stream->last_chunk == 0))
8076           goto corrupt_file;
8077
8078         --stream->last_chunk;
8079       }
8080
8081       GST_LOG_OBJECT (qtdemux,
8082           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
8083           stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
8084
8085       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
8086         goto corrupt_file;
8087
8088       if (stream->last_chunk != G_MAXUINT32) {
8089         if (!qt_atom_parser_peek_sub (&stream->stco,
8090                 stream->first_chunk * stream->co_size,
8091                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
8092                 &stream->co_chunk))
8093           goto corrupt_file;
8094
8095       } else {
8096         stream->co_chunk = stream->stco;
8097         if (!gst_byte_reader_skip (&stream->co_chunk,
8098                 stream->first_chunk * stream->co_size))
8099           goto corrupt_file;
8100       }
8101
8102       stream->stsc_chunk_index = stream->first_chunk;
8103     }
8104
8105     last_chunk = stream->last_chunk;
8106
8107     if (stream->chunks_are_samples) {
8108       cur = &samples[stream->stsc_chunk_index];
8109
8110       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8111         if (j > n) {
8112           /* save state */
8113           stream->stsc_chunk_index = j;
8114           goto done;
8115         }
8116
8117         cur->offset =
8118             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
8119             stream->co_size);
8120
8121         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
8122             "%" G_GUINT64_FORMAT, j, cur->offset);
8123
8124         if (stream->samples_per_frame * stream->bytes_per_frame) {
8125           cur->size =
8126               (stream->samples_per_chunk * stream->n_channels) /
8127               stream->samples_per_frame * stream->bytes_per_frame;
8128         } else {
8129           cur->size = stream->samples_per_chunk;
8130         }
8131
8132         GST_DEBUG_OBJECT (qtdemux,
8133             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
8134             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
8135                     stream->stco_sample_index)), cur->size);
8136
8137         cur->timestamp = stream->stco_sample_index;
8138         cur->duration = stream->samples_per_chunk;
8139         cur->keyframe = TRUE;
8140         cur++;
8141
8142         stream->stco_sample_index += stream->samples_per_chunk;
8143       }
8144       stream->stsc_chunk_index = j;
8145     } else {
8146       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
8147         guint32 samples_per_chunk;
8148         guint64 chunk_offset;
8149
8150         if (!stream->stsc_sample_index
8151             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
8152                 &stream->chunk_offset))
8153           goto corrupt_file;
8154
8155         samples_per_chunk = stream->samples_per_chunk;
8156         chunk_offset = stream->chunk_offset;
8157
8158         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
8159           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
8160               G_GUINT64_FORMAT " and size %d",
8161               (guint) (cur - samples), chunk_offset, cur->size);
8162
8163           cur->offset = chunk_offset;
8164           chunk_offset += cur->size;
8165           cur++;
8166
8167           if (G_UNLIKELY (cur > last)) {
8168             /* save state */
8169             stream->stsc_sample_index = k + 1;
8170             stream->chunk_offset = chunk_offset;
8171             stream->stsc_chunk_index = j;
8172             goto done2;
8173           }
8174         }
8175         stream->stsc_sample_index = 0;
8176       }
8177       stream->stsc_chunk_index = j;
8178     }
8179     stream->stsc_index++;
8180   }
8181
8182   if (stream->chunks_are_samples)
8183     goto ctts;
8184 done2:
8185   {
8186     guint32 n_sample_times;
8187
8188     n_sample_times = stream->n_sample_times;
8189     cur = first;
8190
8191     for (i = stream->stts_index; i < n_sample_times; i++) {
8192       guint32 stts_samples;
8193       gint32 stts_duration;
8194       gint64 stts_time;
8195
8196       if (stream->stts_sample_index >= stream->stts_samples
8197           || !stream->stts_sample_index) {
8198
8199         stream->stts_samples =
8200             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8201         stream->stts_duration =
8202             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
8203
8204         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
8205             i, stream->stts_samples, stream->stts_duration);
8206
8207         stream->stts_sample_index = 0;
8208       }
8209
8210       stts_samples = stream->stts_samples;
8211       stts_duration = stream->stts_duration;
8212       stts_time = stream->stts_time;
8213
8214       for (j = stream->stts_sample_index; j < stts_samples; j++) {
8215         GST_DEBUG_OBJECT (qtdemux,
8216             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
8217             (guint) (cur - samples), j,
8218             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
8219
8220         cur->timestamp = stts_time;
8221         cur->duration = stts_duration;
8222
8223         /* avoid 32-bit wrap-around,
8224          * but still mind possible 'negative' duration */
8225         stts_time += (gint64) stts_duration;
8226         cur++;
8227
8228         if (G_UNLIKELY (cur > last)) {
8229           /* save values */
8230           stream->stts_time = stts_time;
8231           stream->stts_sample_index = j + 1;
8232           goto done3;
8233         }
8234       }
8235       stream->stts_sample_index = 0;
8236       stream->stts_time = stts_time;
8237       stream->stts_index++;
8238     }
8239     /* fill up empty timestamps with the last timestamp, this can happen when
8240      * the last samples do not decode and so we don't have timestamps for them.
8241      * We however look at the last timestamp to estimate the track length so we
8242      * need something in here. */
8243     for (; cur < last; cur++) {
8244       GST_DEBUG_OBJECT (qtdemux,
8245           "fill sample %d: timestamp %" GST_TIME_FORMAT,
8246           (guint) (cur - samples),
8247           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
8248       cur->timestamp = stream->stts_time;
8249       cur->duration = -1;
8250     }
8251   }
8252 done3:
8253   {
8254     /* sample sync, can be NULL */
8255     if (stream->stss_present == TRUE) {
8256       guint32 n_sample_syncs;
8257
8258       n_sample_syncs = stream->n_sample_syncs;
8259
8260       if (!n_sample_syncs) {
8261         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
8262         stream->all_keyframe = TRUE;
8263       } else {
8264         for (i = stream->stss_index; i < n_sample_syncs; i++) {
8265           /* note that the first sample is index 1, not 0 */
8266           guint32 index;
8267
8268           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
8269
8270           if (G_LIKELY (index > 0 && index <= n_samples)) {
8271             index -= 1;
8272             samples[index].keyframe = TRUE;
8273             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8274             /* and exit if we have enough samples */
8275             if (G_UNLIKELY (index >= n)) {
8276               i++;
8277               break;
8278             }
8279           }
8280         }
8281         /* save state */
8282         stream->stss_index = i;
8283       }
8284
8285       /* stps marks partial sync frames like open GOP I-Frames */
8286       if (stream->stps_present == TRUE) {
8287         guint32 n_sample_partial_syncs;
8288
8289         n_sample_partial_syncs = stream->n_sample_partial_syncs;
8290
8291         /* if there are no entries, the stss table contains the real
8292          * sync samples */
8293         if (n_sample_partial_syncs) {
8294           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
8295             /* note that the first sample is index 1, not 0 */
8296             guint32 index;
8297
8298             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
8299
8300             if (G_LIKELY (index > 0 && index <= n_samples)) {
8301               index -= 1;
8302               samples[index].keyframe = TRUE;
8303               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
8304               /* and exit if we have enough samples */
8305               if (G_UNLIKELY (index >= n)) {
8306                 i++;
8307                 break;
8308               }
8309             }
8310           }
8311           /* save state */
8312           stream->stps_index = i;
8313         }
8314       }
8315     } else {
8316       /* no stss, all samples are keyframes */
8317       stream->all_keyframe = TRUE;
8318       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
8319     }
8320   }
8321
8322 ctts:
8323   /* composition time to sample */
8324   if (stream->ctts_present == TRUE) {
8325     guint32 n_composition_times;
8326     guint32 ctts_count;
8327     gint32 ctts_soffset;
8328
8329     /* Fill in the pts_offsets */
8330     cur = first;
8331     n_composition_times = stream->n_composition_times;
8332
8333     for (i = stream->ctts_index; i < n_composition_times; i++) {
8334       if (stream->ctts_sample_index >= stream->ctts_count
8335           || !stream->ctts_sample_index) {
8336         stream->ctts_count =
8337             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
8338         stream->ctts_soffset =
8339             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
8340         stream->ctts_sample_index = 0;
8341       }
8342
8343       ctts_count = stream->ctts_count;
8344       ctts_soffset = stream->ctts_soffset;
8345
8346       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
8347         cur->pts_offset = ctts_soffset;
8348         cur++;
8349
8350         if (G_UNLIKELY (cur > last)) {
8351           /* save state */
8352           stream->ctts_sample_index = j + 1;
8353           goto done;
8354         }
8355       }
8356       stream->ctts_sample_index = 0;
8357       stream->ctts_index++;
8358     }
8359   }
8360 done:
8361   stream->stbl_index = n;
8362   /* if index has been completely parsed, free data that is no-longer needed */
8363   if (n + 1 == stream->n_samples) {
8364     gst_qtdemux_stbl_free (stream);
8365     GST_DEBUG_OBJECT (qtdemux, "parsed all available samples;");
8366     if (qtdemux->pullbased) {
8367       GST_DEBUG_OBJECT (qtdemux, "checking for more samples");
8368       while (n + 1 == stream->n_samples)
8369         if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
8370           break;
8371     }
8372   }
8373   GST_OBJECT_UNLOCK (qtdemux);
8374
8375   return TRUE;
8376
8377   /* SUCCESS */
8378 already_parsed:
8379   {
8380     GST_LOG_OBJECT (qtdemux,
8381         "Tried to parse up to sample %u but this sample has already been parsed",
8382         n);
8383     /* if fragmented, there may be more */
8384     if (qtdemux->fragmented && n == stream->stbl_index)
8385       goto done;
8386     GST_OBJECT_UNLOCK (qtdemux);
8387     return TRUE;
8388   }
8389   /* ERRORS */
8390 out_of_samples:
8391   {
8392     GST_LOG_OBJECT (qtdemux,
8393         "Tried to parse up to sample %u but there are only %u samples", n + 1,
8394         stream->n_samples);
8395     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8396         (_("This file is corrupt and cannot be played.")), (NULL));
8397     return FALSE;
8398   }
8399 corrupt_file:
8400   {
8401     GST_OBJECT_UNLOCK (qtdemux);
8402     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
8403         (_("This file is corrupt and cannot be played.")), (NULL));
8404     return FALSE;
8405   }
8406 }
8407
8408 /* collect all segment info for @stream.
8409  */
8410 static gboolean
8411 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
8412     GNode * trak)
8413 {
8414   GNode *edts;
8415
8416   /* parse and prepare segment info from the edit list */
8417   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
8418   stream->n_segments = 0;
8419   stream->segments = NULL;
8420   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
8421     GNode *elst;
8422     gint n_segments;
8423     gint i, count;
8424     guint64 time;
8425     GstClockTime stime;
8426     guint8 *buffer;
8427
8428     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
8429     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
8430       goto done;
8431
8432     buffer = elst->data;
8433
8434     n_segments = QT_UINT32 (buffer + 12);
8435
8436     /* we might allocate a bit too much, at least allocate 1 segment */
8437     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
8438
8439     /* segments always start from 0 */
8440     time = 0;
8441     stime = 0;
8442     count = 0;
8443     for (i = 0; i < n_segments; i++) {
8444       guint64 duration;
8445       guint64 media_time;
8446       QtDemuxSegment *segment;
8447       guint32 rate_int;
8448 #ifdef TIZEN_FEATURE_GST_UPSTREAM
8449       GstClockTime media_start = GST_CLOCK_TIME_NONE;
8450 #endif
8451
8452       media_time = QT_UINT32 (buffer + 20 + i * 12);
8453       duration = QT_UINT32 (buffer + 16 + i * 12);
8454
8455 #ifdef TIZEN_FEATURE_GST_UPSTREAM
8456       if (media_time != G_MAXUINT32)
8457         media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8458 #endif
8459
8460       segment = &stream->segments[count++];
8461
8462       /* time and duration expressed in global timescale */
8463       segment->time = stime;
8464       /* add non scaled values so we don't cause roundoff errors */
8465 #ifdef TIZEN_FEATURE_GST_UPSTREAM
8466       if (duration || media_start == GST_CLOCK_TIME_NONE) {
8467         time += duration;
8468         stime = QTTIME_TO_GSTTIME (qtdemux, time);
8469         segment->duration = stime - segment->time;
8470       } else {
8471         /* zero duration does not imply media_start == media_stop
8472          * but, only specify media_start.*/
8473         stime = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
8474         if (GST_CLOCK_TIME_IS_VALID (stime) && media_time != G_MAXUINT32
8475             && stime >= media_start) {
8476           segment->duration = stime - media_start;
8477         } else {
8478           segment->duration = GST_CLOCK_TIME_NONE;
8479         }
8480       }
8481 #else
8482       time += duration;
8483       stime = QTTIME_TO_GSTTIME (qtdemux, time);
8484 #endif
8485       segment->stop_time = stime;
8486
8487 #ifndef TIZEN_FEATURE_GST_UPSTREAM
8488       segment->duration = stime - segment->time;
8489 #endif
8490
8491       segment->trak_media_start = media_time;
8492       /* media_time expressed in stream timescale */
8493       if (media_time != G_MAXUINT32) {
8494 #ifdef TIZEN_FEATURE_GST_UPSTREAM
8495         segment->media_start = media_start;
8496 #else
8497         segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
8498 #endif
8499         segment->media_stop = segment->media_start + segment->duration;
8500       } else {
8501         segment->media_start = GST_CLOCK_TIME_NONE;
8502         segment->media_stop = GST_CLOCK_TIME_NONE;
8503       }
8504       rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
8505
8506       if (rate_int <= 1) {
8507         /* 0 is not allowed, some programs write 1 instead of the floating point
8508          * value */
8509         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
8510             rate_int);
8511         segment->rate = 1;
8512       } else {
8513         segment->rate = rate_int / 65536.0;
8514       }
8515
8516       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
8517           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
8518           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
8519           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
8520           i, GST_TIME_ARGS (segment->time),
8521           GST_TIME_ARGS (segment->duration),
8522           GST_TIME_ARGS (segment->media_start), media_time,
8523           GST_TIME_ARGS (segment->media_stop),
8524           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
8525           stream->timescale);
8526       if (segment->stop_time > qtdemux->segment.stop) {
8527         GST_WARNING_OBJECT (qtdemux, "Segment %d "
8528             " extends to %" GST_TIME_FORMAT
8529             " past the end of the file duration %" GST_TIME_FORMAT
8530             " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
8531             GST_TIME_ARGS (qtdemux->segment.stop));
8532         qtdemux->segment.stop = segment->stop_time;
8533       }
8534     }
8535     GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
8536     stream->n_segments = count;
8537   }
8538 done:
8539
8540   /* push based does not handle segments, so act accordingly here,
8541    * and warn if applicable */
8542   if (!qtdemux->pullbased) {
8543     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
8544     /* remove and use default one below, we stream like it anyway */
8545     g_free (stream->segments);
8546     stream->segments = NULL;
8547     stream->n_segments = 0;
8548   }
8549
8550   /* no segments, create one to play the complete trak */
8551   if (stream->n_segments == 0) {
8552     GstClockTime stream_duration =
8553         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
8554
8555     if (stream->segments == NULL)
8556       stream->segments = g_new (QtDemuxSegment, 1);
8557
8558     /* represent unknown our way */
8559     if (stream_duration == 0)
8560       stream_duration = GST_CLOCK_TIME_NONE;
8561
8562     stream->segments[0].time = 0;
8563     stream->segments[0].stop_time = stream_duration;
8564     stream->segments[0].duration = stream_duration;
8565     stream->segments[0].media_start = 0;
8566     stream->segments[0].media_stop = stream_duration;
8567     stream->segments[0].rate = 1.0;
8568     stream->segments[0].trak_media_start = 0;
8569
8570     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
8571         GST_TIME_ARGS (stream_duration));
8572     stream->n_segments = 1;
8573     stream->dummy_segment = TRUE;
8574   }
8575   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
8576
8577   return TRUE;
8578 }
8579
8580 /*
8581  * Parses the stsd atom of a svq3 trak looking for
8582  * the SMI and gama atoms.
8583  */
8584 static void
8585 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
8586     guint8 ** gamma, GstBuffer ** seqh)
8587 {
8588   guint8 *_gamma = NULL;
8589   GstBuffer *_seqh = NULL;
8590   guint8 *stsd_data = stsd->data;
8591   guint32 length = QT_UINT32 (stsd_data);
8592   guint16 version;
8593
8594   if (length < 32) {
8595     GST_WARNING_OBJECT (qtdemux, "stsd too short");
8596     goto end;
8597   }
8598
8599   stsd_data += 32;
8600   length -= 32;
8601   version = QT_UINT16 (stsd_data);
8602   if (version == 3) {
8603     if (length >= 70) {
8604       length -= 70;
8605       stsd_data += 70;
8606       while (length > 8) {
8607         guint32 fourcc, size;
8608         guint8 *data;
8609         size = QT_UINT32 (stsd_data);
8610         fourcc = QT_FOURCC (stsd_data + 4);
8611         data = stsd_data + 8;
8612
8613         if (size == 0) {
8614           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
8615               "svq3 atom parsing");
8616           goto end;
8617         }
8618
8619         switch (fourcc) {
8620           case FOURCC_gama:{
8621             if (size == 12) {
8622               _gamma = data;
8623             } else {
8624               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
8625                   " for gama atom, expected 12", size);
8626             }
8627             break;
8628           }
8629           case FOURCC_SMI_:{
8630             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
8631               guint32 seqh_size;
8632               if (_seqh != NULL) {
8633                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
8634                     " found, ignoring");
8635               } else {
8636                 seqh_size = QT_UINT32 (data + 4);
8637                 if (seqh_size > 0) {
8638                   _seqh = gst_buffer_new_and_alloc (seqh_size);
8639                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
8640                 }
8641               }
8642             }
8643             break;
8644           }
8645           default:{
8646             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
8647                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
8648           }
8649         }
8650
8651         if (size <= length) {
8652           length -= size;
8653           stsd_data += size;
8654         }
8655       }
8656     } else {
8657       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
8658     }
8659   } else {
8660     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
8661         G_GUINT16_FORMAT, version);
8662     goto end;
8663   }
8664
8665 end:
8666   if (gamma) {
8667     *gamma = _gamma;
8668   }
8669   if (seqh) {
8670     *seqh = _seqh;
8671   } else if (_seqh) {
8672     gst_buffer_unref (_seqh);
8673   }
8674 }
8675
8676 static gchar *
8677 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
8678 {
8679   GNode *dinf;
8680   GstByteReader dref;
8681   gchar *uri = NULL;
8682
8683   /*
8684    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
8685    * atom that might contain a 'data' atom with the rtsp uri.
8686    * This case was reported in bug #597497, some info about
8687    * the hndl atom can be found in TN1195
8688    */
8689   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
8690   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
8691
8692   if (dinf) {
8693     guint32 dref_num_entries = 0;
8694     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
8695         gst_byte_reader_skip (&dref, 4) &&
8696         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
8697       gint i;
8698
8699       /* search dref entries for hndl atom */
8700       for (i = 0; i < dref_num_entries; i++) {
8701         guint32 size = 0, type;
8702         guint8 string_len = 0;
8703         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
8704             qt_atom_parser_get_fourcc (&dref, &type)) {
8705           if (type == FOURCC_hndl) {
8706             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
8707
8708             /* skip data reference handle bytes and the
8709              * following pascal string and some extra 4
8710              * bytes I have no idea what are */
8711             if (!gst_byte_reader_skip (&dref, 4) ||
8712                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
8713                 !gst_byte_reader_skip (&dref, string_len + 4)) {
8714               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
8715               break;
8716             }
8717
8718             /* iterate over the atoms to find the data atom */
8719             while (gst_byte_reader_get_remaining (&dref) >= 8) {
8720               guint32 atom_size;
8721               guint32 atom_type;
8722
8723               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
8724                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
8725                 if (atom_type == FOURCC_data) {
8726                   const guint8 *uri_aux = NULL;
8727
8728                   /* found the data atom that might contain the rtsp uri */
8729                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
8730                       "hndl atom, interpreting it as an URI");
8731                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
8732                           &uri_aux)) {
8733                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
8734                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
8735                     else
8736                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
8737                           "didn't contain a rtsp address");
8738                   } else {
8739                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
8740                         "atom contents");
8741                   }
8742                   break;
8743                 }
8744                 /* skipping to the next entry */
8745                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
8746                   break;
8747               } else {
8748                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
8749                     "atom header");
8750                 break;
8751               }
8752             }
8753             break;
8754           }
8755           /* skip to the next entry */
8756           if (!gst_byte_reader_skip (&dref, size - 8))
8757             break;
8758         } else {
8759           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
8760         }
8761       }
8762       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
8763     }
8764   }
8765   return uri;
8766 }
8767
8768 #define AMR_NB_ALL_MODES        0x81ff
8769 #define AMR_WB_ALL_MODES        0x83ff
8770 static guint
8771 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
8772 {
8773   /* The 'damr' atom is of the form:
8774    *
8775    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
8776    *    32 b       8 b          16 b           8 b                 8 b
8777    *
8778    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
8779    * represents the highest mode used in the stream (and thus the maximum
8780    * bitrate), with a couple of special cases as seen below.
8781    */
8782
8783   /* Map of frame type ID -> bitrate */
8784   static const guint nb_bitrates[] = {
8785     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
8786   };
8787   static const guint wb_bitrates[] = {
8788     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
8789   };
8790   GstMapInfo map;
8791   gsize max_mode;
8792   guint16 mode_set;
8793
8794   gst_buffer_map (buf, &map, GST_MAP_READ);
8795
8796   if (map.size != 0x11) {
8797     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
8798     goto bad_data;
8799   }
8800
8801   if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
8802     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
8803         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
8804     goto bad_data;
8805   }
8806
8807   mode_set = QT_UINT16 (map.data + 13);
8808
8809   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
8810     max_mode = 7 + (wb ? 1 : 0);
8811   else
8812     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
8813     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
8814
8815   if (max_mode == -1) {
8816     GST_DEBUG ("No mode indication was found (mode set) = %x",
8817         (guint) mode_set);
8818     goto bad_data;
8819   }
8820
8821   gst_buffer_unmap (buf, &map);
8822   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
8823
8824 bad_data:
8825   gst_buffer_unmap (buf, &map);
8826   return 0;
8827 }
8828
8829 static gboolean
8830 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
8831     GstByteReader * reader, guint32 * matrix, const gchar * atom)
8832 {
8833   /*
8834    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
8835    * [0 1 2]
8836    * [3 4 5]
8837    * [6 7 8]
8838    */
8839
8840   if (gst_byte_reader_get_remaining (reader) < 36)
8841     return FALSE;
8842
8843   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
8844   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
8845   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
8846   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
8847   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
8848   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
8849   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
8850   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
8851   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
8852
8853   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
8854   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
8855       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
8856       matrix[2] & 0xFF);
8857   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
8858       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
8859       matrix[5] & 0xFF);
8860   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
8861       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
8862       matrix[8] & 0xFF);
8863
8864   return TRUE;
8865 }
8866
8867 static void
8868 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
8869     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
8870 {
8871
8872 /* [a b c]
8873  * [d e f]
8874  * [g h i]
8875  *
8876  * This macro will only compare value abdegh, it expects cfi to have already
8877  * been checked
8878  */
8879 #define QTCHECK_MATRIX(m,a,b,d,e) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
8880                                    (m)[3] == (d << 16) && (m)[4] == (e << 16))
8881
8882   /* only handle the cases where the last column has standard values */
8883   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
8884     const gchar *rotation_tag = NULL;
8885
8886     /* no rotation needed */
8887     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1)) {
8888       /* NOP */
8889     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0)) {
8890       rotation_tag = "rotate-90";
8891     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16)) {
8892       rotation_tag = "rotate-180";
8893     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0)) {
8894       rotation_tag = "rotate-270";
8895     } else {
8896       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8897     }
8898
8899     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
8900         rotation_tag);
8901     if (rotation_tag != NULL) {
8902       if (*taglist == NULL)
8903         *taglist = gst_tag_list_new_empty ();
8904       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
8905           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
8906     }
8907   } else {
8908     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
8909   }
8910 }
8911
8912 /* Parses the boxes defined in ISO/IEC 14496-12 that enable support for
8913  * protected streams (sinf, frma, schm and schi); if the protection scheme is
8914  * Common Encryption (cenc), the function will also parse the tenc box (defined
8915  * in ISO/IEC 23001-7). @container points to the node that contains these boxes
8916  * (typically an enc[v|a|t|s] sample entry); the function will set
8917  * @original_fmt to the fourcc of the original unencrypted stream format.
8918  * Returns TRUE if successful; FALSE otherwise. */
8919 static gboolean
8920 qtdemux_parse_protection_scheme_info (GstQTDemux * qtdemux,
8921     QtDemuxStream * stream, GNode * container, guint32 * original_fmt)
8922 {
8923   GNode *sinf;
8924   GNode *frma;
8925   GNode *schm;
8926   GNode *schi;
8927
8928   g_return_val_if_fail (qtdemux != NULL, FALSE);
8929   g_return_val_if_fail (stream != NULL, FALSE);
8930   g_return_val_if_fail (container != NULL, FALSE);
8931   g_return_val_if_fail (original_fmt != NULL, FALSE);
8932
8933   sinf = qtdemux_tree_get_child_by_type (container, FOURCC_sinf);
8934   if (G_UNLIKELY (!sinf)) {
8935     if (stream->protection_scheme_type == FOURCC_cenc) {
8936       GST_ERROR_OBJECT (qtdemux, "sinf box does not contain schi box, which is "
8937           "mandatory for Common Encryption");
8938       return FALSE;
8939     }
8940     return TRUE;
8941   }
8942
8943   frma = qtdemux_tree_get_child_by_type (sinf, FOURCC_frma);
8944   if (G_UNLIKELY (!frma)) {
8945     GST_ERROR_OBJECT (qtdemux, "sinf box does not contain mandatory frma box");
8946     return FALSE;
8947   }
8948
8949   *original_fmt = QT_FOURCC ((const guint8 *) frma->data + 8);
8950   GST_DEBUG_OBJECT (qtdemux, "original stream format: '%" GST_FOURCC_FORMAT "'",
8951       GST_FOURCC_ARGS (*original_fmt));
8952
8953   schm = qtdemux_tree_get_child_by_type (sinf, FOURCC_schm);
8954   if (!schm) {
8955     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schm box");
8956     return FALSE;
8957   }
8958   stream->protection_scheme_type = QT_FOURCC ((const guint8 *) schm->data + 12);
8959   stream->protection_scheme_version =
8960       QT_UINT32 ((const guint8 *) schm->data + 16);
8961
8962   GST_DEBUG_OBJECT (qtdemux,
8963       "protection_scheme_type: %" GST_FOURCC_FORMAT ", "
8964       "protection_scheme_version: %#010x",
8965       GST_FOURCC_ARGS (stream->protection_scheme_type),
8966       stream->protection_scheme_version);
8967
8968   schi = qtdemux_tree_get_child_by_type (sinf, FOURCC_schi);
8969   if (!schi) {
8970     GST_DEBUG_OBJECT (qtdemux, "sinf box does not contain schi box");
8971     return FALSE;
8972   }
8973   if (stream->protection_scheme_type == FOURCC_cenc) {
8974     QtDemuxCencSampleSetInfo *info;
8975     GNode *tenc;
8976     const guint8 *tenc_data;
8977     guint32 isEncrypted;
8978     guint8 iv_size;
8979     const guint8 *default_kid;
8980     GstBuffer *kid_buf;
8981
8982     if (G_UNLIKELY (!stream->protection_scheme_info))
8983       stream->protection_scheme_info =
8984           g_malloc0 (sizeof (QtDemuxCencSampleSetInfo));
8985
8986     info = (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
8987
8988     tenc = qtdemux_tree_get_child_by_type (schi, FOURCC_tenc);
8989     if (!tenc) {
8990       GST_ERROR_OBJECT (qtdemux, "schi box does not contain tenc box, "
8991           "which is mandatory for Common Encryption");
8992       return FALSE;
8993     }
8994     tenc_data = (const guint8 *) tenc->data + 12;
8995     isEncrypted = QT_UINT24 (tenc_data);
8996     iv_size = QT_UINT8 (tenc_data + 3);
8997     default_kid = (tenc_data + 4);
8998     kid_buf = gst_buffer_new_allocate (NULL, 16, NULL);
8999     gst_buffer_fill (kid_buf, 0, default_kid, 16);
9000     if (info->default_properties)
9001       gst_structure_free (info->default_properties);
9002     info->default_properties =
9003         gst_structure_new ("application/x-cenc",
9004         "iv_size", G_TYPE_UINT, iv_size,
9005         "encrypted", G_TYPE_BOOLEAN, (isEncrypted == 1),
9006         "kid", GST_TYPE_BUFFER, kid_buf, NULL);
9007     GST_DEBUG_OBJECT (qtdemux, "default sample properties: "
9008         "is_encrypted=%u, iv_size=%u", isEncrypted, iv_size);
9009     gst_buffer_unref (kid_buf);
9010   }
9011   return TRUE;
9012 }
9013
9014 /* parse the traks.
9015  * With each track we associate a new QtDemuxStream that contains all the info
9016  * about the trak.
9017  * traks that do not decode to something (like strm traks) will not have a pad.
9018  */
9019 static gboolean
9020 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
9021 {
9022   GstByteReader tkhd;
9023   int offset;
9024   GNode *mdia;
9025   GNode *mdhd;
9026   GNode *hdlr;
9027   GNode *minf;
9028   GNode *stbl;
9029   GNode *stsd;
9030   GNode *mp4a;
9031   GNode *mp4v;
9032   GNode *wave;
9033   GNode *esds;
9034   GNode *pasp;
9035   GNode *tref;
9036   GNode *udta;
9037   GNode *svmi;
9038
9039   QtDemuxStream *stream = NULL;
9040   gboolean new_stream = FALSE;
9041   gchar *codec = NULL;
9042   const guint8 *stsd_data;
9043   guint16 lang_code;            /* quicktime lang code or packed iso code */
9044   guint32 version;
9045   guint32 tkhd_flags = 0;
9046   guint8 tkhd_version = 0;
9047   guint32 fourcc;
9048   guint value_size, stsd_len, len;
9049   guint32 track_id;
9050
9051   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
9052
9053   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
9054       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
9055       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
9056     goto corrupt_file;
9057
9058   /* pick between 64 or 32 bits */
9059   value_size = tkhd_version == 1 ? 8 : 4;
9060   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
9061       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
9062     goto corrupt_file;
9063
9064   if (!qtdemux->got_moov) {
9065     if (qtdemux_find_stream (qtdemux, track_id))
9066       goto existing_stream;
9067     stream = _create_stream ();
9068     stream->track_id = track_id;
9069     new_stream = TRUE;
9070   } else {
9071     stream = qtdemux_find_stream (qtdemux, track_id);
9072     if (!stream) {
9073       GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
9074       goto skip_track;
9075     }
9076
9077     /* flush samples data from this track from previous moov */
9078     gst_qtdemux_stream_flush_segments_data (qtdemux, stream);
9079     gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
9080   }
9081
9082   if (stream->pending_tags == NULL)
9083     stream->pending_tags = gst_tag_list_new_empty ();
9084
9085   if ((tkhd_flags & 1) == 0)
9086     stream->disabled = TRUE;
9087
9088   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
9089       tkhd_version, tkhd_flags, stream->track_id);
9090
9091   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
9092     goto corrupt_file;
9093
9094   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
9095     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
9096     if (qtdemux->major_brand != FOURCC_mjp2 ||
9097         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
9098       goto corrupt_file;
9099   }
9100
9101   len = QT_UINT32 ((guint8 *) mdhd->data);
9102   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
9103   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
9104   if (version == 0x01000000) {
9105     if (len < 38)
9106       goto corrupt_file;
9107     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
9108     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
9109     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
9110   } else {
9111     if (len < 30)
9112       goto corrupt_file;
9113     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
9114     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
9115     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
9116   }
9117
9118   if (lang_code < 0x400) {
9119     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
9120   } else if (lang_code == 0x7fff) {
9121     stream->lang_id[0] = 0;     /* unspecified */
9122   } else {
9123     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
9124     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
9125     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
9126     stream->lang_id[3] = 0;
9127   }
9128
9129   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
9130       stream->timescale);
9131   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
9132       stream->duration);
9133   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
9134       lang_code, stream->lang_id);
9135
9136   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
9137     goto corrupt_file;
9138
9139   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
9140     /* chapters track reference */
9141     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
9142     if (chap) {
9143       gsize length = GST_READ_UINT32_BE (chap->data);
9144       if (qtdemux->chapters_track_id)
9145         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
9146
9147       if (length >= 12) {
9148         qtdemux->chapters_track_id =
9149             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
9150       }
9151     }
9152   }
9153
9154   /* fragmented files may have bogus duration in moov */
9155   if (!qtdemux->fragmented &&
9156       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
9157     guint64 tdur1, tdur2;
9158
9159     /* don't overflow */
9160     tdur1 = stream->timescale * (guint64) qtdemux->duration;
9161     tdur2 = qtdemux->timescale * (guint64) stream->duration;
9162
9163     /* HACK:
9164      * some of those trailers, nowadays, have prologue images that are
9165      * themselves vide tracks as well. I haven't really found a way to
9166      * identify those yet, except for just looking at their duration. */
9167     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
9168       GST_WARNING_OBJECT (qtdemux,
9169           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
9170           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
9171           "found, assuming preview image or something; skipping track",
9172           stream->duration, stream->timescale, qtdemux->duration,
9173           qtdemux->timescale);
9174       if (new_stream)
9175         gst_qtdemux_stream_free (qtdemux, stream);
9176       return TRUE;
9177     }
9178   }
9179
9180   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
9181     goto corrupt_file;
9182
9183   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
9184       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
9185
9186   len = QT_UINT32 ((guint8 *) hdlr->data);
9187   if (len >= 20)
9188     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
9189   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
9190       GST_FOURCC_ARGS (stream->subtype));
9191
9192   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
9193     goto corrupt_file;
9194
9195   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
9196     goto corrupt_file;
9197
9198   /*parse svmi header if existing */
9199   svmi = qtdemux_tree_get_child_by_type (stbl, FOURCC_svmi);
9200   if (svmi) {
9201     len = QT_UINT32 ((guint8 *) svmi->data);
9202     version = QT_UINT32 ((guint8 *) svmi->data + 8);
9203     if (!version) {
9204       GstVideoMultiviewMode mode = GST_VIDEO_MULTIVIEW_MODE_NONE;
9205       GstVideoMultiviewFlags flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
9206       guint8 frame_type, frame_layout;
9207
9208       /* MPEG-A stereo video */
9209       if (qtdemux->major_brand == FOURCC_ss02)
9210         flags |= GST_VIDEO_MULTIVIEW_FLAGS_MIXED_MONO;
9211
9212       frame_type = QT_UINT8 ((guint8 *) svmi->data + 12);
9213       frame_layout = QT_UINT8 ((guint8 *) svmi->data + 13) & 0x01;
9214       switch (frame_type) {
9215         case 0:
9216           mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
9217           break;
9218         case 1:
9219           mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
9220           break;
9221         case 2:
9222           mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
9223           break;
9224         case 3:
9225           /* mode 3 is primary/secondary view sequence, ie
9226            * left/right views in separate tracks. See section 7.2
9227            * of ISO/IEC 23000-11:2009 */
9228           GST_FIXME_OBJECT (qtdemux,
9229               "Implement stereo video in separate streams");
9230       }
9231
9232       if ((frame_layout & 0x1) == 0)
9233         flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
9234
9235       GST_LOG_OBJECT (qtdemux,
9236           "StereoVideo: composition type: %u, is_left_first: %u",
9237           frame_type, frame_layout);
9238       stream->multiview_mode = mode;
9239       stream->multiview_flags = flags;
9240     }
9241   }
9242
9243   /* parse stsd */
9244   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
9245     goto corrupt_file;
9246   stsd_data = (const guint8 *) stsd->data;
9247
9248   /* stsd should at least have one entry */
9249   stsd_len = QT_UINT32 (stsd_data);
9250   if (stsd_len < 24) {
9251     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
9252     if (stream->subtype == FOURCC_vivo) {
9253       if (new_stream)
9254         gst_qtdemux_stream_free (qtdemux, stream);
9255       return TRUE;
9256     } else {
9257       goto corrupt_file;
9258     }
9259   }
9260
9261   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
9262
9263   /* and that entry should fit within stsd */
9264   len = QT_UINT32 (stsd_data + 16);
9265   if (len > stsd_len + 16)
9266     goto corrupt_file;
9267
9268   stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
9269   GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
9270       GST_FOURCC_ARGS (stream->fourcc));
9271   GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
9272
9273   if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi))
9274     goto error_encrypted;
9275
9276   if (fourcc == FOURCC_encv || fourcc == FOURCC_enca) {
9277     GNode *enc = qtdemux_tree_get_child_by_type (stsd, fourcc);
9278     stream->protected = TRUE;
9279     if (!qtdemux_parse_protection_scheme_info (qtdemux, stream, enc, &fourcc))
9280       GST_ERROR_OBJECT (qtdemux, "Failed to parse protection scheme info");
9281   }
9282
9283   if (stream->subtype == FOURCC_vide) {
9284     guint32 w = 0, h = 0;
9285     gboolean gray;
9286     gint depth, palette_size, palette_count;
9287     guint32 matrix[9];
9288     guint32 *palette_data = NULL;
9289
9290     stream->sampled = TRUE;
9291
9292     /* version 1 uses some 64-bit ints */
9293     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
9294       goto corrupt_file;
9295
9296     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
9297       goto corrupt_file;
9298
9299     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
9300         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
9301       goto corrupt_file;
9302
9303     stream->display_width = w >> 16;
9304     stream->display_height = h >> 16;
9305
9306     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix,
9307         &stream->pending_tags);
9308
9309     offset = 16;
9310     if (len < 86)
9311       goto corrupt_file;
9312
9313     stream->width = QT_UINT16 (stsd_data + offset + 32);
9314     stream->height = QT_UINT16 (stsd_data + offset + 34);
9315     stream->fps_n = 0;          /* this is filled in later */
9316     stream->fps_d = 0;          /* this is filled in later */
9317     stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
9318     stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
9319
9320     GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
9321         stream->width, stream->height, stream->bits_per_sample,
9322         stream->color_table_id);
9323
9324     depth = stream->bits_per_sample;
9325
9326     /* more than 32 bits means grayscale */
9327     gray = (depth > 32);
9328     /* low 32 bits specify the depth  */
9329     depth &= 0x1F;
9330
9331     /* different number of palette entries is determined by depth. */
9332     palette_count = 0;
9333     if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
9334       palette_count = (1 << depth);
9335     palette_size = palette_count * 4;
9336
9337     if (stream->color_table_id) {
9338       switch (palette_count) {
9339         case 0:
9340           break;
9341         case 2:
9342           palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
9343           break;
9344         case 4:
9345           palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
9346           break;
9347         case 16:
9348           if (gray)
9349             palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
9350           else
9351             palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
9352           break;
9353         case 256:
9354           if (gray)
9355             palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
9356           else
9357             palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
9358           break;
9359         default:
9360           GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9361               (_("The video in this file might not play correctly.")),
9362               ("unsupported palette depth %d", depth));
9363           break;
9364       }
9365     } else {
9366       gint i, j, start, end;
9367
9368       if (len < 94)
9369         goto corrupt_file;
9370
9371       /* read table */
9372       start = QT_UINT32 (stsd_data + offset + 86);
9373       palette_count = QT_UINT16 (stsd_data + offset + 90);
9374       end = QT_UINT16 (stsd_data + offset + 92);
9375
9376       GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
9377           start, end, palette_count);
9378
9379       if (end > 255)
9380         end = 255;
9381       if (start > end)
9382         start = end;
9383
9384       if (len < 94 + (end - start) * 8)
9385         goto corrupt_file;
9386
9387       /* palette is always the same size */
9388       palette_data = g_malloc0 (256 * 4);
9389       palette_size = 256 * 4;
9390
9391       for (j = 0, i = start; i <= end; j++, i++) {
9392         guint32 a, r, g, b;
9393
9394         a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
9395         r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
9396         g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
9397         b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
9398
9399         palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
9400             (g & 0xff00) | (b >> 8);
9401       }
9402     }
9403
9404     if (stream->caps)
9405       gst_caps_unref (stream->caps);
9406
9407     stream->caps =
9408         qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9409     if (G_UNLIKELY (!stream->caps)) {
9410       g_free (palette_data);
9411       goto unknown_stream;
9412     }
9413
9414     if (codec) {
9415       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9416           GST_TAG_VIDEO_CODEC, codec, NULL);
9417       g_free (codec);
9418       codec = NULL;
9419     }
9420
9421
9422     if (palette_data) {
9423       GstStructure *s;
9424
9425       if (stream->rgb8_palette)
9426         gst_memory_unref (stream->rgb8_palette);
9427       stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
9428           palette_data, palette_size, 0, palette_size, palette_data, g_free);
9429
9430       s = gst_caps_get_structure (stream->caps, 0);
9431
9432       /* non-raw video has a palette_data property. raw video has the palette as
9433        * an extra plane that we append to the output buffers before we push
9434        * them*/
9435       if (!gst_structure_has_name (s, "video/x-raw")) {
9436         GstBuffer *palette;
9437
9438         palette = gst_buffer_new ();
9439         gst_buffer_append_memory (palette, stream->rgb8_palette);
9440         stream->rgb8_palette = NULL;
9441
9442         gst_caps_set_simple (stream->caps, "palette_data",
9443             GST_TYPE_BUFFER, palette, NULL);
9444         gst_buffer_unref (palette);
9445       }
9446     } else if (palette_count != 0) {
9447       GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
9448           (NULL), ("Unsupported palette depth %d", depth));
9449     }
9450
9451     GST_LOG_OBJECT (qtdemux, "frame count:   %u",
9452         QT_UINT16 (stsd_data + offset + 48));
9453
9454     esds = NULL;
9455     pasp = NULL;
9456     /* pick 'the' stsd child */
9457     if (!stream->protected)
9458       mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
9459     else
9460       mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_encv);
9461
9462     if (mp4v) {
9463       esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
9464       pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
9465     }
9466
9467     if (pasp) {
9468       const guint8 *pasp_data = (const guint8 *) pasp->data;
9469
9470       stream->par_w = QT_UINT32 (pasp_data + 8);
9471       stream->par_h = QT_UINT32 (pasp_data + 12);
9472     } else {
9473       stream->par_w = 0;
9474       stream->par_h = 0;
9475     }
9476
9477     if (esds) {
9478       gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
9479     } else {
9480       switch (fourcc) {
9481         case FOURCC_H264:
9482         case FOURCC_avc1:
9483         case FOURCC_avc3:
9484         {
9485           gint len = QT_UINT32 (stsd_data) - 0x66;
9486           const guint8 *avc_data = stsd_data + 0x66;
9487
9488           /* find avcC */
9489           while (len >= 0x8) {
9490             gint size;
9491
9492             if (QT_UINT32 (avc_data) <= len)
9493               size = QT_UINT32 (avc_data) - 0x8;
9494             else
9495               size = len - 0x8;
9496
9497             if (size < 1)
9498               /* No real data, so break out */
9499               break;
9500
9501             switch (QT_FOURCC (avc_data + 0x4)) {
9502               case FOURCC_avcC:
9503               {
9504                 /* parse, if found */
9505                 GstBuffer *buf;
9506
9507                 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9508
9509                 /* First 4 bytes are the length of the atom, the next 4 bytes
9510                  * are the fourcc, the next 1 byte is the version, and the
9511                  * subsequent bytes are profile_tier_level structure like data. */
9512                 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9513                     avc_data + 8 + 1, size - 1);
9514                 buf = gst_buffer_new_and_alloc (size);
9515                 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
9516                 gst_caps_set_simple (stream->caps,
9517                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
9518                 gst_buffer_unref (buf);
9519
9520                 break;
9521               }
9522               case FOURCC_strf:
9523               {
9524                 GstBuffer *buf;
9525
9526                 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
9527
9528                 /* First 4 bytes are the length of the atom, the next 4 bytes
9529                  * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
9530                  * next 1 byte is the version, and the
9531                  * subsequent bytes are sequence parameter set like data. */
9532
9533                 size -= 40;     /* we'll be skipping BITMAPINFOHEADER */
9534                 if (size > 1) {
9535                   gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
9536                       avc_data + 8 + 40 + 1, size - 1);
9537
9538                   buf = gst_buffer_new_and_alloc (size);
9539                   gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
9540                   gst_caps_set_simple (stream->caps,
9541                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
9542                   gst_buffer_unref (buf);
9543                 }
9544                 break;
9545               }
9546               case FOURCC_btrt:
9547               {
9548                 guint avg_bitrate, max_bitrate;
9549
9550                 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
9551                 if (size < 12)
9552                   break;
9553
9554                 max_bitrate = QT_UINT32 (avc_data + 0xc);
9555                 avg_bitrate = QT_UINT32 (avc_data + 0x10);
9556
9557                 if (!max_bitrate && !avg_bitrate)
9558                   break;
9559
9560                 /* Some muxers seem to swap the average and maximum bitrates
9561                  * (I'm looking at you, YouTube), so we swap for sanity. */
9562                 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
9563                   guint temp = avg_bitrate;
9564
9565                   avg_bitrate = max_bitrate;
9566                   max_bitrate = temp;
9567                 }
9568
9569                 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
9570                   gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9571                       GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
9572                 }
9573                 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
9574                   gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9575                       GST_TAG_BITRATE, avg_bitrate, NULL);
9576                 }
9577
9578                 break;
9579               }
9580
9581               default:
9582                 break;
9583             }
9584
9585             len -= size + 8;
9586             avc_data += size + 8;
9587           }
9588
9589           break;
9590         }
9591         case FOURCC_H265:
9592         case FOURCC_hvc1:
9593         case FOURCC_hev1:
9594         {
9595           gint len = QT_UINT32 (stsd_data) - 0x66;
9596           const guint8 *hevc_data = stsd_data + 0x66;
9597
9598           /* find hevc */
9599           while (len >= 0x8) {
9600             gint size;
9601
9602             if (QT_UINT32 (hevc_data) <= len)
9603               size = QT_UINT32 (hevc_data) - 0x8;
9604             else
9605               size = len - 0x8;
9606
9607             if (size < 1)
9608               /* No real data, so break out */
9609               break;
9610
9611             switch (QT_FOURCC (hevc_data + 0x4)) {
9612               case FOURCC_hvcC:
9613               {
9614                 /* parse, if found */
9615                 GstBuffer *buf;
9616
9617                 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
9618
9619                 /* First 4 bytes are the length of the atom, the next 4 bytes
9620                  * are the fourcc, the next 1 byte is the version, and the
9621                  * subsequent bytes are sequence parameter set like data. */
9622                 gst_codec_utils_h265_caps_set_level_tier_and_profile
9623                     (stream->caps, hevc_data + 8 + 1, size - 1);
9624
9625                 buf = gst_buffer_new_and_alloc (size);
9626                 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
9627                 gst_caps_set_simple (stream->caps,
9628                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
9629                 gst_buffer_unref (buf);
9630                 break;
9631               }
9632               default:
9633                 break;
9634             }
9635             len -= size + 8;
9636             hevc_data += size + 8;
9637           }
9638           break;
9639         }
9640         case FOURCC_mp4v:
9641         case FOURCC_MP4V:
9642         case FOURCC_fmp4:
9643         case FOURCC_FMP4:
9644         {
9645           GNode *glbl;
9646
9647           GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
9648               GST_FOURCC_ARGS (fourcc));
9649
9650           /* codec data might be in glbl extension atom */
9651           glbl = mp4v ?
9652               qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
9653           if (glbl) {
9654             guint8 *data;
9655             GstBuffer *buf;
9656             gint len;
9657
9658             GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
9659             data = glbl->data;
9660             len = QT_UINT32 (data);
9661             if (len > 0x8) {
9662               len -= 0x8;
9663               buf = gst_buffer_new_and_alloc (len);
9664               gst_buffer_fill (buf, 0, data + 8, len);
9665               gst_caps_set_simple (stream->caps,
9666                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
9667               gst_buffer_unref (buf);
9668             }
9669           }
9670           break;
9671         }
9672         case FOURCC_mjp2:
9673         {
9674           /* see annex I of the jpeg2000 spec */
9675           GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
9676           const guint8 *data;
9677           const gchar *colorspace = NULL;
9678           gint ncomp = 0;
9679           guint32 ncomp_map = 0;
9680           gint32 *comp_map = NULL;
9681           guint32 nchan_def = 0;
9682           gint32 *chan_def = NULL;
9683
9684           GST_DEBUG_OBJECT (qtdemux, "found mjp2");
9685           /* some required atoms */
9686           mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
9687           if (!mjp2)
9688             break;
9689           jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
9690           if (!jp2h)
9691             break;
9692
9693           /* number of components; redundant with info in codestream, but useful
9694              to a muxer */
9695           ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
9696           if (!ihdr || QT_UINT32 (ihdr->data) != 22)
9697             break;
9698           ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
9699
9700           colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
9701           if (!colr)
9702             break;
9703           GST_DEBUG_OBJECT (qtdemux, "found colr");
9704           /* extract colour space info */
9705           if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
9706             switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
9707               case 16:
9708                 colorspace = "sRGB";
9709                 break;
9710               case 17:
9711                 colorspace = "GRAY";
9712                 break;
9713               case 18:
9714                 colorspace = "sYUV";
9715                 break;
9716               default:
9717                 colorspace = NULL;
9718                 break;
9719             }
9720           }
9721           if (!colorspace)
9722             /* colr is required, and only values 16, 17, and 18 are specified,
9723                so error if we have no colorspace */
9724             break;
9725
9726           /* extract component mapping */
9727           cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
9728           if (cmap) {
9729             guint32 cmap_len = 0;
9730             int i;
9731             cmap_len = QT_UINT32 (cmap->data);
9732             if (cmap_len >= 8) {
9733               /* normal box, subtract off header */
9734               cmap_len -= 8;
9735               /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
9736               if (cmap_len % 4 == 0) {
9737                 ncomp_map = (cmap_len / 4);
9738                 comp_map = g_new0 (gint32, ncomp_map);
9739                 for (i = 0; i < ncomp_map; i++) {
9740                   guint16 cmp;
9741                   guint8 mtyp, pcol;
9742                   cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
9743                   mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
9744                   pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
9745                   comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
9746                 }
9747               }
9748             }
9749           }
9750           /* extract channel definitions */
9751           cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
9752           if (cdef) {
9753             guint32 cdef_len = 0;
9754             int i;
9755             cdef_len = QT_UINT32 (cdef->data);
9756             if (cdef_len >= 10) {
9757               /* normal box, subtract off header and len */
9758               cdef_len -= 10;
9759               /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
9760               if (cdef_len % 6 == 0) {
9761                 nchan_def = (cdef_len / 6);
9762                 chan_def = g_new0 (gint32, nchan_def);
9763                 for (i = 0; i < nchan_def; i++)
9764                   chan_def[i] = -1;
9765                 for (i = 0; i < nchan_def; i++) {
9766                   guint16 cn, typ, asoc;
9767                   cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
9768                   typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
9769                   asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
9770                   if (cn < nchan_def) {
9771                     switch (typ) {
9772                       case 0:
9773                         chan_def[cn] = asoc;
9774                         break;
9775                       case 1:
9776                         chan_def[cn] = 0;       /* alpha */
9777                         break;
9778                       default:
9779                         chan_def[cn] = -typ;
9780                     }
9781                   }
9782                 }
9783               }
9784             }
9785           }
9786
9787           gst_caps_set_simple (stream->caps,
9788               "num-components", G_TYPE_INT, ncomp, NULL);
9789           gst_caps_set_simple (stream->caps,
9790               "colorspace", G_TYPE_STRING, colorspace, NULL);
9791
9792           if (comp_map) {
9793             GValue arr = { 0, };
9794             GValue elt = { 0, };
9795             int i;
9796             g_value_init (&arr, GST_TYPE_ARRAY);
9797             g_value_init (&elt, G_TYPE_INT);
9798             for (i = 0; i < ncomp_map; i++) {
9799               g_value_set_int (&elt, comp_map[i]);
9800               gst_value_array_append_value (&arr, &elt);
9801             }
9802             gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9803                 "component-map", &arr);
9804             g_value_unset (&elt);
9805             g_value_unset (&arr);
9806             g_free (comp_map);
9807           }
9808
9809           if (chan_def) {
9810             GValue arr = { 0, };
9811             GValue elt = { 0, };
9812             int i;
9813             g_value_init (&arr, GST_TYPE_ARRAY);
9814             g_value_init (&elt, G_TYPE_INT);
9815             for (i = 0; i < nchan_def; i++) {
9816               g_value_set_int (&elt, chan_def[i]);
9817               gst_value_array_append_value (&arr, &elt);
9818             }
9819             gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
9820                 "channel-definitions", &arr);
9821             g_value_unset (&elt);
9822             g_value_unset (&arr);
9823             g_free (chan_def);
9824           }
9825
9826           /* some optional atoms */
9827           field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
9828           prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
9829
9830           /* indicate possible fields in caps */
9831           if (field) {
9832             data = (guint8 *) field->data + 8;
9833             if (*data != 1)
9834               gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
9835                   (gint) * data, NULL);
9836           }
9837           /* add codec_data if provided */
9838           if (prefix) {
9839             GstBuffer *buf;
9840             gint len;
9841
9842             GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
9843             data = prefix->data;
9844             len = QT_UINT32 (data);
9845             if (len > 0x8) {
9846               len -= 0x8;
9847               buf = gst_buffer_new_and_alloc (len);
9848               gst_buffer_fill (buf, 0, data + 8, len);
9849               gst_caps_set_simple (stream->caps,
9850                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
9851               gst_buffer_unref (buf);
9852             }
9853           }
9854           break;
9855         }
9856         case FOURCC_SVQ3:
9857         case FOURCC_VP31:
9858         {
9859           GstBuffer *buf;
9860           GstBuffer *seqh = NULL;
9861           guint8 *gamma_data = NULL;
9862           gint len = QT_UINT32 (stsd_data);
9863
9864           qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
9865           if (gamma_data) {
9866             gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
9867                 QT_FP32 (gamma_data), NULL);
9868           }
9869           if (seqh) {
9870             /* sorry for the bad name, but we don't know what this is, other
9871              * than its own fourcc */
9872             gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
9873                 NULL);
9874           }
9875
9876           GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
9877           buf = gst_buffer_new_and_alloc (len);
9878           gst_buffer_fill (buf, 0, stsd_data, len);
9879           gst_caps_set_simple (stream->caps,
9880               "codec_data", GST_TYPE_BUFFER, buf, NULL);
9881           gst_buffer_unref (buf);
9882           break;
9883         }
9884         case FOURCC_rle_:
9885         case FOURCC_WRLE:
9886         {
9887           gst_caps_set_simple (stream->caps,
9888               "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
9889           break;
9890         }
9891         case FOURCC_XiTh:
9892         {
9893           GNode *xith, *xdxt;
9894
9895           GST_DEBUG_OBJECT (qtdemux, "found XiTh");
9896           xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
9897           if (!xith)
9898             break;
9899
9900           xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
9901           if (!xdxt)
9902             break;
9903
9904           GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
9905           /* collect the headers and store them in a stream list so that we can
9906            * send them out first */
9907           qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
9908           break;
9909         }
9910         case FOURCC_ovc1:
9911         {
9912           GNode *ovc1;
9913           guint8 *ovc1_data;
9914           guint ovc1_len;
9915           GstBuffer *buf;
9916
9917           GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
9918           ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
9919           if (!ovc1)
9920             break;
9921           ovc1_data = ovc1->data;
9922           ovc1_len = QT_UINT32 (ovc1_data);
9923           if (ovc1_len <= 198) {
9924             GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
9925             break;
9926           }
9927           buf = gst_buffer_new_and_alloc (ovc1_len - 198);
9928           gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
9929           gst_caps_set_simple (stream->caps,
9930               "codec_data", GST_TYPE_BUFFER, buf, NULL);
9931           gst_buffer_unref (buf);
9932           break;
9933         }
9934         case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
9935         {
9936           gint len = QT_UINT32 (stsd_data) - 0x66;
9937           const guint8 *vc1_data = stsd_data + 0x66;
9938
9939           /* find dvc1 */
9940           while (len >= 8) {
9941             gint size;
9942
9943             if (QT_UINT32 (vc1_data) <= len)
9944               size = QT_UINT32 (vc1_data) - 8;
9945             else
9946               size = len - 8;
9947
9948             if (size < 1)
9949               /* No real data, so break out */
9950               break;
9951
9952             switch (QT_FOURCC (vc1_data + 0x4)) {
9953               case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
9954               {
9955                 GstBuffer *buf;
9956
9957                 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
9958                 buf = gst_buffer_new_and_alloc (size);
9959                 gst_buffer_fill (buf, 0, vc1_data + 8, size);
9960                 gst_caps_set_simple (stream->caps,
9961                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
9962                 gst_buffer_unref (buf);
9963                 break;
9964               }
9965               default:
9966                 break;
9967             }
9968             len -= size + 8;
9969             vc1_data += size + 8;
9970           }
9971           break;
9972         }
9973         default:
9974           break;
9975       }
9976     }
9977
9978     GST_INFO_OBJECT (qtdemux,
9979         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9980         GST_FOURCC_ARGS (fourcc), stream->caps);
9981
9982   } else if (stream->subtype == FOURCC_soun) {
9983     int version, samplesize;
9984     guint16 compression_id;
9985     gboolean amrwb = FALSE;
9986
9987     offset = 32;
9988     /* sample description entry (16) + sound sample description v0 (20) */
9989     if (len < 36)
9990       goto corrupt_file;
9991
9992     version = QT_UINT32 (stsd_data + offset);
9993     stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
9994     samplesize = QT_UINT16 (stsd_data + offset + 10);
9995     compression_id = QT_UINT16 (stsd_data + offset + 12);
9996     stream->rate = QT_FP32 (stsd_data + offset + 16);
9997
9998     GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
9999     GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
10000         QT_UINT32 (stsd_data + offset + 4));
10001     GST_LOG_OBJECT (qtdemux, "n_channels:       %d", stream->n_channels);
10002     GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
10003     GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
10004     GST_LOG_OBJECT (qtdemux, "packet size:      %d",
10005         QT_UINT16 (stsd_data + offset + 14));
10006     GST_LOG_OBJECT (qtdemux, "sample rate:      %g", stream->rate);
10007
10008     if (compression_id == 0xfffe)
10009       stream->sampled = TRUE;
10010
10011     /* first assume uncompressed audio */
10012     stream->bytes_per_sample = samplesize / 8;
10013     stream->samples_per_frame = stream->n_channels;
10014     stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
10015     stream->samples_per_packet = stream->samples_per_frame;
10016     stream->bytes_per_packet = stream->bytes_per_sample;
10017
10018     offset = 52;
10019     switch (fourcc) {
10020         /* Yes, these have to be hard-coded */
10021       case FOURCC_MAC6:
10022       {
10023         stream->samples_per_packet = 6;
10024         stream->bytes_per_packet = 1;
10025         stream->bytes_per_frame = 1 * stream->n_channels;
10026         stream->bytes_per_sample = 1;
10027         stream->samples_per_frame = 6 * stream->n_channels;
10028         break;
10029       }
10030       case FOURCC_MAC3:
10031       {
10032         stream->samples_per_packet = 3;
10033         stream->bytes_per_packet = 1;
10034         stream->bytes_per_frame = 1 * stream->n_channels;
10035         stream->bytes_per_sample = 1;
10036         stream->samples_per_frame = 3 * stream->n_channels;
10037         break;
10038       }
10039       case FOURCC_ima4:
10040       {
10041         stream->samples_per_packet = 64;
10042         stream->bytes_per_packet = 34;
10043         stream->bytes_per_frame = 34 * stream->n_channels;
10044         stream->bytes_per_sample = 2;
10045         stream->samples_per_frame = 64 * stream->n_channels;
10046         break;
10047       }
10048       case FOURCC_ulaw:
10049       case FOURCC_alaw:
10050       {
10051         stream->samples_per_packet = 1;
10052         stream->bytes_per_packet = 1;
10053         stream->bytes_per_frame = 1 * stream->n_channels;
10054         stream->bytes_per_sample = 1;
10055         stream->samples_per_frame = 1 * stream->n_channels;
10056         break;
10057       }
10058       case FOURCC_agsm:
10059       {
10060         stream->samples_per_packet = 160;
10061         stream->bytes_per_packet = 33;
10062         stream->bytes_per_frame = 33 * stream->n_channels;
10063         stream->bytes_per_sample = 2;
10064         stream->samples_per_frame = 160 * stream->n_channels;
10065         break;
10066       }
10067       default:
10068         break;
10069     }
10070
10071     if (version == 0x00010000) {
10072       /* sample description entry (16) + sound sample description v1 (20+16) */
10073       if (len < 52)
10074         goto corrupt_file;
10075
10076       switch (fourcc) {
10077         case FOURCC_twos:
10078         case FOURCC_sowt:
10079         case FOURCC_raw_:
10080           break;
10081         default:
10082         {
10083           /* only parse extra decoding config for non-pcm audio */
10084           stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
10085           stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
10086           stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
10087           stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
10088
10089           GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
10090               stream->samples_per_packet);
10091           GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
10092               stream->bytes_per_packet);
10093           GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
10094               stream->bytes_per_frame);
10095           GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
10096               stream->bytes_per_sample);
10097
10098           if (!stream->sampled && stream->bytes_per_packet) {
10099             stream->samples_per_frame = (stream->bytes_per_frame /
10100                 stream->bytes_per_packet) * stream->samples_per_packet;
10101             GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
10102                 stream->samples_per_frame);
10103           }
10104           break;
10105         }
10106       }
10107     } else if (version == 0x00020000) {
10108       union
10109       {
10110         gdouble fp;
10111         guint64 val;
10112       } qtfp;
10113
10114       /* sample description entry (16) + sound sample description v2 (56) */
10115       if (len < 72)
10116         goto corrupt_file;
10117
10118       qtfp.val = QT_UINT64 (stsd_data + offset + 4);
10119       stream->rate = qtfp.fp;
10120       stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
10121
10122       GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
10123       GST_LOG_OBJECT (qtdemux, "sample rate:        %g", stream->rate);
10124       GST_LOG_OBJECT (qtdemux, "n_channels:         %d", stream->n_channels);
10125       GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
10126           QT_UINT32 (stsd_data + offset + 20));
10127       GST_LOG_OBJECT (qtdemux, "format flags:       %X",
10128           QT_UINT32 (stsd_data + offset + 24));
10129       GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
10130           QT_UINT32 (stsd_data + offset + 28));
10131       GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
10132           QT_UINT32 (stsd_data + offset + 32));
10133     } else if (version != 0x00000) {
10134       GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
10135     }
10136
10137     if (stream->caps)
10138       gst_caps_unref (stream->caps);
10139
10140     stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
10141         stsd_data + 32, len - 16, &codec);
10142
10143     switch (fourcc) {
10144       case FOURCC_in24:
10145       {
10146         GNode *enda;
10147         GNode *in24;
10148
10149         in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
10150
10151         enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
10152         if (!enda) {
10153           wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
10154           if (wave)
10155             enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
10156         }
10157         if (enda) {
10158           int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
10159           gst_caps_set_simple (stream->caps,
10160               "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
10161         }
10162         break;
10163       }
10164       case FOURCC_owma:
10165       {
10166         GNode *owma;
10167         const guint8 *owma_data;
10168         const gchar *codec_name = NULL;
10169         guint owma_len;
10170         GstBuffer *buf;
10171         gint version = 1;
10172         /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10173         /* FIXME this should also be gst_riff_strf_auds,
10174          * but the latter one is actually missing bits-per-sample :( */
10175         typedef struct
10176         {
10177           gint16 wFormatTag;
10178           gint16 nChannels;
10179           gint32 nSamplesPerSec;
10180           gint32 nAvgBytesPerSec;
10181           gint16 nBlockAlign;
10182           gint16 wBitsPerSample;
10183           gint16 cbSize;
10184         } WAVEFORMATEX;
10185         WAVEFORMATEX *wfex;
10186
10187         GST_DEBUG_OBJECT (qtdemux, "parse owma");
10188         owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
10189         if (!owma)
10190           break;
10191         owma_data = owma->data;
10192         owma_len = QT_UINT32 (owma_data);
10193         if (owma_len <= 54) {
10194           GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
10195           break;
10196         }
10197         wfex = (WAVEFORMATEX *) (owma_data + 36);
10198         buf = gst_buffer_new_and_alloc (owma_len - 54);
10199         gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
10200         if (wfex->wFormatTag == 0x0161) {
10201           codec_name = "Windows Media Audio";
10202           version = 2;
10203         } else if (wfex->wFormatTag == 0x0162) {
10204           codec_name = "Windows Media Audio 9 Pro";
10205           version = 3;
10206         } else if (wfex->wFormatTag == 0x0163) {
10207           codec_name = "Windows Media Audio 9 Lossless";
10208           /* is that correct? gstffmpegcodecmap.c is missing it, but
10209            * fluendo codec seems to support it */
10210           version = 4;
10211         }
10212
10213         gst_caps_set_simple (stream->caps,
10214             "codec_data", GST_TYPE_BUFFER, buf,
10215             "wmaversion", G_TYPE_INT, version,
10216             "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
10217             "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
10218             "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10219             "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
10220             NULL);
10221         gst_buffer_unref (buf);
10222
10223         if (codec_name) {
10224           g_free (codec);
10225           codec = g_strdup (codec_name);
10226         }
10227         break;
10228       }
10229       case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
10230       {
10231         gint len = QT_UINT32 (stsd_data) - offset;
10232         const guint8 *wfex_data = stsd_data + offset;
10233         const gchar *codec_name = NULL;
10234         gint version = 1;
10235         /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
10236         /* FIXME this should also be gst_riff_strf_auds,
10237          * but the latter one is actually missing bits-per-sample :( */
10238         typedef struct
10239         {
10240           gint16 wFormatTag;
10241           gint16 nChannels;
10242           gint32 nSamplesPerSec;
10243           gint32 nAvgBytesPerSec;
10244           gint16 nBlockAlign;
10245           gint16 wBitsPerSample;
10246           gint16 cbSize;
10247         } WAVEFORMATEX;
10248         WAVEFORMATEX wfex;
10249
10250         /* FIXME: unify with similar wavformatex parsing code above */
10251         GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
10252
10253         /* find wfex */
10254         while (len >= 8) {
10255           gint size;
10256
10257           if (QT_UINT32 (wfex_data) <= len)
10258             size = QT_UINT32 (wfex_data) - 8;
10259           else
10260             size = len - 8;
10261
10262           if (size < 1)
10263             /* No real data, so break out */
10264             break;
10265
10266           switch (QT_FOURCC (wfex_data + 4)) {
10267             case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
10268             {
10269               GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
10270
10271               if (size < 8 + 18)
10272                 break;
10273
10274               wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
10275               wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
10276               wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
10277               wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
10278               wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
10279               wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
10280               wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
10281
10282               GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
10283               GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
10284                   "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
10285                   "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
10286                   wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
10287                   wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
10288
10289               if (wfex.wFormatTag == 0x0161) {
10290                 codec_name = "Windows Media Audio";
10291                 version = 2;
10292               } else if (wfex.wFormatTag == 0x0162) {
10293                 codec_name = "Windows Media Audio 9 Pro";
10294                 version = 3;
10295               } else if (wfex.wFormatTag == 0x0163) {
10296                 codec_name = "Windows Media Audio 9 Lossless";
10297                 /* is that correct? gstffmpegcodecmap.c is missing it, but
10298                  * fluendo codec seems to support it */
10299                 version = 4;
10300               }
10301
10302               gst_caps_set_simple (stream->caps,
10303                   "wmaversion", G_TYPE_INT, version,
10304                   "block_align", G_TYPE_INT, wfex.nBlockAlign,
10305                   "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
10306                   "width", G_TYPE_INT, wfex.wBitsPerSample,
10307                   "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
10308
10309               if (size > wfex.cbSize) {
10310                 GstBuffer *buf;
10311
10312                 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
10313                 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
10314                     size - wfex.cbSize);
10315                 gst_caps_set_simple (stream->caps,
10316                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
10317                 gst_buffer_unref (buf);
10318               } else {
10319                 GST_WARNING_OBJECT (qtdemux, "no codec data");
10320               }
10321
10322               if (codec_name) {
10323                 g_free (codec);
10324                 codec = g_strdup (codec_name);
10325               }
10326               break;
10327             }
10328             default:
10329               break;
10330           }
10331           len -= size + 8;
10332           wfex_data += size + 8;
10333         }
10334         break;
10335       }
10336       default:
10337         break;
10338     }
10339
10340     if (codec) {
10341       GstStructure *s;
10342       gint bitrate = 0;
10343
10344       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10345           GST_TAG_AUDIO_CODEC, codec, NULL);
10346       g_free (codec);
10347       codec = NULL;
10348
10349       /* some bitrate info may have ended up in caps */
10350       s = gst_caps_get_structure (stream->caps, 0);
10351       gst_structure_get_int (s, "bitrate", &bitrate);
10352       if (bitrate > 0)
10353         gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10354             GST_TAG_BITRATE, bitrate, NULL);
10355     }
10356
10357     if (stream->protected && fourcc == FOURCC_mp4a)
10358       mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_enca);
10359     else
10360       mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
10361
10362     wave = NULL;
10363     esds = NULL;
10364     if (mp4a) {
10365       wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
10366       if (wave)
10367         esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
10368       if (!esds)
10369         esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
10370     }
10371
10372
10373     /* If the fourcc's bottom 16 bits gives 'sm', then the top
10374        16 bits is a byte-swapped wave-style codec identifier,
10375        and we can find a WAVE header internally to a 'wave' atom here.
10376        This can more clearly be thought of as 'ms' as the top 16 bits, and a
10377        codec id as the bottom 16 bits - but byte-swapped to store in QT (which
10378        is big-endian).
10379      */
10380     if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
10381       if (len < offset + 20) {
10382         GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
10383       } else {
10384         guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
10385         const guint8 *data = stsd_data + offset + 16;
10386         GNode *wavenode;
10387         GNode *waveheadernode;
10388
10389         wavenode = g_node_new ((guint8 *) data);
10390         if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
10391           const guint8 *waveheader;
10392           guint32 headerlen;
10393
10394           waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
10395           if (waveheadernode) {
10396             waveheader = (const guint8 *) waveheadernode->data;
10397             headerlen = QT_UINT32 (waveheader);
10398
10399             if (headerlen > 8) {
10400               gst_riff_strf_auds *header = NULL;
10401               GstBuffer *headerbuf;
10402               GstBuffer *extra;
10403
10404               waveheader += 8;
10405               headerlen -= 8;
10406
10407               headerbuf = gst_buffer_new_and_alloc (headerlen);
10408               gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
10409
10410               if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
10411                       headerbuf, &header, &extra)) {
10412                 gst_caps_unref (stream->caps);
10413                 /* FIXME: Need to do something with the channel reorder map */
10414                 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
10415                     header, extra, NULL, NULL, NULL);
10416
10417                 if (extra)
10418                   gst_buffer_unref (extra);
10419                 g_free (header);
10420               }
10421             }
10422           } else
10423             GST_DEBUG ("Didn't find waveheadernode for this codec");
10424         }
10425         g_node_destroy (wavenode);
10426       }
10427     } else if (esds) {
10428       gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10429     } else {
10430       switch (fourcc) {
10431 #if 0
10432           /* FIXME: what is in the chunk? */
10433         case FOURCC_QDMC:
10434         {
10435           gint len = QT_UINT32 (stsd_data);
10436
10437           /* seems to be always = 116 = 0x74 */
10438           break;
10439         }
10440 #endif
10441         case FOURCC_QDM2:
10442         {
10443           gint len = QT_UINT32 (stsd_data);
10444
10445           if (len > 0x4C) {
10446             GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
10447
10448             gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
10449             gst_caps_set_simple (stream->caps,
10450                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10451             gst_buffer_unref (buf);
10452           }
10453           gst_caps_set_simple (stream->caps,
10454               "samplesize", G_TYPE_INT, samplesize, NULL);
10455           break;
10456         }
10457         case FOURCC_alac:
10458         {
10459           GNode *alac, *wave = NULL;
10460
10461           /* apparently, m4a has this atom appended directly in the stsd entry,
10462            * while mov has it in a wave atom */
10463           alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
10464           if (alac) {
10465             /* alac now refers to stsd entry atom */
10466             wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
10467             if (wave)
10468               alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
10469             else
10470               alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
10471           }
10472           if (alac) {
10473             const guint8 *alac_data = alac->data;
10474             gint len = QT_UINT32 (alac->data);
10475             GstBuffer *buf;
10476
10477             if (len < 36) {
10478               GST_DEBUG_OBJECT (qtdemux,
10479                   "discarding alac atom with unexpected len %d", len);
10480             } else {
10481               /* codec-data contains alac atom size and prefix,
10482                * ffmpeg likes it that way, not quite gst-ish though ...*/
10483               buf = gst_buffer_new_and_alloc (len);
10484               gst_buffer_fill (buf, 0, alac->data, len);
10485               gst_caps_set_simple (stream->caps,
10486                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
10487               gst_buffer_unref (buf);
10488
10489               stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
10490               stream->n_channels = QT_UINT8 (alac_data + 21);
10491               stream->rate = QT_UINT32 (alac_data + 32);
10492             }
10493           }
10494           gst_caps_set_simple (stream->caps,
10495               "samplesize", G_TYPE_INT, samplesize, NULL);
10496           break;
10497         }
10498         case FOURCC_sawb:
10499           /* Fallthrough! */
10500           amrwb = TRUE;
10501         case FOURCC_samr:
10502         {
10503           gint len = QT_UINT32 (stsd_data);
10504
10505           if (len > 0x34) {
10506             GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
10507             guint bitrate;
10508
10509             gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
10510
10511             /* If we have enough data, let's try to get the 'damr' atom. See
10512              * the 3GPP container spec (26.244) for more details. */
10513             if ((len - 0x34) > 8 &&
10514                 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
10515               gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10516                   GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
10517             }
10518
10519             gst_caps_set_simple (stream->caps,
10520                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
10521             gst_buffer_unref (buf);
10522           }
10523           break;
10524         }
10525         case FOURCC_mp4a:
10526         {
10527           /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
10528           gint len = QT_UINT32 (stsd_data);
10529
10530           if (len >= 50) {
10531             guint16 sound_version = QT_UINT16 (stsd_data + 32);
10532
10533             if (sound_version == 1) {
10534               guint16 channels = QT_UINT16 (stsd_data + 40);
10535               guint32 time_scale = QT_UINT32 (stsd_data + 46);
10536               guint8 codec_data[2];
10537               GstBuffer *buf;
10538               gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
10539
10540               gint sample_rate_index =
10541                   gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
10542
10543               /* build AAC codec data */
10544               codec_data[0] = profile << 3;
10545               codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
10546               codec_data[1] = (sample_rate_index & 0x01) << 7;
10547               codec_data[1] |= (channels & 0xF) << 3;
10548
10549               buf = gst_buffer_new_and_alloc (2);
10550               gst_buffer_fill (buf, 0, codec_data, 2);
10551               gst_caps_set_simple (stream->caps,
10552                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
10553               gst_buffer_unref (buf);
10554             }
10555           }
10556           break;
10557         }
10558         default:
10559           GST_INFO_OBJECT (qtdemux,
10560               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10561           break;
10562       }
10563     }
10564     GST_INFO_OBJECT (qtdemux,
10565         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10566         GST_FOURCC_ARGS (fourcc), stream->caps);
10567
10568   } else if (stream->subtype == FOURCC_strm) {
10569     if (fourcc == FOURCC_rtsp) {
10570       stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
10571     } else {
10572       GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
10573           GST_FOURCC_ARGS (fourcc));
10574       goto unknown_stream;
10575     }
10576     stream->sampled = TRUE;
10577   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
10578       || stream->subtype == FOURCC_sbtl || stream->subtype == FOURCC_subt) {
10579
10580     stream->sampled = TRUE;
10581     stream->sparse = TRUE;
10582
10583     stream->caps =
10584         qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10585     if (codec) {
10586       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10587           GST_TAG_SUBTITLE_CODEC, codec, NULL);
10588       g_free (codec);
10589       codec = NULL;
10590     }
10591
10592     /* hunt for sort-of codec data */
10593     switch (fourcc) {
10594       case FOURCC_mp4s:
10595       {
10596         GNode *mp4s = NULL;
10597         GNode *esds = NULL;
10598
10599         /* look for palette in a stsd->mp4s->esds sub-atom */
10600         mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
10601         if (mp4s)
10602           esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
10603         if (esds == NULL) {
10604           /* Invalid STSD */
10605           GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
10606           break;
10607         }
10608
10609         gst_qtdemux_handle_esds (qtdemux, stream, esds, stream->pending_tags);
10610         break;
10611       }
10612       default:
10613         GST_INFO_OBJECT (qtdemux,
10614             "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
10615         break;
10616     }
10617     GST_INFO_OBJECT (qtdemux,
10618         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
10619         GST_FOURCC_ARGS (fourcc), stream->caps);
10620   } else {
10621     /* everything in 1 sample */
10622     stream->sampled = TRUE;
10623
10624     stream->caps =
10625         qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
10626
10627     if (stream->caps == NULL)
10628       goto unknown_stream;
10629
10630     if (codec) {
10631       gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10632           GST_TAG_SUBTITLE_CODEC, codec, NULL);
10633       g_free (codec);
10634       codec = NULL;
10635     }
10636   }
10637
10638   /* promote to sampled format */
10639   if (stream->fourcc == FOURCC_samr) {
10640     /* force mono 8000 Hz for AMR */
10641     stream->sampled = TRUE;
10642     stream->n_channels = 1;
10643     stream->rate = 8000;
10644   } else if (stream->fourcc == FOURCC_sawb) {
10645     /* force mono 16000 Hz for AMR-WB */
10646     stream->sampled = TRUE;
10647     stream->n_channels = 1;
10648     stream->rate = 16000;
10649   } else if (stream->fourcc == FOURCC_mp4a) {
10650     stream->sampled = TRUE;
10651   }
10652
10653   /* collect sample information */
10654   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
10655     goto samples_failed;
10656
10657   if (qtdemux->fragmented) {
10658     guint32 dummy;
10659     guint64 offset;
10660
10661     /* need all moov samples as basis; probably not many if any at all */
10662     /* prevent moof parsing taking of at this time */
10663     offset = qtdemux->moof_offset;
10664     qtdemux->moof_offset = 0;
10665     if (stream->n_samples &&
10666         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
10667       qtdemux->moof_offset = offset;
10668       goto samples_failed;
10669     }
10670     qtdemux->moof_offset = 0;
10671     /* movie duration more reliable in this case (e.g. mehd) */
10672     if (qtdemux->segment.duration &&
10673         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
10674       stream->duration =
10675           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
10676     /* need defaults for fragments */
10677     qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
10678   }
10679
10680   /* configure segments */
10681   if (!qtdemux_parse_segments (qtdemux, stream, trak))
10682     goto segments_failed;
10683
10684   /* add some language tag, if useful */
10685   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
10686       strcmp (stream->lang_id, "und")) {
10687     const gchar *lang_code;
10688
10689     /* convert ISO 639-2 code to ISO 639-1 */
10690     lang_code = gst_tag_get_language_code (stream->lang_id);
10691     gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10692         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
10693   }
10694
10695   /* Check for UDTA tags */
10696   if ((udta = qtdemux_tree_get_child_by_type (trak, FOURCC_udta))) {
10697     qtdemux_parse_udta (qtdemux, stream->pending_tags, udta);
10698   }
10699
10700   /* now we are ready to add the stream */
10701   if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
10702     goto too_many_streams;
10703
10704   if (!qtdemux->got_moov) {
10705     qtdemux->streams[qtdemux->n_streams] = stream;
10706     qtdemux->n_streams++;
10707     GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
10708   }
10709
10710   return TRUE;
10711
10712 /* ERRORS */
10713 skip_track:
10714   {
10715     GST_INFO_OBJECT (qtdemux, "skip disabled track");
10716     if (new_stream)
10717       gst_qtdemux_stream_free (qtdemux, stream);
10718     return TRUE;
10719   }
10720 corrupt_file:
10721   {
10722     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
10723         (_("This file is corrupt and cannot be played.")), (NULL));
10724     if (new_stream)
10725       gst_qtdemux_stream_free (qtdemux, stream);
10726     return FALSE;
10727   }
10728 error_encrypted:
10729   {
10730     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
10731     if (new_stream)
10732       gst_qtdemux_stream_free (qtdemux, stream);
10733     return FALSE;
10734   }
10735 samples_failed:
10736 segments_failed:
10737   {
10738     /* we posted an error already */
10739     /* free stbl sub-atoms */
10740     gst_qtdemux_stbl_free (stream);
10741     if (new_stream)
10742       gst_qtdemux_stream_free (qtdemux, stream);
10743     return FALSE;
10744   }
10745 existing_stream:
10746   {
10747     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
10748         track_id);
10749     if (new_stream)
10750       gst_qtdemux_stream_free (qtdemux, stream);
10751     return TRUE;
10752   }
10753 unknown_stream:
10754   {
10755     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
10756         GST_FOURCC_ARGS (stream->subtype));
10757     if (new_stream)
10758       gst_qtdemux_stream_free (qtdemux, stream);
10759     return TRUE;
10760   }
10761 too_many_streams:
10762   {
10763     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
10764         (_("This file contains too many streams. Only playing first %d"),
10765             GST_QTDEMUX_MAX_STREAMS), (NULL));
10766     return TRUE;
10767   }
10768 }
10769
10770 /* If we can estimate the overall bitrate, and don't have information about the
10771  * stream bitrate for exactly one stream, this guesses the stream bitrate as
10772  * the overall bitrate minus the sum of the bitrates of all other streams. This
10773  * should be useful for the common case where we have one audio and one video
10774  * stream and can estimate the bitrate of one, but not the other. */
10775 static void
10776 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
10777 {
10778   QtDemuxStream *stream = NULL;
10779   gint64 size, sys_bitrate, sum_bitrate = 0;
10780   GstClockTime duration;
10781   gint i;
10782   guint bitrate;
10783
10784   if (qtdemux->fragmented)
10785     return;
10786
10787   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
10788
10789   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
10790       || size <= 0) {
10791     GST_DEBUG_OBJECT (qtdemux,
10792         "Size in bytes of the stream not known - bailing");
10793     return;
10794   }
10795
10796   /* Subtract the header size */
10797   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
10798       size, qtdemux->header_size);
10799
10800   if (size < qtdemux->header_size)
10801     return;
10802
10803   size = size - qtdemux->header_size;
10804
10805   if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
10806       duration == GST_CLOCK_TIME_NONE) {
10807     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
10808     return;
10809   }
10810
10811   for (i = 0; i < qtdemux->n_streams; i++) {
10812     switch (qtdemux->streams[i]->subtype) {
10813       case FOURCC_soun:
10814       case FOURCC_vide:
10815         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
10816             qtdemux->streams[i]->caps);
10817         /* retrieve bitrate, prefer avg then max */
10818         bitrate = 0;
10819         if (qtdemux->streams[i]->pending_tags) {
10820           gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10821               GST_TAG_MAXIMUM_BITRATE, &bitrate);
10822           GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
10823           gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10824               GST_TAG_NOMINAL_BITRATE, &bitrate);
10825           GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
10826           gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
10827               GST_TAG_BITRATE, &bitrate);
10828           GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
10829         }
10830         if (bitrate)
10831           sum_bitrate += bitrate;
10832         else {
10833           if (stream) {
10834             GST_DEBUG_OBJECT (qtdemux,
10835                 ">1 stream with unknown bitrate - bailing");
10836             return;
10837           } else
10838             stream = qtdemux->streams[i];
10839         }
10840
10841       default:
10842         /* For other subtypes, we assume no significant impact on bitrate */
10843         break;
10844     }
10845   }
10846
10847   if (!stream) {
10848     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
10849     return;
10850   }
10851
10852   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
10853
10854   if (sys_bitrate < sum_bitrate) {
10855     /* This can happen, since sum_bitrate might be derived from maximum
10856      * bitrates and not average bitrates */
10857     GST_DEBUG_OBJECT (qtdemux,
10858         "System bitrate less than sum bitrate - bailing");
10859     return;
10860   }
10861
10862   bitrate = sys_bitrate - sum_bitrate;
10863   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
10864       ", Stream bitrate = %u", sys_bitrate, bitrate);
10865
10866   if (!stream->pending_tags)
10867     stream->pending_tags = gst_tag_list_new_empty ();
10868
10869   gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
10870       GST_TAG_BITRATE, bitrate, NULL);
10871 }
10872
10873 static GstFlowReturn
10874 qtdemux_prepare_streams (GstQTDemux * qtdemux)
10875 {
10876   gint i;
10877   GstFlowReturn ret = GST_FLOW_OK;
10878
10879   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
10880
10881   for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10882     QtDemuxStream *stream = qtdemux->streams[i];
10883     guint32 sample_num = 0;
10884
10885     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10886         i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10887
10888     if (qtdemux->fragmented) {
10889       /* need all moov samples first */
10890       GST_OBJECT_LOCK (qtdemux);
10891       while (stream->n_samples == 0)
10892         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
10893           break;
10894       GST_OBJECT_UNLOCK (qtdemux);
10895     } else {
10896       /* discard any stray moof */
10897       qtdemux->moof_offset = 0;
10898     }
10899
10900     /* prepare braking */
10901     if (ret != GST_FLOW_ERROR)
10902       ret = GST_FLOW_OK;
10903
10904     /* in pull mode, we should have parsed some sample info by now;
10905      * and quite some code will not handle no samples.
10906      * in push mode, we'll just have to deal with it */
10907     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
10908       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
10909       gst_qtdemux_remove_stream (qtdemux, i);
10910       i--;
10911       continue;
10912     }
10913
10914     /* parse the initial sample for use in setting the frame rate cap */
10915     while (sample_num == 0 && sample_num < stream->n_samples) {
10916       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
10917         break;
10918       ++sample_num;
10919     }
10920     if (stream->n_samples > 0 && stream->stbl_index >= 0) {
10921       stream->first_duration = stream->samples[0].duration;
10922       GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
10923           stream->track_id, stream->first_duration);
10924     }
10925   }
10926
10927   return ret;
10928 }
10929
10930 static GstFlowReturn
10931 qtdemux_expose_streams (GstQTDemux * qtdemux)
10932 {
10933   gint i;
10934   GstFlowReturn ret = GST_FLOW_OK;
10935   GSList *oldpads = NULL;
10936   GSList *iter;
10937
10938   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
10939
10940   for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
10941     QtDemuxStream *stream = qtdemux->streams[i];
10942     GstPad *oldpad = stream->pad;
10943     GstTagList *list;
10944
10945     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
10946         i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
10947
10948     if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
10949         stream->track_id == qtdemux->chapters_track_id) {
10950       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
10951          so that it doesn't look like a subtitle track */
10952       gst_qtdemux_remove_stream (qtdemux, i);
10953       i--;
10954       continue;
10955     }
10956
10957     /* now we have all info and can expose */
10958     list = stream->pending_tags;
10959     stream->pending_tags = NULL;
10960     if (oldpad)
10961       oldpads = g_slist_prepend (oldpads, oldpad);
10962     gst_qtdemux_add_stream (qtdemux, stream, list);
10963   }
10964
10965   gst_qtdemux_guess_bitrate (qtdemux);
10966
10967   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
10968
10969   for (iter = oldpads; iter; iter = g_slist_next (iter)) {
10970     GstPad *oldpad = iter->data;
10971
10972     gst_pad_push_event (oldpad, gst_event_new_eos ());
10973     gst_pad_set_active (oldpad, FALSE);
10974     gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
10975     gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
10976     gst_object_unref (oldpad);
10977   }
10978
10979   /* check if we should post a redirect in case there is a single trak
10980    * and it is a redirecting trak */
10981   if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
10982     GstMessage *m;
10983
10984     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
10985         "an external content");
10986     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
10987         gst_structure_new ("redirect",
10988             "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
10989             NULL));
10990     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
10991     qtdemux->posted_redirect = TRUE;
10992   }
10993
10994   for (i = 0; i < qtdemux->n_streams; i++) {
10995     QtDemuxStream *stream = qtdemux->streams[i];
10996
10997     qtdemux_do_allocation (qtdemux, stream);
10998   }
10999
11000   qtdemux->exposed = TRUE;
11001   return ret;
11002 }
11003
11004 /* check if major or compatible brand is 3GP */
11005 static inline gboolean
11006 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
11007 {
11008   if (major) {
11009     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11010         GST_MAKE_FOURCC ('3', 'g', 0, 0));
11011   } else if (qtdemux->comp_brands != NULL) {
11012     GstMapInfo map;
11013     guint8 *data;
11014     gsize size;
11015     gboolean res = FALSE;
11016
11017     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
11018     data = map.data;
11019     size = map.size;
11020     while (size >= 4) {
11021       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
11022           GST_MAKE_FOURCC ('3', 'g', 0, 0));
11023       data += 4;
11024       size -= 4;
11025     }
11026     gst_buffer_unmap (qtdemux->comp_brands, &map);
11027     return res;
11028   } else {
11029     return FALSE;
11030   }
11031 }
11032
11033 /* check if tag is a spec'ed 3GP tag keyword storing a string */
11034 static inline gboolean
11035 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
11036 {
11037   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
11038       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
11039       || fourcc == FOURCC_albm;
11040 }
11041
11042 static void
11043 qtdemux_tag_add_location (GstQTDemux * qtdemux, GstTagList * taglist,
11044     const char *tag, const char *dummy, GNode * node)
11045 {
11046   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11047   int offset;
11048   char *name;
11049   gchar *data;
11050   gdouble longitude, latitude, altitude;
11051   gint len;
11052
11053   len = QT_UINT32 (node->data);
11054   if (len <= 14)
11055     goto short_read;
11056
11057   data = node->data;
11058   offset = 14;
11059
11060   /* TODO: language code skipped */
11061
11062   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
11063
11064   if (!name) {
11065     /* do not alarm in trivial case, but bail out otherwise */
11066     if (*(data + offset) != 0) {
11067       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
11068           "giving up", tag);
11069     }
11070   } else {
11071     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11072         GST_TAG_GEO_LOCATION_NAME, name, NULL);
11073     offset += strlen (name);
11074     g_free (name);
11075   }
11076
11077   if (len < offset + 2 + 4 + 4 + 4)
11078     goto short_read;
11079
11080   /* +1 +1 = skip null-terminator and location role byte */
11081   offset += 1 + 1;
11082   /* table in spec says unsigned, semantics say negative has meaning ... */
11083   longitude = QT_SFP32 (data + offset);
11084
11085   offset += 4;
11086   latitude = QT_SFP32 (data + offset);
11087
11088   offset += 4;
11089   altitude = QT_SFP32 (data + offset);
11090
11091   /* one invalid means all are invalid */
11092   if (longitude >= -180.0 && longitude <= 180.0 &&
11093       latitude >= -90.0 && latitude <= 90.0) {
11094     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE,
11095         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
11096         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
11097         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
11098   }
11099
11100   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
11101
11102   return;
11103
11104   /* ERRORS */
11105 short_read:
11106   {
11107     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
11108     return;
11109   }
11110 }
11111
11112
11113 static void
11114 qtdemux_tag_add_year (GstQTDemux * qtdemux, GstTagList * taglist,
11115     const char *tag, const char *dummy, GNode * node)
11116 {
11117   guint16 y;
11118   GDate *date;
11119   gint len;
11120
11121   len = QT_UINT32 (node->data);
11122   if (len < 14)
11123     return;
11124
11125   y = QT_UINT16 ((guint8 *) node->data + 12);
11126   if (y == 0) {
11127     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
11128     return;
11129   }
11130   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
11131
11132   date = g_date_new_dmy (1, 1, y);
11133   gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11134   g_date_free (date);
11135 }
11136
11137 static void
11138 qtdemux_tag_add_classification (GstQTDemux * qtdemux, GstTagList * taglist,
11139     const char *tag, const char *dummy, GNode * node)
11140 {
11141   int offset;
11142   char *tag_str = NULL;
11143   guint8 *entity;
11144   guint16 table;
11145   gint len;
11146
11147   len = QT_UINT32 (node->data);
11148   if (len <= 20)
11149     goto short_read;
11150
11151   offset = 12;
11152   entity = (guint8 *) node->data + offset;
11153   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
11154     GST_DEBUG_OBJECT (qtdemux,
11155         "classification info: %c%c%c%c invalid classification entity",
11156         entity[0], entity[1], entity[2], entity[3]);
11157     return;
11158   }
11159
11160   offset += 4;
11161   table = QT_UINT16 ((guint8 *) node->data + offset);
11162
11163   /* Language code skipped */
11164
11165   offset += 4;
11166
11167   /* Tag format: "XXXX://Y[YYYY]/classification info string"
11168    * XXXX: classification entity, fixed length 4 chars.
11169    * Y[YYYY]: classification table, max 5 chars.
11170    */
11171   tag_str = g_strdup_printf ("----://%u/%s",
11172       table, (char *) node->data + offset);
11173
11174   /* memcpy To be sure we're preserving byte order */
11175   memcpy (tag_str, entity, 4);
11176   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
11177
11178   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND, tag, tag_str, NULL);
11179
11180   g_free (tag_str);
11181
11182   return;
11183
11184   /* ERRORS */
11185 short_read:
11186   {
11187     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
11188     return;
11189   }
11190 }
11191
11192 static gboolean
11193 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, GstTagList * taglist,
11194     const char *tag, const char *dummy, GNode * node)
11195 {
11196   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11197   GNode *data;
11198   char *s;
11199   int len;
11200   guint32 type;
11201   int offset;
11202   gboolean ret = TRUE;
11203   const gchar *charset = NULL;
11204
11205   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11206   if (data) {
11207     len = QT_UINT32 (data->data);
11208     type = QT_UINT32 ((guint8 *) data->data + 8);
11209     if (type == 0x00000001 && len > 16) {
11210       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
11211           env_vars);
11212       if (s) {
11213         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11214         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11215         g_free (s);
11216       } else {
11217         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11218       }
11219     }
11220   } else {
11221     len = QT_UINT32 (node->data);
11222     type = QT_UINT32 ((guint8 *) node->data + 4);
11223     if ((type >> 24) == 0xa9) {
11224       gint str_len;
11225       gint lang_code;
11226
11227       /* Type starts with the (C) symbol, so the next data is a list
11228        * of (string size(16), language code(16), string) */
11229
11230       str_len = QT_UINT16 ((guint8 *) node->data + 8);
11231       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
11232
11233       /* the string + fourcc + size + 2 16bit fields,
11234        * means that there are more tags in this atom */
11235       if (len > str_len + 8 + 4) {
11236         /* TODO how to represent the same tag in different languages? */
11237         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
11238             "text alternatives, reading only first one");
11239       }
11240
11241       offset = 12;
11242       len = str_len + 8 + 4;    /* remove trailing strings that we don't use */
11243       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
11244
11245       if (lang_code < 0x800) {  /* MAC encoded string */
11246         charset = "mac";
11247       }
11248     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
11249             QT_FOURCC ((guint8 *) node->data + 4))) {
11250       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
11251
11252       /* we go for 3GP style encoding if major brands claims so,
11253        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
11254       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11255           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
11256               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
11257         offset = 14;
11258         /* 16-bit Language code is ignored here as well */
11259         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
11260       } else {
11261         goto normal;
11262       }
11263     } else {
11264     normal:
11265       offset = 8;
11266       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
11267       ret = FALSE;              /* may have to fallback */
11268     }
11269     if (charset) {
11270       GError *err = NULL;
11271
11272       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
11273           charset, NULL, NULL, &err);
11274       if (err) {
11275         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
11276             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
11277             err->message);
11278         g_error_free (err);
11279       }
11280     } else {
11281       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11282           len - offset, env_vars);
11283     }
11284     if (s) {
11285       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
11286       gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, s, NULL);
11287       g_free (s);
11288       ret = TRUE;
11289     } else {
11290       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
11291     }
11292   }
11293   return ret;
11294 }
11295
11296 static void
11297 qtdemux_tag_add_str (GstQTDemux * qtdemux, GstTagList * taglist,
11298     const char *tag, const char *dummy, GNode * node)
11299 {
11300   qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node);
11301 }
11302
11303 static void
11304 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, GstTagList * taglist,
11305     const char *tag, const char *dummy, GNode * node)
11306 {
11307   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
11308   guint8 *data;
11309   char *s, *t, *k = NULL;
11310   int len;
11311   int offset;
11312   int count;
11313
11314   /* first try normal string tag if major brand not 3GP */
11315   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
11316     if (!qtdemux_tag_add_str_full (qtdemux, taglist, tag, dummy, node)) {
11317       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
11318        * let's try it 3gpp way after minor safety check */
11319       data = node->data;
11320       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
11321         return;
11322     } else
11323       return;
11324   }
11325
11326   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
11327
11328   data = node->data;
11329
11330   len = QT_UINT32 (data);
11331   if (len < 15)
11332     goto short_read;
11333
11334   count = QT_UINT8 (data + 14);
11335   offset = 15;
11336   for (; count; count--) {
11337     gint slen;
11338
11339     if (offset + 1 > len)
11340       goto short_read;
11341     slen = QT_UINT8 (data + offset);
11342     offset += 1;
11343     if (offset + slen > len)
11344       goto short_read;
11345     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
11346         slen, env_vars);
11347     if (s) {
11348       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
11349       if (k) {
11350         t = g_strjoin (",", k, s, NULL);
11351         g_free (s);
11352         g_free (k);
11353         k = t;
11354       } else {
11355         k = s;
11356       }
11357     } else {
11358       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
11359     }
11360     offset += slen;
11361   }
11362
11363 done:
11364   if (k) {
11365     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
11366     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, k, NULL);
11367   }
11368   g_free (k);
11369
11370   return;
11371
11372   /* ERRORS */
11373 short_read:
11374   {
11375     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
11376     goto done;
11377   }
11378 }
11379
11380 static void
11381 qtdemux_tag_add_num (GstQTDemux * qtdemux, GstTagList * taglist,
11382     const char *tag1, const char *tag2, GNode * node)
11383 {
11384   GNode *data;
11385   int len;
11386   int type;
11387   int n1, n2;
11388
11389   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11390   if (data) {
11391     len = QT_UINT32 (data->data);
11392     type = QT_UINT32 ((guint8 *) data->data + 8);
11393     if (type == 0x00000000 && len >= 22) {
11394       n1 = QT_UINT16 ((guint8 *) data->data + 18);
11395       n2 = QT_UINT16 ((guint8 *) data->data + 20);
11396       if (n1 > 0) {
11397         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
11398         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, n1, NULL);
11399       }
11400       if (n2 > 0) {
11401         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
11402         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag2, n2, NULL);
11403       }
11404     }
11405   }
11406 }
11407
11408 static void
11409 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, GstTagList * taglist,
11410     const char *tag1, const char *dummy, GNode * node)
11411 {
11412   GNode *data;
11413   int len;
11414   int type;
11415   int n1;
11416
11417   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11418   if (data) {
11419     len = QT_UINT32 (data->data);
11420     type = QT_UINT32 ((guint8 *) data->data + 8);
11421     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
11422     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11423     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
11424       n1 = QT_UINT16 ((guint8 *) data->data + 16);
11425       if (n1) {
11426         /* do not add bpm=0 */
11427         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
11428         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, (gdouble) n1,
11429             NULL);
11430       }
11431     }
11432   }
11433 }
11434
11435 static void
11436 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, GstTagList * taglist,
11437     const char *tag1, const char *dummy, GNode * node)
11438 {
11439   GNode *data;
11440   int len;
11441   int type;
11442   guint32 num;
11443
11444   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11445   if (data) {
11446     len = QT_UINT32 (data->data);
11447     type = QT_UINT32 ((guint8 *) data->data + 8);
11448     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
11449     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
11450     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
11451       num = QT_UINT32 ((guint8 *) data->data + 16);
11452       if (num) {
11453         /* do not add num=0 */
11454         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
11455         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, num, NULL);
11456       }
11457     }
11458   }
11459 }
11460
11461 static void
11462 qtdemux_tag_add_covr (GstQTDemux * qtdemux, GstTagList * taglist,
11463     const char *tag1, const char *dummy, GNode * node)
11464 {
11465   GNode *data;
11466   int len;
11467   int type;
11468   GstSample *sample;
11469
11470   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11471   if (data) {
11472     len = QT_UINT32 (data->data);
11473     type = QT_UINT32 ((guint8 *) data->data + 8);
11474     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
11475     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
11476       if ((sample =
11477               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
11478                   len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
11479         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
11480         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag1, sample, NULL);
11481         gst_sample_unref (sample);
11482       }
11483     }
11484   }
11485 }
11486
11487 static void
11488 qtdemux_tag_add_date (GstQTDemux * qtdemux, GstTagList * taglist,
11489     const char *tag, const char *dummy, GNode * node)
11490 {
11491   GNode *data;
11492   char *s;
11493   int len;
11494   int type;
11495
11496   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11497   if (data) {
11498     len = QT_UINT32 (data->data);
11499     type = QT_UINT32 ((guint8 *) data->data + 8);
11500     if (type == 0x00000001 && len > 16) {
11501       guint y, m = 1, d = 1;
11502       gint ret;
11503
11504       s = g_strndup ((char *) data->data + 16, len - 16);
11505       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
11506       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
11507       if (ret >= 1 && y > 1500 && y < 3000) {
11508         GDate *date;
11509
11510         date = g_date_new_dmy (d, m, y);
11511         gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, date, NULL);
11512         g_date_free (date);
11513       } else {
11514         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
11515       }
11516       g_free (s);
11517     }
11518   }
11519 }
11520
11521 static void
11522 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, GstTagList * taglist,
11523     const char *tag, const char *dummy, GNode * node)
11524 {
11525   GNode *data;
11526
11527   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11528
11529   /* re-route to normal string tag if major brand says so
11530    * or no data atom and compatible brand suggests so */
11531   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
11532       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
11533     qtdemux_tag_add_str (qtdemux, taglist, tag, dummy, node);
11534     return;
11535   }
11536
11537   if (data) {
11538     guint len, type, n;
11539
11540     len = QT_UINT32 (data->data);
11541     type = QT_UINT32 ((guint8 *) data->data + 8);
11542     if (type == 0x00000000 && len >= 18) {
11543       n = QT_UINT16 ((guint8 *) data->data + 16);
11544       if (n > 0) {
11545         const gchar *genre;
11546
11547         genre = gst_tag_id3_genre_get (n - 1);
11548         if (genre != NULL) {
11549           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
11550           gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, genre, NULL);
11551         }
11552       }
11553     }
11554   }
11555 }
11556
11557 static void
11558 qtdemux_add_double_tag_from_str (GstQTDemux * demux, GstTagList * taglist,
11559     const gchar * tag, guint8 * data, guint32 datasize)
11560 {
11561   gdouble value;
11562   gchar *datacopy;
11563
11564   /* make a copy to have \0 at the end */
11565   datacopy = g_strndup ((gchar *) data, datasize);
11566
11567   /* convert the str to double */
11568   if (sscanf (datacopy, "%lf", &value) == 1) {
11569     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
11570     gst_tag_list_add (taglist, GST_TAG_MERGE_REPLACE, tag, value, NULL);
11571   } else {
11572     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
11573         datacopy);
11574   }
11575   g_free (datacopy);
11576 }
11577
11578
11579 static void
11580 qtdemux_tag_add_revdns (GstQTDemux * demux, GstTagList * taglist,
11581     const char *tag, const char *tag_bis, GNode * node)
11582 {
11583   GNode *mean;
11584   GNode *name;
11585   GNode *data;
11586   guint32 meansize;
11587   guint32 namesize;
11588   guint32 datatype;
11589   guint32 datasize;
11590   const gchar *meanstr;
11591   const gchar *namestr;
11592
11593   /* checking the whole ---- atom size for consistency */
11594   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
11595     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
11596     return;
11597   }
11598
11599   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
11600   if (!mean) {
11601     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
11602     return;
11603   }
11604
11605   meansize = QT_UINT32 (mean->data);
11606   if (meansize <= 12) {
11607     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
11608     return;
11609   }
11610   meanstr = ((gchar *) mean->data) + 12;
11611   meansize -= 12;
11612
11613   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
11614   if (!name) {
11615     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
11616     return;
11617   }
11618
11619   namesize = QT_UINT32 (name->data);
11620   if (namesize <= 12) {
11621     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
11622     return;
11623   }
11624   namestr = ((gchar *) name->data) + 12;
11625   namesize -= 12;
11626
11627   /*
11628    * Data atom is:
11629    * uint32 - size
11630    * uint32 - name
11631    * uint8  - version
11632    * uint24 - data type
11633    * uint32 - all 0
11634    * rest   - the data
11635    */
11636   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
11637   if (!data) {
11638     GST_WARNING_OBJECT (demux, "No data atom in this tag");
11639     return;
11640   }
11641   datasize = QT_UINT32 (data->data);
11642   if (datasize <= 16) {
11643     GST_WARNING_OBJECT (demux, "Data atom too small");
11644     return;
11645   }
11646   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
11647
11648   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
11649       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
11650     static const struct
11651     {
11652       const gchar name[28];
11653       const gchar tag[28];
11654     } tags[] = {
11655       {
11656       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
11657       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
11658       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
11659       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
11660       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
11661       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
11662       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
11663       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
11664     };
11665     int i;
11666
11667     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
11668       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
11669         switch (gst_tag_get_type (tags[i].tag)) {
11670           case G_TYPE_DOUBLE:
11671             qtdemux_add_double_tag_from_str (demux, taglist, tags[i].tag,
11672                 ((guint8 *) data->data) + 16, datasize - 16);
11673             break;
11674           case G_TYPE_STRING:
11675             qtdemux_tag_add_str (demux, taglist, tags[i].tag, NULL, node);
11676             break;
11677           default:
11678             /* not reached */
11679             break;
11680         }
11681         break;
11682       }
11683     }
11684     if (i == G_N_ELEMENTS (tags))
11685       goto unknown_tag;
11686   } else {
11687     goto unknown_tag;
11688   }
11689
11690   return;
11691
11692 /* errors */
11693 unknown_tag:
11694 #ifndef GST_DISABLE_GST_DEBUG
11695   {
11696     gchar *namestr_dbg;
11697     gchar *meanstr_dbg;
11698
11699     meanstr_dbg = g_strndup (meanstr, meansize);
11700     namestr_dbg = g_strndup (namestr, namesize);
11701
11702     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
11703         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
11704
11705     g_free (namestr_dbg);
11706     g_free (meanstr_dbg);
11707   }
11708 #endif
11709   return;
11710 }
11711
11712 static void
11713 qtdemux_tag_add_id32 (GstQTDemux * demux, GstTagList * taglist, const char *tag,
11714     const char *tag_bis, GNode * node)
11715 {
11716   guint8 *data;
11717   GstBuffer *buf;
11718   guint len;
11719   GstTagList *id32_taglist = NULL;
11720
11721   GST_LOG_OBJECT (demux, "parsing ID32");
11722
11723   data = node->data;
11724   len = GST_READ_UINT32_BE (data);
11725
11726   /* need at least full box and language tag */
11727   if (len < 12 + 2)
11728     return;
11729
11730   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
11731   gst_buffer_fill (buf, 0, data + 14, len - 14);
11732
11733   id32_taglist = gst_tag_list_from_id3v2_tag (buf);
11734   if (id32_taglist) {
11735     GST_LOG_OBJECT (demux, "parsing ok");
11736     gst_tag_list_insert (taglist, id32_taglist, GST_TAG_MERGE_KEEP);
11737     gst_tag_list_unref (id32_taglist);
11738   } else {
11739     GST_LOG_OBJECT (demux, "parsing failed");
11740   }
11741
11742   gst_buffer_unref (buf);
11743 }
11744
11745 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux, GstTagList * taglist,
11746     const char *tag, const char *tag_bis, GNode * node);
11747
11748 /* unmapped tags
11749 FOURCC_pcst -> if media is a podcast -> bool
11750 FOURCC_cpil -> if media is part of a compilation -> bool
11751 FOURCC_pgap -> if media is part of a gapless context -> bool
11752 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
11753 */
11754
11755 static const struct
11756 {
11757   guint32 fourcc;
11758   const gchar *gst_tag;
11759   const gchar *gst_tag_bis;
11760   const GstQTDemuxAddTagFunc func;
11761 } add_funcs[] = {
11762   {
11763   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11764   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
11765   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
11766   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11767   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11768   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
11769   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
11770   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
11771   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11772   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
11773   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11774   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
11775   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11776   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11777   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11778   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
11779   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
11780   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
11781   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
11782   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11783   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
11784   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
11785   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11786         qtdemux_tag_add_num}, {
11787   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
11788         qtdemux_tag_add_num}, {
11789   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
11790   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
11791   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
11792   FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
11793   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
11794   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
11795   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11796   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
11797   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
11798   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
11799   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
11800   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11801   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
11802   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
11803   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
11804   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
11805   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
11806   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
11807         qtdemux_tag_add_classification}, {
11808   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
11809   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
11810   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
11811
11812     /* This is a special case, some tags are stored in this
11813      * 'reverse dns naming', according to:
11814      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
11815      * bug #614471
11816      */
11817   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
11818     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
11819   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
11820 };
11821
11822 struct _GstQtDemuxTagList
11823 {
11824   GstQTDemux *demux;
11825   GstTagList *taglist;
11826 };
11827 typedef struct _GstQtDemuxTagList GstQtDemuxTagList;
11828
11829 static void
11830 qtdemux_tag_add_blob (GNode * node, GstQtDemuxTagList * qtdemuxtaglist)
11831 {
11832   gint len;
11833   guint8 *data;
11834   GstBuffer *buf;
11835   gchar *media_type;
11836   const gchar *style;
11837   GstSample *sample;
11838   GstStructure *s;
11839   guint i;
11840   guint8 ndata[4];
11841   GstQTDemux *demux = qtdemuxtaglist->demux;
11842   GstTagList *taglist = qtdemuxtaglist->taglist;
11843
11844   data = node->data;
11845   len = QT_UINT32 (data);
11846   buf = gst_buffer_new_and_alloc (len);
11847   gst_buffer_fill (buf, 0, data, len);
11848
11849   /* heuristic to determine style of tag */
11850   if (QT_FOURCC (data + 4) == FOURCC_____ ||
11851       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
11852     style = "itunes";
11853   else if (demux->major_brand == FOURCC_qt__)
11854     style = "quicktime";
11855   /* fall back to assuming iso/3gp tag style */
11856   else
11857     style = "iso";
11858
11859   /* santize the name for the caps. */
11860   for (i = 0; i < 4; i++) {
11861     guint8 d = data[4 + i];
11862     if (g_ascii_isalnum (d))
11863       ndata[i] = g_ascii_tolower (d);
11864     else
11865       ndata[i] = '_';
11866   }
11867
11868   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
11869       ndata[0], ndata[1], ndata[2], ndata[3]);
11870   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
11871
11872   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
11873   sample = gst_sample_new (buf, NULL, NULL, s);
11874   gst_buffer_unref (buf);
11875   g_free (media_type);
11876
11877   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
11878       len, s);
11879
11880   gst_tag_list_add (taglist, GST_TAG_MERGE_APPEND,
11881       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
11882
11883   gst_sample_unref (sample);
11884 }
11885
11886 static void
11887 qtdemux_parse_udta (GstQTDemux * qtdemux, GstTagList * taglist, GNode * udta)
11888 {
11889   GNode *meta;
11890   GNode *ilst;
11891   GNode *xmp_;
11892   GNode *node;
11893   gint i;
11894   GstQtDemuxTagList demuxtaglist;
11895
11896   demuxtaglist.demux = qtdemux;
11897   demuxtaglist.taglist = taglist;
11898
11899   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
11900   if (meta != NULL) {
11901     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
11902     if (ilst == NULL) {
11903       GST_LOG_OBJECT (qtdemux, "no ilst");
11904       return;
11905     }
11906   } else {
11907     ilst = udta;
11908     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
11909   }
11910
11911   i = 0;
11912   while (i < G_N_ELEMENTS (add_funcs)) {
11913     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
11914     if (node) {
11915       gint len;
11916
11917       len = QT_UINT32 (node->data);
11918       if (len < 12) {
11919         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
11920             GST_FOURCC_ARGS (add_funcs[i].fourcc));
11921       } else {
11922         add_funcs[i].func (qtdemux, taglist, add_funcs[i].gst_tag,
11923             add_funcs[i].gst_tag_bis, node);
11924       }
11925       g_node_destroy (node);
11926     } else {
11927       i++;
11928     }
11929   }
11930
11931   /* parsed nodes have been removed, pass along remainder as blob */
11932   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
11933       (GNodeForeachFunc) qtdemux_tag_add_blob, &demuxtaglist);
11934
11935   /* parse up XMP_ node if existing */
11936   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
11937   if (xmp_ != NULL) {
11938     GstBuffer *buf;
11939     GstTagList *xmptaglist;
11940
11941     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
11942         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
11943     xmptaglist = gst_tag_list_from_xmp_buffer (buf);
11944     gst_buffer_unref (buf);
11945
11946     qtdemux_handle_xmp_taglist (qtdemux, taglist, xmptaglist);
11947   } else {
11948     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
11949   }
11950 }
11951
11952 typedef struct
11953 {
11954   GstStructure *structure;      /* helper for sort function */
11955   gchar *location;
11956   guint min_req_bitrate;
11957   guint min_req_qt_version;
11958 } GstQtReference;
11959
11960 static gint
11961 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
11962 {
11963   GstQtReference *ref_a = (GstQtReference *) a;
11964   GstQtReference *ref_b = (GstQtReference *) b;
11965
11966   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
11967     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
11968
11969   /* known bitrates go before unknown; higher bitrates go first */
11970   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
11971 }
11972
11973 /* sort the redirects and post a message for the application.
11974  */
11975 static void
11976 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
11977 {
11978   GstQtReference *best;
11979   GstStructure *s;
11980   GstMessage *msg;
11981   GValue list_val = { 0, };
11982   GList *l;
11983
11984   g_assert (references != NULL);
11985
11986   references = g_list_sort (references, qtdemux_redirects_sort_func);
11987
11988   best = (GstQtReference *) references->data;
11989
11990   g_value_init (&list_val, GST_TYPE_LIST);
11991
11992   for (l = references; l != NULL; l = l->next) {
11993     GstQtReference *ref = (GstQtReference *) l->data;
11994     GValue struct_val = { 0, };
11995
11996     ref->structure = gst_structure_new ("redirect",
11997         "new-location", G_TYPE_STRING, ref->location, NULL);
11998
11999     if (ref->min_req_bitrate > 0) {
12000       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
12001           ref->min_req_bitrate, NULL);
12002     }
12003
12004     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
12005     g_value_set_boxed (&struct_val, ref->structure);
12006     gst_value_list_append_value (&list_val, &struct_val);
12007     g_value_unset (&struct_val);
12008     /* don't free anything here yet, since we need best->structure below */
12009   }
12010
12011   g_assert (best != NULL);
12012   s = gst_structure_copy (best->structure);
12013
12014   if (g_list_length (references) > 1) {
12015     gst_structure_set_value (s, "locations", &list_val);
12016   }
12017
12018   g_value_unset (&list_val);
12019
12020   for (l = references; l != NULL; l = l->next) {
12021     GstQtReference *ref = (GstQtReference *) l->data;
12022
12023     gst_structure_free (ref->structure);
12024     g_free (ref->location);
12025     g_free (ref);
12026   }
12027   g_list_free (references);
12028
12029   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
12030   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
12031   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
12032   qtdemux->posted_redirect = TRUE;
12033 }
12034
12035 /* look for redirect nodes, collect all redirect information and
12036  * process it.
12037  */
12038 static gboolean
12039 qtdemux_parse_redirects (GstQTDemux * qtdemux)
12040 {
12041   GNode *rmra, *rmda, *rdrf;
12042
12043   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
12044   if (rmra) {
12045     GList *redirects = NULL;
12046
12047     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
12048     while (rmda) {
12049       GstQtReference ref = { NULL, NULL, 0, 0 };
12050       GNode *rmdr, *rmvc;
12051
12052       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
12053         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
12054         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
12055             ref.min_req_bitrate);
12056       }
12057
12058       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
12059         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
12060         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
12061
12062 #ifndef GST_DISABLE_GST_DEBUG
12063         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
12064 #endif
12065         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
12066
12067         GST_LOG_OBJECT (qtdemux,
12068             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
12069             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
12070             bitmask, check_type);
12071         if (package == FOURCC_qtim && check_type == 0) {
12072           ref.min_req_qt_version = version;
12073         }
12074       }
12075
12076       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
12077       if (rdrf) {
12078         guint32 ref_type;
12079         guint8 *ref_data;
12080         guint ref_len;
12081
12082         ref_len = QT_UINT32 ((guint8 *) rdrf->data);
12083         if (ref_len > 20) {
12084           ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
12085           ref_data = (guint8 *) rdrf->data + 20;
12086           if (ref_type == FOURCC_alis) {
12087             guint record_len, record_version, fn_len;
12088
12089             if (ref_len > 70) {
12090               /* MacOSX alias record, google for alias-layout.txt */
12091               record_len = QT_UINT16 (ref_data + 4);
12092               record_version = QT_UINT16 (ref_data + 4 + 2);
12093               fn_len = QT_UINT8 (ref_data + 50);
12094               if (record_len > 50 && record_version == 2 && fn_len > 0) {
12095                 ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
12096               }
12097             } else {
12098               GST_WARNING_OBJECT (qtdemux, "Invalid rdrf/alis size (%u < 70)",
12099                   ref_len);
12100             }
12101           } else if (ref_type == FOURCC_url_) {
12102             ref.location = g_strndup ((gchar *) ref_data, ref_len - 8);
12103           } else {
12104             GST_DEBUG_OBJECT (qtdemux,
12105                 "unknown rdrf reference type %" GST_FOURCC_FORMAT,
12106                 GST_FOURCC_ARGS (ref_type));
12107           }
12108           if (ref.location != NULL) {
12109             GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
12110             redirects =
12111                 g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
12112           } else {
12113             GST_WARNING_OBJECT (qtdemux,
12114                 "Failed to extract redirect location from rdrf atom");
12115           }
12116         } else {
12117           GST_WARNING_OBJECT (qtdemux, "Invalid rdrf size (%u < 20)", ref_len);
12118         }
12119       }
12120
12121       /* look for others */
12122       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
12123     }
12124
12125     if (redirects != NULL) {
12126       qtdemux_process_redirects (qtdemux, redirects);
12127     }
12128   }
12129   return TRUE;
12130 }
12131
12132 static GstTagList *
12133 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
12134 {
12135   const gchar *fmt;
12136
12137   if (tags == NULL) {
12138     tags = gst_tag_list_new_empty ();
12139     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
12140   }
12141
12142   if (qtdemux->major_brand == FOURCC_mjp2)
12143     fmt = "Motion JPEG 2000";
12144   else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
12145     fmt = "3GP";
12146   else if (qtdemux->major_brand == FOURCC_qt__)
12147     fmt = "Quicktime";
12148   else if (qtdemux->fragmented)
12149     fmt = "ISO fMP4";
12150   else
12151     fmt = "ISO MP4/M4A";
12152
12153   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
12154       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
12155
12156   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
12157       fmt, NULL);
12158
12159   return tags;
12160 }
12161
12162 /* we have read th complete moov node now.
12163  * This function parses all of the relevant info, creates the traks and
12164  * prepares all data structures for playback
12165  */
12166 static gboolean
12167 qtdemux_parse_tree (GstQTDemux * qtdemux)
12168 {
12169   GNode *mvhd;
12170   GNode *trak;
12171   GNode *udta;
12172   GNode *mvex;
12173   GstClockTime duration;
12174   GNode *pssh;
12175   guint64 creation_time;
12176   GstDateTime *datetime = NULL;
12177   gint version;
12178
12179   /* make sure we have a usable taglist */
12180   if (!qtdemux->tag_list) {
12181     qtdemux->tag_list = gst_tag_list_new_empty ();
12182     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12183   } else {
12184     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12185   }
12186
12187   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
12188   if (mvhd == NULL) {
12189     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
12190     return qtdemux_parse_redirects (qtdemux);
12191   }
12192
12193   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
12194   if (version == 1) {
12195     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
12196     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
12197     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
12198   } else if (version == 0) {
12199     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
12200     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
12201     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
12202   } else {
12203     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
12204     return FALSE;
12205   }
12206
12207   /* Moving qt creation time (secs since 1904) to unix time */
12208   if (creation_time != 0) {
12209     /* Try to use epoch first as it should be faster and more commonly found */
12210     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
12211       GTimeVal now;
12212
12213       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
12214       /* some data cleansing sanity */
12215       g_get_current_time (&now);
12216       if (now.tv_sec + 24 * 3600 < creation_time) {
12217         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
12218       } else {
12219         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
12220       }
12221     } else {
12222       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
12223       GDateTime *dt, *dt_local;
12224
12225       dt = g_date_time_add_seconds (base_dt, creation_time);
12226       dt_local = g_date_time_to_local (dt);
12227       datetime = gst_date_time_new_from_g_date_time (dt_local);
12228
12229       g_date_time_unref (base_dt);
12230       g_date_time_unref (dt);
12231     }
12232   }
12233   if (datetime) {
12234     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
12235     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
12236         datetime, NULL);
12237     gst_date_time_unref (datetime);
12238   }
12239
12240   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
12241   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
12242
12243   /* check for fragmented file and get some (default) data */
12244   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
12245   if (mvex) {
12246     GNode *mehd;
12247     GstByteReader mehd_data;
12248
12249     /* let track parsing or anyone know weird stuff might happen ... */
12250     qtdemux->fragmented = TRUE;
12251
12252     /* compensate for total duration */
12253     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
12254     if (mehd)
12255       qtdemux_parse_mehd (qtdemux, &mehd_data);
12256   }
12257
12258   /* set duration in the segment info */
12259   gst_qtdemux_get_duration (qtdemux, &duration);
12260   if (duration) {
12261     qtdemux->segment.duration = duration;
12262     /* also do not exceed duration; stop is set that way post seek anyway,
12263      * and segment activation falls back to duration,
12264      * whereas loop only checks stop, so let's align this here as well */
12265     qtdemux->segment.stop = duration;
12266   }
12267
12268   /* parse all traks */
12269   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
12270   while (trak) {
12271     qtdemux_parse_trak (qtdemux, trak);
12272     /* iterate all siblings */
12273     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
12274   }
12275
12276   if (!qtdemux->tag_list) {
12277     GST_DEBUG_OBJECT (qtdemux, "new tag list");
12278     qtdemux->tag_list = gst_tag_list_new_empty ();
12279     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
12280   } else {
12281     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
12282   }
12283
12284   /* find tags */
12285   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
12286   if (udta) {
12287     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12288   } else {
12289     GST_LOG_OBJECT (qtdemux, "No udta node found.");
12290   }
12291
12292   /* maybe also some tags in meta box */
12293   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
12294   if (udta) {
12295     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
12296     qtdemux_parse_udta (qtdemux, qtdemux->tag_list, udta);
12297   } else {
12298     GST_LOG_OBJECT (qtdemux, "No meta node found.");
12299   }
12300
12301   /* parse any protection system info */
12302   pssh = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_pssh);
12303   while (pssh) {
12304     GST_LOG_OBJECT (qtdemux, "Parsing pssh box.");
12305     qtdemux_parse_pssh (qtdemux, pssh);
12306     pssh = qtdemux_tree_get_sibling_by_type (pssh, FOURCC_pssh);
12307   }
12308
12309   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
12310
12311   return TRUE;
12312 }
12313
12314 /* taken from ffmpeg */
12315 static int
12316 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
12317 {
12318   int count = 4;
12319   int len = 0;
12320
12321   while (count--) {
12322     int c;
12323
12324     if (ptr >= end)
12325       return -1;
12326
12327     c = *ptr++;
12328     len = (len << 7) | (c & 0x7f);
12329     if (!(c & 0x80))
12330       break;
12331   }
12332   *end_out = ptr;
12333   return len;
12334 }
12335
12336 /* this can change the codec originally present in @list */
12337 static void
12338 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
12339     GNode * esds, GstTagList * list)
12340 {
12341   int len = QT_UINT32 (esds->data);
12342   guint8 *ptr = esds->data;
12343   guint8 *end = ptr + len;
12344   int tag;
12345   guint8 *data_ptr = NULL;
12346   int data_len = 0;
12347   guint8 object_type_id = 0;
12348   const char *codec_name = NULL;
12349   GstCaps *caps = NULL;
12350
12351   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
12352   ptr += 8;
12353   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
12354   ptr += 4;
12355   while (ptr + 1 < end) {
12356     tag = QT_UINT8 (ptr);
12357     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
12358     ptr++;
12359     len = read_descr_size (ptr, end, &ptr);
12360     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
12361
12362     /* Check the stated amount of data is available for reading */
12363     if (len < 0 || ptr + len > end)
12364       break;
12365
12366     switch (tag) {
12367       case ES_DESCRIPTOR_TAG:
12368         GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
12369         GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
12370         ptr += 3;
12371         break;
12372       case DECODER_CONFIG_DESC_TAG:{
12373         guint max_bitrate, avg_bitrate;
12374
12375         object_type_id = QT_UINT8 (ptr);
12376         max_bitrate = QT_UINT32 (ptr + 5);
12377         avg_bitrate = QT_UINT32 (ptr + 9);
12378         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
12379         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
12380         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
12381         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
12382         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
12383         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
12384           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12385               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
12386         }
12387         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
12388           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
12389               avg_bitrate, NULL);
12390         }
12391         ptr += 13;
12392         break;
12393       }
12394       case DECODER_SPECIFIC_INFO_TAG:
12395         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
12396         if (object_type_id == 0xe0 && len == 0x40) {
12397           guint8 *data;
12398           GstStructure *s;
12399           guint32 clut[16];
12400           gint i;
12401
12402           GST_DEBUG_OBJECT (qtdemux,
12403               "Have VOBSUB palette. Creating palette event");
12404           /* move to decConfigDescr data and read palette */
12405           data = ptr;
12406           for (i = 0; i < 16; i++) {
12407             clut[i] = QT_UINT32 (data);
12408             data += 4;
12409           }
12410
12411           s = gst_structure_new ("application/x-gst-dvd", "event",
12412               G_TYPE_STRING, "dvd-spu-clut-change",
12413               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
12414               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
12415               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
12416               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
12417               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
12418               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
12419               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
12420               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
12421               NULL);
12422
12423           /* store event and trigger custom processing */
12424           stream->pending_event =
12425               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
12426         } else {
12427           /* Generic codec_data handler puts it on the caps */
12428           data_ptr = ptr;
12429           data_len = len;
12430         }
12431
12432         ptr += len;
12433         break;
12434       case SL_CONFIG_DESC_TAG:
12435         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
12436         ptr += 1;
12437         break;
12438       default:
12439         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
12440             tag);
12441         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
12442         ptr += len;
12443         break;
12444     }
12445   }
12446
12447   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
12448    * in use, and should also be used to override some other parameters for some
12449    * codecs. */
12450   switch (object_type_id) {
12451     case 0x20:                 /* MPEG-4 */
12452       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
12453        * profile_and_level_indication */
12454       if (data_ptr != NULL && data_len >= 5 &&
12455           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
12456         gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
12457             data_ptr + 4, data_len - 4);
12458       }
12459       break;                    /* Nothing special needed here */
12460     case 0x21:                 /* H.264 */
12461       codec_name = "H.264 / AVC";
12462       caps = gst_caps_new_simple ("video/x-h264",
12463           "stream-format", G_TYPE_STRING, "avc",
12464           "alignment", G_TYPE_STRING, "au", NULL);
12465       break;
12466     case 0x40:                 /* AAC (any) */
12467     case 0x66:                 /* AAC Main */
12468     case 0x67:                 /* AAC LC */
12469     case 0x68:                 /* AAC SSR */
12470       /* Override channels and rate based on the codec_data, as it's often
12471        * wrong. */
12472       /* Only do so for basic setup without HE-AAC extension */
12473       if (data_ptr && data_len == 2) {
12474         guint channels, rateindex, rate;
12475
12476         /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
12477         channels = (data_ptr[1] & 0x7f) >> 3;
12478         if (channels > 0 && channels < 7) {
12479           stream->n_channels = channels;
12480         } else if (channels == 7) {
12481           stream->n_channels = 8;
12482         }
12483
12484         rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
12485         rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
12486         if (rate > 0)
12487           stream->rate = rate;
12488       }
12489
12490       /* Set level and profile if possible */
12491       if (data_ptr != NULL && data_len >= 2) {
12492         gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
12493             data_ptr, data_len);
12494       }
12495       break;
12496     case 0x60:                 /* MPEG-2, various profiles */
12497     case 0x61:
12498     case 0x62:
12499     case 0x63:
12500     case 0x64:
12501     case 0x65:
12502       codec_name = "MPEG-2 video";
12503       caps = gst_caps_new_simple ("video/mpeg",
12504           "mpegversion", G_TYPE_INT, 2,
12505           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12506       break;
12507     case 0x69:                 /* MPEG-2 BC audio */
12508     case 0x6B:                 /* MPEG-1 audio */
12509       caps = gst_caps_new_simple ("audio/mpeg",
12510           "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
12511       codec_name = "MPEG-1 audio";
12512       break;
12513     case 0x6A:                 /* MPEG-1 */
12514       codec_name = "MPEG-1 video";
12515       caps = gst_caps_new_simple ("video/mpeg",
12516           "mpegversion", G_TYPE_INT, 1,
12517           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12518       break;
12519     case 0x6C:                 /* MJPEG */
12520       caps =
12521           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12522           NULL);
12523       codec_name = "Motion-JPEG";
12524       break;
12525     case 0x6D:                 /* PNG */
12526       caps =
12527           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
12528           NULL);
12529       codec_name = "PNG still images";
12530       break;
12531     case 0x6E:                 /* JPEG2000 */
12532       codec_name = "JPEG-2000";
12533       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12534       break;
12535     case 0xA4:                 /* Dirac */
12536       codec_name = "Dirac";
12537       caps = gst_caps_new_empty_simple ("video/x-dirac");
12538       break;
12539     case 0xA5:                 /* AC3 */
12540       codec_name = "AC-3 audio";
12541       caps = gst_caps_new_simple ("audio/x-ac3",
12542           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12543       break;
12544     case 0xA9:                 /* AC3 */
12545       codec_name = "DTS audio";
12546       caps = gst_caps_new_simple ("audio/x-dts",
12547           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
12548       break;
12549     case 0xE1:                 /* QCELP */
12550       /* QCELP, the codec_data is a riff tag (little endian) with
12551        * 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). */
12552       caps = gst_caps_new_empty_simple ("audio/qcelp");
12553       codec_name = "QCELP";
12554       break;
12555     default:
12556       break;
12557   }
12558
12559   /* If we have a replacement caps, then change our caps for this stream */
12560   if (caps) {
12561     gst_caps_unref (stream->caps);
12562     stream->caps = caps;
12563   }
12564
12565   if (codec_name && list)
12566     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
12567         GST_TAG_AUDIO_CODEC, codec_name, NULL);
12568
12569   /* Add the codec_data attribute to caps, if we have it */
12570   if (data_ptr) {
12571     GstBuffer *buffer;
12572
12573     buffer = gst_buffer_new_and_alloc (data_len);
12574     gst_buffer_fill (buffer, 0, data_ptr, data_len);
12575
12576     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
12577     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
12578
12579     gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
12580         buffer, NULL);
12581     gst_buffer_unref (buffer);
12582   }
12583
12584 }
12585
12586 #define _codec(name) \
12587   do { \
12588     if (codec_name) { \
12589       *codec_name = g_strdup (name); \
12590     } \
12591   } while (0)
12592
12593 static GstCaps *
12594 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
12595     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
12596 {
12597   GstCaps *caps = NULL;
12598   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
12599
12600   switch (fourcc) {
12601     case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
12602       _codec ("PNG still images");
12603       caps = gst_caps_new_empty_simple ("image/png");
12604       break;
12605     case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
12606       _codec ("JPEG still images");
12607       caps =
12608           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12609           NULL);
12610       break;
12611     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
12612     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
12613     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
12614     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
12615       _codec ("Motion-JPEG");
12616       caps =
12617           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
12618           NULL);
12619       break;
12620     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
12621       _codec ("Motion-JPEG format B");
12622       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
12623       break;
12624     case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
12625       _codec ("JPEG-2000");
12626       /* override to what it should be according to spec, avoid palette_data */
12627       stream->bits_per_sample = 24;
12628       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
12629       break;
12630     case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
12631       _codec ("Sorensen video v.3");
12632       caps = gst_caps_new_simple ("video/x-svq",
12633           "svqversion", G_TYPE_INT, 3, NULL);
12634       break;
12635     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
12636     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
12637       _codec ("Sorensen video v.1");
12638       caps = gst_caps_new_simple ("video/x-svq",
12639           "svqversion", G_TYPE_INT, 1, NULL);
12640       break;
12641     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
12642       caps = gst_caps_new_empty_simple ("video/x-raw");
12643       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
12644       _codec ("Windows Raw RGB");
12645       break;
12646     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
12647     {
12648       guint16 bps;
12649
12650       bps = QT_UINT16 (stsd_data + 98);
12651       switch (bps) {
12652         case 15:
12653           format = GST_VIDEO_FORMAT_RGB15;
12654           break;
12655         case 16:
12656           format = GST_VIDEO_FORMAT_RGB16;
12657           break;
12658         case 24:
12659           format = GST_VIDEO_FORMAT_RGB;
12660           break;
12661         case 32:
12662           format = GST_VIDEO_FORMAT_ARGB;
12663           break;
12664         default:
12665           /* unknown */
12666           break;
12667       }
12668       break;
12669     }
12670     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
12671       format = GST_VIDEO_FORMAT_I420;
12672       break;
12673     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
12674     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
12675       format = GST_VIDEO_FORMAT_I420;
12676       break;
12677     case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
12678     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
12679       format = GST_VIDEO_FORMAT_UYVY;
12680       break;
12681     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
12682       format = GST_VIDEO_FORMAT_v308;
12683       break;
12684     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
12685       format = GST_VIDEO_FORMAT_v216;
12686       break;
12687     case GST_MAKE_FOURCC ('v', '2', '1', '0'):
12688       format = GST_VIDEO_FORMAT_v210;
12689       break;
12690     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
12691       format = GST_VIDEO_FORMAT_r210;
12692       break;
12693       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
12694          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
12695          format = GST_VIDEO_FORMAT_v410;
12696          break;
12697        */
12698       /* Packed YUV 4:4:4:4 8 bit in 32 bits
12699        * but different order than AYUV
12700        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
12701        format = GST_VIDEO_FORMAT_v408;
12702        break;
12703        */
12704     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
12705     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
12706       _codec ("MPEG-1 video");
12707       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
12708           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12709       break;
12710     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
12711     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
12712     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
12713     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
12714     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
12715     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
12716     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
12717     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
12718     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
12719     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
12720     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
12721     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
12722     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
12723     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
12724     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
12725     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
12726     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
12727     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
12728     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
12729     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
12730     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
12731     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
12732     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
12733     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
12734     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
12735     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
12736     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
12737     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
12738     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
12739     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
12740     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
12741     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
12742     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
12743     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
12744     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
12745     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
12746     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12747     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
12748     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
12749     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
12750     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
12751     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
12752     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
12753     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
12754     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
12755     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
12756       _codec ("MPEG-2 video");
12757       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
12758           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12759       break;
12760     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
12761       _codec ("GIF still images");
12762       caps = gst_caps_new_empty_simple ("image/gif");
12763       break;
12764     case GST_MAKE_FOURCC ('h', '2', '6', '3'):
12765     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
12766     case GST_MAKE_FOURCC ('s', '2', '6', '3'):
12767     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
12768       _codec ("H.263");
12769       /* ffmpeg uses the height/width props, don't know why */
12770       caps = gst_caps_new_simple ("video/x-h263",
12771           "variant", G_TYPE_STRING, "itu", NULL);
12772       break;
12773     case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
12774     case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
12775       _codec ("MPEG-4 video");
12776       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
12777           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12778       break;
12779     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
12780     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
12781       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
12782       caps = gst_caps_new_simple ("video/x-msmpeg",
12783           "msmpegversion", G_TYPE_INT, 43, NULL);
12784       break;
12785     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
12786       _codec ("DivX 3");
12787       caps = gst_caps_new_simple ("video/x-divx",
12788           "divxversion", G_TYPE_INT, 3, NULL);
12789       break;
12790     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
12791     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
12792       _codec ("DivX 4");
12793       caps = gst_caps_new_simple ("video/x-divx",
12794           "divxversion", G_TYPE_INT, 4, NULL);
12795       break;
12796     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
12797       _codec ("DivX 5");
12798       caps = gst_caps_new_simple ("video/x-divx",
12799           "divxversion", G_TYPE_INT, 5, NULL);
12800       break;
12801
12802     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
12803     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
12804     case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
12805     case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
12806     case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
12807     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
12808       caps = gst_caps_new_simple ("video/mpeg",
12809           "mpegversion", G_TYPE_INT, 4, NULL);
12810       if (codec_name)
12811         *codec_name = g_strdup ("MPEG-4");
12812       break;
12813
12814     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
12815       _codec ("Cinepak");
12816       caps = gst_caps_new_empty_simple ("video/x-cinepak");
12817       break;
12818     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
12819       _codec ("Apple QuickDraw");
12820       caps = gst_caps_new_empty_simple ("video/x-qdrw");
12821       break;
12822     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
12823       _codec ("Apple video");
12824       caps = gst_caps_new_empty_simple ("video/x-apple-video");
12825       break;
12826     case GST_MAKE_FOURCC ('H', '2', '6', '4'):
12827     case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
12828       _codec ("H.264 / AVC");
12829       caps = gst_caps_new_simple ("video/x-h264",
12830           "stream-format", G_TYPE_STRING, "avc",
12831           "alignment", G_TYPE_STRING, "au", NULL);
12832       break;
12833     case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
12834       _codec ("H.264 / AVC");
12835       caps = gst_caps_new_simple ("video/x-h264",
12836           "stream-format", G_TYPE_STRING, "avc3",
12837           "alignment", G_TYPE_STRING, "au", NULL);
12838       break;
12839     case GST_MAKE_FOURCC ('H', '2', '6', '5'):
12840     case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
12841       _codec ("H.265 / HEVC");
12842       caps = gst_caps_new_simple ("video/x-h265",
12843           "stream-format", G_TYPE_STRING, "hvc1",
12844           "alignment", G_TYPE_STRING, "au", NULL);
12845       break;
12846     case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
12847       _codec ("H.265 / HEVC");
12848       caps = gst_caps_new_simple ("video/x-h265",
12849           "stream-format", G_TYPE_STRING, "hev1",
12850           "alignment", G_TYPE_STRING, "au", NULL);
12851       break;
12852     case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
12853       _codec ("Run-length encoding");
12854       caps = gst_caps_new_simple ("video/x-rle",
12855           "layout", G_TYPE_STRING, "quicktime", NULL);
12856       break;
12857     case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
12858       _codec ("Run-length encoding");
12859       caps = gst_caps_new_simple ("video/x-rle",
12860           "layout", G_TYPE_STRING, "microsoft", NULL);
12861       break;
12862     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
12863     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
12864       _codec ("Indeo Video 3");
12865       caps = gst_caps_new_simple ("video/x-indeo",
12866           "indeoversion", G_TYPE_INT, 3, NULL);
12867       break;
12868     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
12869     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
12870       _codec ("Intel Video 4");
12871       caps = gst_caps_new_simple ("video/x-indeo",
12872           "indeoversion", G_TYPE_INT, 4, NULL);
12873       break;
12874     case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
12875     case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
12876     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
12877     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
12878     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
12879     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
12880     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
12881     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
12882       _codec ("DV Video");
12883       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
12884           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12885       break;
12886     case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
12887     case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
12888       _codec ("DVCPro50 Video");
12889       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
12890           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12891       break;
12892     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
12893     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
12894       _codec ("DVCProHD Video");
12895       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
12896           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
12897       break;
12898     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
12899       _codec ("Apple Graphics (SMC)");
12900       caps = gst_caps_new_empty_simple ("video/x-smc");
12901       break;
12902     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
12903       _codec ("VP3");
12904       caps = gst_caps_new_empty_simple ("video/x-vp3");
12905       break;
12906     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
12907       _codec ("VP6 Flash");
12908       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
12909       break;
12910     case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
12911       _codec ("Theora");
12912       caps = gst_caps_new_empty_simple ("video/x-theora");
12913       /* theora uses one byte of padding in the data stream because it does not
12914        * allow 0 sized packets while theora does */
12915       stream->padding = 1;
12916       break;
12917     case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
12918       _codec ("Dirac");
12919       caps = gst_caps_new_empty_simple ("video/x-dirac");
12920       break;
12921     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
12922       _codec ("TIFF still images");
12923       caps = gst_caps_new_empty_simple ("image/tiff");
12924       break;
12925     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
12926       _codec ("Apple Intermediate Codec");
12927       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
12928       break;
12929     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
12930       _codec ("AVID DNxHD");
12931       caps = gst_caps_from_string ("video/x-dnxhd");
12932       break;
12933     case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
12934       _codec ("On2 VP8");
12935       caps = gst_caps_from_string ("video/x-vp8");
12936       break;
12937     case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
12938       _codec ("Apple ProRes LT");
12939       caps =
12940           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
12941           NULL);
12942       break;
12943     case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
12944       _codec ("Apple ProRes HQ");
12945       caps =
12946           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
12947           NULL);
12948       break;
12949     case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
12950       _codec ("Apple ProRes");
12951       caps =
12952           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12953           "standard", NULL);
12954       break;
12955     case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
12956       _codec ("Apple ProRes Proxy");
12957       caps =
12958           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12959           "proxy", NULL);
12960       break;
12961     case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
12962       _codec ("Apple ProRes 4444");
12963       caps =
12964           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
12965           "4444", NULL);
12966       break;
12967     case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
12968     case FOURCC_ovc1:
12969       _codec ("VC-1");
12970       caps = gst_caps_new_simple ("video/x-wmv",
12971           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
12972       break;
12973     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
12974     default:
12975     {
12976       char *s, fourstr[5];
12977
12978       g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
12979       s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
12980       caps = gst_caps_new_empty_simple (s);
12981       g_free (s);
12982       break;
12983     }
12984   }
12985
12986   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
12987     GstVideoInfo info;
12988
12989     gst_video_info_init (&info);
12990     gst_video_info_set_format (&info, format, stream->width, stream->height);
12991
12992     caps = gst_video_info_to_caps (&info);
12993     *codec_name = gst_pb_utils_get_codec_description (caps);
12994
12995     /* enable clipping for raw video streams */
12996     stream->need_clip = TRUE;
12997   }
12998
12999   return caps;
13000 }
13001
13002 static GstCaps *
13003 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13004     guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
13005 {
13006   GstCaps *caps;
13007   const GstStructure *s;
13008   const gchar *name;
13009   gint endian = 0;
13010   GstAudioFormat format = 0;
13011   gint depth;
13012
13013   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13014
13015   depth = stream->bytes_per_packet * 8;
13016
13017   switch (fourcc) {
13018     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
13019       /* fall-through */
13020     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
13021       /* 8-bit audio is unsigned */
13022       if (depth == 8)
13023         format = GST_AUDIO_FORMAT_U8;
13024       /* otherwise it's signed and big-endian just like 'twos' */
13025     case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
13026       endian = G_BIG_ENDIAN;
13027       /* fall-through */
13028     case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
13029     {
13030       gchar *str;
13031
13032       if (!endian)
13033         endian = G_LITTLE_ENDIAN;
13034
13035       if (!format)
13036         format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
13037
13038       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
13039       _codec (str);
13040       g_free (str);
13041
13042       caps = gst_caps_new_simple ("audio/x-raw",
13043           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13044           "layout", G_TYPE_STRING, "interleaved", NULL);
13045       break;
13046     }
13047     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
13048       _codec ("Raw 64-bit floating-point audio");
13049       caps = gst_caps_new_simple ("audio/x-raw",
13050           "format", G_TYPE_STRING, "F64BE",
13051           "layout", G_TYPE_STRING, "interleaved", NULL);
13052       break;
13053     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
13054       _codec ("Raw 32-bit floating-point audio");
13055       caps = gst_caps_new_simple ("audio/x-raw",
13056           "format", G_TYPE_STRING, "F32BE",
13057           "layout", G_TYPE_STRING, "interleaved", NULL);
13058       break;
13059     case FOURCC_in24:
13060       _codec ("Raw 24-bit PCM audio");
13061       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
13062        * endian later */
13063       caps = gst_caps_new_simple ("audio/x-raw",
13064           "format", G_TYPE_STRING, "S24BE",
13065           "layout", G_TYPE_STRING, "interleaved", NULL);
13066       break;
13067     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
13068       _codec ("Raw 32-bit PCM audio");
13069       caps = gst_caps_new_simple ("audio/x-raw",
13070           "format", G_TYPE_STRING, "S32BE",
13071           "layout", G_TYPE_STRING, "interleaved", NULL);
13072       break;
13073     case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
13074       _codec ("Mu-law audio");
13075       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
13076       break;
13077     case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
13078       _codec ("A-law audio");
13079       caps = gst_caps_new_empty_simple ("audio/x-alaw");
13080       break;
13081     case 0x0200736d:
13082     case 0x6d730002:
13083       _codec ("Microsoft ADPCM");
13084       /* Microsoft ADPCM-ACM code 2 */
13085       caps = gst_caps_new_simple ("audio/x-adpcm",
13086           "layout", G_TYPE_STRING, "microsoft", NULL);
13087       break;
13088     case 0x1100736d:
13089     case 0x6d730011:
13090       _codec ("DVI/IMA ADPCM");
13091       caps = gst_caps_new_simple ("audio/x-adpcm",
13092           "layout", G_TYPE_STRING, "dvi", NULL);
13093       break;
13094     case 0x1700736d:
13095     case 0x6d730017:
13096       _codec ("DVI/Intel IMA ADPCM");
13097       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
13098       caps = gst_caps_new_simple ("audio/x-adpcm",
13099           "layout", G_TYPE_STRING, "quicktime", NULL);
13100       break;
13101     case 0x5500736d:
13102     case 0x6d730055:
13103       /* MPEG layer 3, CBR only (pre QT4.1) */
13104     case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
13105       _codec ("MPEG-1 layer 3");
13106       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
13107       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
13108           "mpegversion", G_TYPE_INT, 1, NULL);
13109       break;
13110     case 0x20736d:
13111     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
13112       _codec ("EAC-3 audio");
13113       caps = gst_caps_new_simple ("audio/x-eac3",
13114           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13115       stream->sampled = TRUE;
13116       break;
13117     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
13118     case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
13119       _codec ("AC-3 audio");
13120       caps = gst_caps_new_simple ("audio/x-ac3",
13121           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13122       stream->sampled = TRUE;
13123       break;
13124     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
13125     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
13126       _codec ("DTS audio");
13127       caps = gst_caps_new_simple ("audio/x-dts",
13128           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13129       stream->sampled = TRUE;
13130       break;
13131     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
13132     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
13133       _codec ("DTS-HD audio");
13134       caps = gst_caps_new_simple ("audio/x-dts",
13135           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
13136       stream->sampled = TRUE;
13137       break;
13138     case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
13139       _codec ("MACE-3");
13140       caps = gst_caps_new_simple ("audio/x-mace",
13141           "maceversion", G_TYPE_INT, 3, NULL);
13142       break;
13143     case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
13144       _codec ("MACE-6");
13145       caps = gst_caps_new_simple ("audio/x-mace",
13146           "maceversion", G_TYPE_INT, 6, NULL);
13147       break;
13148     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
13149       /* ogg/vorbis */
13150       caps = gst_caps_new_empty_simple ("application/ogg");
13151       break;
13152     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
13153       _codec ("DV audio");
13154       caps = gst_caps_new_empty_simple ("audio/x-dv");
13155       break;
13156     case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
13157       _codec ("MPEG-4 AAC audio");
13158       caps = gst_caps_new_simple ("audio/mpeg",
13159           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
13160           "stream-format", G_TYPE_STRING, "raw", NULL);
13161       break;
13162     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
13163       _codec ("QDesign Music");
13164       caps = gst_caps_new_empty_simple ("audio/x-qdm");
13165       break;
13166     case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
13167       _codec ("QDesign Music v.2");
13168       /* FIXME: QDesign music version 2 (no constant) */
13169       if (FALSE && data) {
13170         caps = gst_caps_new_simple ("audio/x-qdm2",
13171             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
13172             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
13173             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
13174       } else {
13175         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
13176       }
13177       break;
13178     case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
13179       _codec ("GSM audio");
13180       caps = gst_caps_new_empty_simple ("audio/x-gsm");
13181       break;
13182     case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
13183       _codec ("AMR audio");
13184       caps = gst_caps_new_empty_simple ("audio/AMR");
13185       break;
13186     case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
13187       _codec ("AMR-WB audio");
13188       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
13189       break;
13190     case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
13191       _codec ("Quicktime IMA ADPCM");
13192       caps = gst_caps_new_simple ("audio/x-adpcm",
13193           "layout", G_TYPE_STRING, "quicktime", NULL);
13194       break;
13195     case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
13196       _codec ("Apple lossless audio");
13197       caps = gst_caps_new_empty_simple ("audio/x-alac");
13198       break;
13199     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
13200       _codec ("QualComm PureVoice");
13201       caps = gst_caps_from_string ("audio/qcelp");
13202       break;
13203     case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
13204     case FOURCC_owma:
13205       _codec ("WMA");
13206       caps = gst_caps_new_empty_simple ("audio/x-wma");
13207       break;
13208     case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
13209     {
13210       guint32 flags = 0;
13211       guint32 depth = 0;
13212       guint32 width = 0;
13213       GstAudioFormat format;
13214       enum
13215       {
13216         FLAG_IS_FLOAT = 0x1,
13217         FLAG_IS_BIG_ENDIAN = 0x2,
13218         FLAG_IS_SIGNED = 0x4,
13219         FLAG_IS_PACKED = 0x8,
13220         FLAG_IS_ALIGNED_HIGH = 0x10,
13221         FLAG_IS_NON_INTERLEAVED = 0x20
13222       };
13223       _codec ("Raw LPCM audio");
13224
13225       if (data && len >= 56) {
13226         depth = QT_UINT32 (data + 40);
13227         flags = QT_UINT32 (data + 44);
13228         width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
13229       }
13230       if ((flags & FLAG_IS_FLOAT) == 0) {
13231         if (depth == 0)
13232           depth = 16;
13233         if (width == 0)
13234           width = 16;
13235         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
13236             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
13237             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
13238         caps = gst_caps_new_simple ("audio/x-raw",
13239             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13240             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13241             "non-interleaved" : "interleaved", NULL);
13242       } else {
13243         if (width == 0)
13244           width = 32;
13245         if (width == 64) {
13246           if (flags & FLAG_IS_BIG_ENDIAN)
13247             format = GST_AUDIO_FORMAT_F64BE;
13248           else
13249             format = GST_AUDIO_FORMAT_F64LE;
13250         } else {
13251           if (flags & FLAG_IS_BIG_ENDIAN)
13252             format = GST_AUDIO_FORMAT_F32BE;
13253           else
13254             format = GST_AUDIO_FORMAT_F32LE;
13255         }
13256         caps = gst_caps_new_simple ("audio/x-raw",
13257             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
13258             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
13259             "non-interleaved" : "interleaved", NULL);
13260       }
13261       break;
13262     }
13263     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
13264       /* ? */
13265     default:
13266     {
13267       char *s, fourstr[5];
13268
13269       g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13270       s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
13271       caps = gst_caps_new_empty_simple (s);
13272       g_free (s);
13273       break;
13274     }
13275   }
13276
13277   if (caps) {
13278     GstCaps *templ_caps =
13279         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
13280     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
13281     gst_caps_unref (caps);
13282     gst_caps_unref (templ_caps);
13283     caps = intersection;
13284   }
13285
13286   /* enable clipping for raw audio streams */
13287   s = gst_caps_get_structure (caps, 0);
13288   name = gst_structure_get_name (s);
13289   if (g_str_has_prefix (name, "audio/x-raw")) {
13290     stream->need_clip = TRUE;
13291     stream->max_buffer_size = 4096 * stream->bytes_per_frame;
13292     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
13293   }
13294   return caps;
13295 }
13296
13297 static GstCaps *
13298 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13299     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13300 {
13301   GstCaps *caps;
13302
13303   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
13304
13305   switch (fourcc) {
13306     case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
13307       _codec ("DVD subtitle");
13308       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
13309       stream->need_process = TRUE;
13310       break;
13311     case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
13312       _codec ("Quicktime timed text");
13313       goto text;
13314     case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
13315       _codec ("3GPP timed text");
13316     text:
13317       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
13318           "utf8", NULL);
13319       /* actual text piece needs to be extracted */
13320       stream->need_process = TRUE;
13321       break;
13322     default:
13323     {
13324       char *s, fourstr[5];
13325
13326       g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
13327       s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
13328       caps = gst_caps_new_empty_simple (s);
13329       g_free (s);
13330       break;
13331     }
13332   }
13333   return caps;
13334 }
13335
13336 static GstCaps *
13337 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
13338     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
13339 {
13340   GstCaps *caps;
13341
13342   switch (fourcc) {
13343     case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
13344       _codec ("MPEG 1 video");
13345       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
13346           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
13347       break;
13348     default:
13349       caps = NULL;
13350       break;
13351   }
13352   return caps;
13353 }
13354
13355 static void
13356 gst_qtdemux_append_protection_system_id (GstQTDemux * qtdemux,
13357     const gchar * system_id)
13358 {
13359   gint i;
13360
13361   if (!qtdemux->protection_system_ids)
13362     qtdemux->protection_system_ids =
13363         g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
13364   /* Check whether we already have an entry for this system ID. */
13365   for (i = 0; i < qtdemux->protection_system_ids->len; ++i) {
13366     const gchar *id = g_ptr_array_index (qtdemux->protection_system_ids, i);
13367     if (g_ascii_strcasecmp (system_id, id) == 0) {
13368       return;
13369     }
13370   }
13371   GST_DEBUG_OBJECT (qtdemux, "Adding cenc protection system ID %s", system_id);
13372   g_ptr_array_add (qtdemux->protection_system_ids, g_ascii_strdown (system_id,
13373           -1));
13374 }