qtdemux: fix deadlock seeking in files without seek entries
[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  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Library General Public
14  * License as published by the Free Software Foundation; either
15  * version 2 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Library General Public License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with this library; if not, write to the
24  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25  * Boston, MA 02110-1301, USA.
26  */
27
28 /**
29  * SECTION:element-qtdemux
30  *
31  * Demuxes a .mov file into raw or compressed audio and/or video streams.
32  *
33  * This element supports both push and pull-based scheduling, depending on the
34  * capabilities of the upstream elements.
35  *
36  * <refsect2>
37  * <title>Example launch line</title>
38  * |[
39  * gst-launch-1.0 filesrc location=test.mov ! qtdemux name=demux  demux.audio_0 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_0 ! queue ! decodebin ! videoconvert ! videoscale ! autovideosink
40  * ]| Play (parse and decode) a .mov file and try to output it to
41  * an automatically detected soundcard and videosink. If the MOV file contains
42  * compressed audio or video data, this will only work if you have the
43  * right decoder elements/plugins installed.
44  * </refsect2>
45  */
46
47 #ifdef HAVE_CONFIG_H
48 #include "config.h"
49 #endif
50
51 #include "gst/gst-i18n-plugin.h"
52
53 #include <glib/gprintf.h>
54 #include <gst/tag/tag.h>
55 #include <gst/audio/audio.h>
56 #include <gst/video/video.h>
57
58 #include "qtatomparser.h"
59 #include "qtdemux_types.h"
60 #include "qtdemux_dump.h"
61 #include "fourcc.h"
62 #include "descriptors.h"
63 #include "qtdemux_lang.h"
64 #include "qtdemux.h"
65 #include "qtpalette.h"
66
67 #include "gst/riff/riff-media.h"
68 #include "gst/riff/riff-read.h"
69
70 #include <gst/pbutils/pbutils.h>
71
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <string.h>
75
76 #include <math.h>
77 #include <gst/math-compat.h>
78
79 #ifdef HAVE_ZLIB
80 # include <zlib.h>
81 #endif
82
83 /* max. size considered 'sane' for non-mdat atoms */
84 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
85
86 /* if the sample index is larger than this, something is likely wrong */
87 #define QTDEMUX_MAX_SAMPLE_INDEX_SIZE (50*1024*1024)
88
89 /* For converting qt creation times to unix epoch times */
90 #define QTDEMUX_SECONDS_PER_DAY (60 * 60 * 24)
91 #define QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970 17
92 #define QTDEMUX_SECONDS_FROM_1904_TO_1970 (((1970 - 1904) * (guint64) 365 + \
93     QTDEMUX_LEAP_YEARS_FROM_1904_TO_1970) * QTDEMUX_SECONDS_PER_DAY)
94
95 #define STREAM_IS_EOS(s) (s->time_position == GST_CLOCK_TIME_NONE)
96
97 GST_DEBUG_CATEGORY (qtdemux_debug);
98
99 /*typedef struct _QtNode QtNode; */
100 typedef struct _QtDemuxSegment QtDemuxSegment;
101 typedef struct _QtDemuxSample QtDemuxSample;
102
103 /*struct _QtNode
104 {
105   guint32 type;
106   guint8 *data;
107   gint len;
108 };*/
109
110 struct _QtDemuxSample
111 {
112   guint32 size;
113   gint32 pts_offset;            /* Add this value to timestamp to get the pts */
114   guint64 offset;
115   guint64 timestamp;            /* DTS In mov time */
116   guint32 duration;             /* In mov time */
117   gboolean keyframe;            /* TRUE when this packet is a keyframe */
118 };
119
120 /* Macros for converting to/from timescale */
121 #define QTSTREAMTIME_TO_GSTTIME(stream, value) (gst_util_uint64_scale((value), GST_SECOND, (stream)->timescale))
122 #define GSTTIME_TO_QTSTREAMTIME(stream, value) (gst_util_uint64_scale((value), (stream)->timescale, GST_SECOND))
123
124 #define QTTIME_TO_GSTTIME(qtdemux, value) (gst_util_uint64_scale((value), GST_SECOND, (qtdemux)->timescale))
125 #define GSTTIME_TO_QTTIME(qtdemux, value) (gst_util_uint64_scale((value), (qtdemux)->timescale, GST_SECOND))
126
127 /* timestamp is the DTS */
128 #define QTSAMPLE_DTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp))
129 /* timestamp + offset is the PTS */
130 #define QTSAMPLE_PTS(stream,sample) (QTSTREAMTIME_TO_GSTTIME((stream), (sample)->timestamp + (sample)->pts_offset))
131 /* timestamp + duration - dts is the duration */
132 #define QTSAMPLE_DUR_DTS(stream, sample, dts) (QTSTREAMTIME_TO_GSTTIME ((stream), (sample)->timestamp + (sample)->duration) - (dts))
133
134 #define QTSAMPLE_KEYFRAME(stream,sample) ((stream)->all_keyframe || (sample)->keyframe)
135
136 /*
137  * Quicktime has tracks and segments. A track is a continuous piece of
138  * multimedia content. The track is not always played from start to finish but
139  * instead, pieces of the track are 'cut out' and played in sequence. This is
140  * what the segments do.
141  *
142  * Inside the track we have keyframes (K) and delta frames. The track has its
143  * own timing, which starts from 0 and extends to end. The position in the track
144  * is called the media_time.
145  *
146  * The segments now describe the pieces that should be played from this track
147  * and are basically tuples of media_time/duration/rate entries. We can have
148  * multiple segments and they are all played after one another. An example:
149  *
150  * segment 1: media_time: 1 second, duration: 1 second, rate 1
151  * segment 2: media_time: 3 second, duration: 2 second, rate 2
152  *
153  * To correctly play back this track, one must play: 1 second of media starting
154  * from media_time 1 followed by 2 seconds of media starting from media_time 3
155  * at a rate of 2.
156  *
157  * Each of the segments will be played at a specific time, the first segment at
158  * time 0, the second one after the duration of the first one, etc.. Note that
159  * the time in resulting playback is not identical to the media_time of the
160  * track anymore.
161  *
162  * Visually, assuming the track has 4 second of media_time:
163  *
164  *                (a)                   (b)          (c)              (d)
165  *         .-----------------------------------------------------------.
166  * track:  | K.....K.........K........K.......K.......K...........K... |
167  *         '-----------------------------------------------------------'
168  *         0              1              2              3              4
169  *           .------------^              ^   .----------^              ^
170  *          /              .-------------'  /       .------------------'
171  *         /              /          .-----'       /
172  *         .--------------.         .--------------.
173  *         | segment 1    |         | segment 2    |
174  *         '--------------'         '--------------'
175  *
176  * The challenge here is to cut out the right pieces of the track for each of
177  * the playback segments. This fortunately can easily be done with the SEGMENT
178  * events of GStreamer.
179  *
180  * For playback of segment 1, we need to provide the decoder with the keyframe
181  * (a), in the above figure, but we must instruct it only to output the decoded
182  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
183  * position set to the time of the segment: 0.
184  *
185  * We then proceed to push data from keyframe (a) to frame (b). The decoder
186  * decodes but clips all before media_time 1.
187  *
188  * After finishing a segment, we push out a new SEGMENT event with the clipping
189  * boundaries of the new data.
190  *
191  * This is a good usecase for the GStreamer accumulated SEGMENT events.
192  */
193
194 struct _QtDemuxSegment
195 {
196   /* global time and duration, all gst time */
197   GstClockTime time;
198   GstClockTime stop_time;
199   GstClockTime duration;
200   /* media time of trak, all gst time */
201   GstClockTime media_start;
202   GstClockTime media_stop;
203   gdouble rate;
204   /* Media start time in trak timescale units */
205   guint32 trak_media_start;
206 };
207
208 #define QTSEGMENT_IS_EMPTY(s) ((s)->media_start == GST_CLOCK_TIME_NONE)
209
210 /* Used with fragmented MP4 files (mfra atom) */
211 typedef struct
212 {
213   GstClockTime ts;
214   guint64 moof_offset;
215 } QtDemuxRandomAccessEntry;
216
217 struct _QtDemuxStream
218 {
219   GstPad *pad;
220
221   /* stream type */
222   guint32 subtype;
223   GstCaps *caps;
224   guint32 fourcc;
225   gboolean sparse;
226
227   gboolean new_caps;
228   gboolean new_stream;          /* signals that a stream_start is required */
229   gboolean on_keyframe;         /* if this stream last pushed buffer was a
230                                  * keyframe. This is important to identify
231                                  * where to stop pushing buffers after a
232                                  * segment stop time */
233
234   /* if the stream has a redirect URI in its headers, we store it here */
235   gchar *redirect_uri;
236
237   /* track id */
238   guint track_id;
239
240   /* duration/scale */
241   guint64 duration;             /* in timescale */
242   guint32 timescale;
243
244   /* language */
245   gchar lang_id[4];             /* ISO 639-2T language code */
246
247   /* our samples */
248   guint32 n_samples;
249   QtDemuxSample *samples;
250   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
251   guint32 first_duration;       /* duration in timescale of first sample, used for figuring out
252                                    the framerate, in timescale units */
253   guint32 offset_in_sample;
254   guint32 max_buffer_size;
255
256   /* if we use chunks or samples */
257   gboolean sampled;
258   guint padding;
259
260   /* video info */
261   gint width;
262   gint height;
263   /* aspect ratio */
264   gint display_width;
265   gint display_height;
266   gint par_w;
267   gint par_h;
268   /* Numerator/denominator framerate */
269   gint fps_n;
270   gint fps_d;
271   guint16 bits_per_sample;
272   guint16 color_table_id;
273   GstMemory *rgb8_palette;
274
275   /* audio info */
276   gdouble rate;
277   gint n_channels;
278   guint samples_per_packet;
279   guint samples_per_frame;
280   guint bytes_per_packet;
281   guint bytes_per_sample;
282   guint bytes_per_frame;
283   guint compression;
284
285   /* allocation */
286   gboolean use_allocator;
287   GstAllocator *allocator;
288   GstAllocationParams params;
289
290   /* when a discontinuity is pending */
291   gboolean discont;
292
293   /* list of buffers to push first */
294   GSList *buffers;
295
296   /* if we need to clip this buffer. This is only needed for uncompressed
297    * data */
298   gboolean need_clip;
299
300   /* buffer needs some custom processing, e.g. subtitles */
301   gboolean need_process;
302
303   /* current position */
304   guint32 segment_index;
305   guint32 sample_index;
306   GstClockTime time_position;   /* in gst time */
307
308   /* the Gst segment we are processing out, used for clipping */
309   GstSegment segment;
310   guint32 segment_seqnum;       /* segment event seqnum obtained from seek */
311
312   /* quicktime segments */
313   guint32 n_segments;
314   QtDemuxSegment *segments;
315   gboolean dummy_segment;
316   guint32 from_sample;
317   guint32 to_sample;
318
319   gboolean sent_eos;
320   GstTagList *pending_tags;
321   gboolean send_global_tags;
322
323   GstEvent *pending_event;
324
325   GstByteReader stco;
326   GstByteReader stsz;
327   GstByteReader stsc;
328   GstByteReader stts;
329   GstByteReader stss;
330   GstByteReader stps;
331   GstByteReader ctts;
332
333   gboolean chunks_are_samples;  /* TRUE means treat chunks as samples */
334   gint64 stbl_index;
335   /* stco */
336   guint co_size;
337   GstByteReader co_chunk;
338   guint32 first_chunk;
339   guint32 current_chunk;
340   guint32 last_chunk;
341   guint32 samples_per_chunk;
342   guint32 stco_sample_index;
343   /* stsz */
344   guint32 sample_size;          /* 0 means variable sizes are stored in stsz */
345   /* stsc */
346   guint32 stsc_index;
347   guint32 n_samples_per_chunk;
348   guint32 stsc_chunk_index;
349   guint32 stsc_sample_index;
350   guint64 chunk_offset;
351   /* stts */
352   guint32 stts_index;
353   guint32 stts_samples;
354   guint32 n_sample_times;
355   guint32 stts_sample_index;
356   guint64 stts_time;
357   guint32 stts_duration;
358   /* stss */
359   gboolean stss_present;
360   guint32 n_sample_syncs;
361   guint32 stss_index;
362   /* stps */
363   gboolean stps_present;
364   guint32 n_sample_partial_syncs;
365   guint32 stps_index;
366   QtDemuxRandomAccessEntry *ra_entries;
367   guint n_ra_entries;
368
369   const QtDemuxRandomAccessEntry *pending_seek;
370
371   /* ctts */
372   gboolean ctts_present;
373   guint32 n_composition_times;
374   guint32 ctts_index;
375   guint32 ctts_sample_index;
376   guint32 ctts_count;
377   gint32 ctts_soffset;
378
379   /* fragmented */
380   gboolean parsed_trex;
381   guint32 def_sample_duration;
382   guint32 def_sample_size;
383   guint32 def_sample_flags;
384
385   gboolean disabled;
386 };
387
388 enum QtDemuxState
389 {
390   QTDEMUX_STATE_INITIAL,        /* Initial state (haven't got the header yet) */
391   QTDEMUX_STATE_HEADER,         /* Parsing the header */
392   QTDEMUX_STATE_MOVIE,          /* Parsing/Playing the media data */
393   QTDEMUX_STATE_BUFFER_MDAT     /* Buffering the mdat atom */
394 };
395
396 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
397 static GNode *qtdemux_tree_get_child_by_type_full (GNode * node,
398     guint32 fourcc, GstByteReader * parser);
399 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
400 static GNode *qtdemux_tree_get_sibling_by_type_full (GNode * node,
401     guint32 fourcc, GstByteReader * parser);
402
403 static GstFlowReturn qtdemux_add_fragmented_samples (GstQTDemux * qtdemux);
404
405 static GstStaticPadTemplate gst_qtdemux_sink_template =
406     GST_STATIC_PAD_TEMPLATE ("sink",
407     GST_PAD_SINK,
408     GST_PAD_ALWAYS,
409     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
410         "application/x-3gp")
411     );
412
413 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
414 GST_STATIC_PAD_TEMPLATE ("video_%u",
415     GST_PAD_SRC,
416     GST_PAD_SOMETIMES,
417     GST_STATIC_CAPS_ANY);
418
419 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
420 GST_STATIC_PAD_TEMPLATE ("audio_%u",
421     GST_PAD_SRC,
422     GST_PAD_SOMETIMES,
423     GST_STATIC_CAPS_ANY);
424
425 static GstStaticPadTemplate gst_qtdemux_subsrc_template =
426 GST_STATIC_PAD_TEMPLATE ("subtitle_%u",
427     GST_PAD_SRC,
428     GST_PAD_SOMETIMES,
429     GST_STATIC_CAPS_ANY);
430
431 #define gst_qtdemux_parent_class parent_class
432 G_DEFINE_TYPE (GstQTDemux, gst_qtdemux, GST_TYPE_ELEMENT);
433
434 static void gst_qtdemux_dispose (GObject * object);
435
436 static guint32
437 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
438     GstClockTime media_time);
439 static guint32
440 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
441     QtDemuxStream * str, gint64 media_offset);
442
443 #if 0
444 static void gst_qtdemux_set_index (GstElement * element, GstIndex * index);
445 static GstIndex *gst_qtdemux_get_index (GstElement * element);
446 #endif
447 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
448     GstStateChange transition);
449 static gboolean qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent);
450 static gboolean qtdemux_sink_activate_mode (GstPad * sinkpad,
451     GstObject * parent, GstPadMode mode, gboolean active);
452
453 static void gst_qtdemux_loop (GstPad * pad);
454 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent,
455     GstBuffer * inbuf);
456 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstObject * parent,
457     GstEvent * event);
458 static gboolean gst_qtdemux_setcaps (GstQTDemux * qtdemux, GstCaps * caps);
459 static gboolean gst_qtdemux_configure_stream (GstQTDemux * qtdemux,
460     QtDemuxStream * stream);
461 static GstFlowReturn gst_qtdemux_process_adapter (GstQTDemux * demux,
462     gboolean force);
463
464 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux,
465     const guint8 * buffer, guint length);
466 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
467     const guint8 * buffer, guint length);
468 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
469
470 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
471     QtDemuxStream * stream, GNode * esds, GstTagList * list);
472 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
473     QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
474     gchar ** codec_name);
475 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
476     QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
477     gchar ** codec_name);
478 static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
479     QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
480     gchar ** codec_name);
481 static GstCaps *qtdemux_generic_caps (GstQTDemux * qtdemux,
482     QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
483     gchar ** codec_name);
484
485 static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
486     QtDemuxStream * stream, guint32 n);
487 static GstFlowReturn qtdemux_expose_streams (GstQTDemux * qtdemux);
488 static void gst_qtdemux_stream_free (GstQTDemux * qtdemux,
489     QtDemuxStream * stream);
490 static void gst_qtdemux_stream_clear (GstQTDemux * qtdemux,
491     QtDemuxStream * stream);
492 static void gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int index);
493 static GstFlowReturn qtdemux_prepare_streams (GstQTDemux * qtdemux);
494 static void qtdemux_do_allocation (GstQTDemux * qtdemux,
495     QtDemuxStream * stream);
496
497 static gboolean qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux);
498
499 static void
500 gst_qtdemux_class_init (GstQTDemuxClass * klass)
501 {
502   GObjectClass *gobject_class;
503   GstElementClass *gstelement_class;
504
505   gobject_class = (GObjectClass *) klass;
506   gstelement_class = (GstElementClass *) klass;
507
508   parent_class = g_type_class_peek_parent (klass);
509
510   gobject_class->dispose = gst_qtdemux_dispose;
511
512   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_qtdemux_change_state);
513 #if 0
514   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_qtdemux_set_index);
515   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_qtdemux_get_index);
516 #endif
517
518   gst_tag_register_musicbrainz_tags ();
519
520   gst_element_class_add_pad_template (gstelement_class,
521       gst_static_pad_template_get (&gst_qtdemux_sink_template));
522   gst_element_class_add_pad_template (gstelement_class,
523       gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
524   gst_element_class_add_pad_template (gstelement_class,
525       gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
526   gst_element_class_add_pad_template (gstelement_class,
527       gst_static_pad_template_get (&gst_qtdemux_subsrc_template));
528   gst_element_class_set_static_metadata (gstelement_class, "QuickTime demuxer",
529       "Codec/Demuxer",
530       "Demultiplex a QuickTime file into audio and video streams",
531       "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
532
533   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
534
535 }
536
537 static void
538 gst_qtdemux_init (GstQTDemux * qtdemux)
539 {
540   qtdemux->sinkpad =
541       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
542   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
543   gst_pad_set_activatemode_function (qtdemux->sinkpad,
544       qtdemux_sink_activate_mode);
545   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
546   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
547   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
548
549   qtdemux->state = QTDEMUX_STATE_INITIAL;
550   qtdemux->pullbased = FALSE;
551   qtdemux->posted_redirect = FALSE;
552   qtdemux->neededbytes = 16;
553   qtdemux->todrop = 0;
554   qtdemux->adapter = gst_adapter_new ();
555   qtdemux->offset = 0;
556   qtdemux->first_mdat = -1;
557   qtdemux->got_moov = FALSE;
558   qtdemux->mdatoffset = -1;
559   qtdemux->mdatbuffer = NULL;
560   qtdemux->restoredata_buffer = NULL;
561   qtdemux->restoredata_offset = -1;
562   qtdemux->fragment_start = -1;
563   qtdemux->fragment_start_offset = -1;
564   qtdemux->media_caps = NULL;
565   qtdemux->exposed = FALSE;
566   qtdemux->mss_mode = FALSE;
567   qtdemux->pending_newsegment = NULL;
568   qtdemux->upstream_newsegment = FALSE;
569   qtdemux->have_group_id = FALSE;
570   qtdemux->group_id = G_MAXUINT;
571   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
572   qtdemux->flowcombiner = gst_flow_combiner_new ();
573
574   GST_OBJECT_FLAG_SET (qtdemux, GST_ELEMENT_FLAG_INDEXABLE);
575 }
576
577 static void
578 gst_qtdemux_dispose (GObject * object)
579 {
580   GstQTDemux *qtdemux = GST_QTDEMUX (object);
581
582   if (qtdemux->adapter) {
583     g_object_unref (G_OBJECT (qtdemux->adapter));
584     qtdemux->adapter = NULL;
585   }
586   gst_flow_combiner_free (qtdemux->flowcombiner);
587
588   G_OBJECT_CLASS (parent_class)->dispose (object);
589 }
590
591 static void
592 gst_qtdemux_post_no_playable_stream_error (GstQTDemux * qtdemux)
593 {
594   if (qtdemux->posted_redirect) {
595     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
596         (_("This file contains no playable streams.")),
597         ("no known streams found, a redirect message has been posted"));
598   } else {
599     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
600         (_("This file contains no playable streams.")),
601         ("no known streams found"));
602   }
603 }
604
605 static GstBuffer *
606 _gst_buffer_new_wrapped (gpointer mem, gsize size, GFreeFunc free_func)
607 {
608   return gst_buffer_new_wrapped_full (free_func ? 0 : GST_MEMORY_FLAG_READONLY,
609       mem, size, 0, size, mem, free_func);
610 }
611
612 static GstFlowReturn
613 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
614     GstBuffer ** buf)
615 {
616   GstFlowReturn flow;
617   GstMapInfo map;
618   gsize bsize;
619
620   if (G_UNLIKELY (size == 0)) {
621     GstFlowReturn ret;
622     GstBuffer *tmp = NULL;
623
624     ret = gst_qtdemux_pull_atom (qtdemux, offset, sizeof (guint32), &tmp);
625     if (ret != GST_FLOW_OK)
626       return ret;
627
628     gst_buffer_map (tmp, &map, GST_MAP_READ);
629     size = QT_UINT32 (map.data);
630     GST_DEBUG_OBJECT (qtdemux, "size 0x%08" G_GINT64_MODIFIER "x", size);
631
632     gst_buffer_unmap (tmp, &map);
633     gst_buffer_unref (tmp);
634   }
635
636   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
637   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
638     if (qtdemux->state != QTDEMUX_STATE_MOVIE && qtdemux->got_moov) {
639       /* we're pulling header but already got most interesting bits,
640        * so never mind the rest (e.g. tags) (that much) */
641       GST_WARNING_OBJECT (qtdemux, "atom has bogus size %" G_GUINT64_FORMAT,
642           size);
643       return GST_FLOW_EOS;
644     } else {
645       GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
646           (_("This file is invalid and cannot be played.")),
647           ("atom has bogus size %" G_GUINT64_FORMAT, size));
648       return GST_FLOW_ERROR;
649     }
650   }
651
652   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
653
654   if (G_UNLIKELY (flow != GST_FLOW_OK))
655     return flow;
656
657   bsize = gst_buffer_get_size (*buf);
658   /* Catch short reads - we don't want any partial atoms */
659   if (G_UNLIKELY (bsize < size)) {
660     GST_WARNING_OBJECT (qtdemux,
661         "short read: %" G_GSIZE_FORMAT " < %" G_GUINT64_FORMAT, bsize, size);
662     gst_buffer_unref (*buf);
663     *buf = NULL;
664     return GST_FLOW_EOS;
665   }
666
667   return flow;
668 }
669
670 #if 1
671 static gboolean
672 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
673     GstFormat dest_format, gint64 * dest_value)
674 {
675   gboolean res = TRUE;
676   QtDemuxStream *stream = gst_pad_get_element_private (pad);
677   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
678   gint32 index;
679
680   if (stream->subtype != FOURCC_vide) {
681     res = FALSE;
682     goto done;
683   }
684
685   switch (src_format) {
686     case GST_FORMAT_TIME:
687       switch (dest_format) {
688         case GST_FORMAT_BYTES:{
689           index = gst_qtdemux_find_index_linear (qtdemux, stream, src_value);
690           if (-1 == index)
691             return FALSE;
692
693           *dest_value = stream->samples[index].offset;
694
695           GST_DEBUG_OBJECT (qtdemux, "Format Conversion Time->Offset :%"
696               GST_TIME_FORMAT "->%" G_GUINT64_FORMAT,
697               GST_TIME_ARGS (src_value), *dest_value);
698           break;
699         }
700         default:
701           res = FALSE;
702           break;
703       }
704       break;
705     case GST_FORMAT_BYTES:
706       switch (dest_format) {
707         case GST_FORMAT_TIME:{
708           index =
709               gst_qtdemux_find_index_for_given_media_offset_linear (qtdemux,
710               stream, src_value);
711
712           if (-1 == index)
713             return FALSE;
714
715           *dest_value =
716               QTSTREAMTIME_TO_GSTTIME (stream,
717               stream->samples[index].timestamp);
718           GST_DEBUG_OBJECT (qtdemux,
719               "Format Conversion Offset->Time :%" G_GUINT64_FORMAT "->%"
720               GST_TIME_FORMAT, src_value, GST_TIME_ARGS (*dest_value));
721           break;
722         }
723         default:
724           res = FALSE;
725           break;
726       }
727       break;
728     default:
729       res = FALSE;
730   }
731
732 done:
733   gst_object_unref (qtdemux);
734
735   return res;
736 }
737 #endif
738
739 static gboolean
740 gst_qtdemux_get_duration (GstQTDemux * qtdemux, GstClockTime * duration)
741 {
742   gboolean res = TRUE;
743
744   *duration = GST_CLOCK_TIME_NONE;
745
746   if (qtdemux->duration != 0) {
747     if (qtdemux->duration != G_MAXINT64 && qtdemux->timescale != 0) {
748       *duration = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
749     }
750   }
751   return res;
752 }
753
754 static gboolean
755 gst_qtdemux_handle_src_query (GstPad * pad, GstObject * parent,
756     GstQuery * query)
757 {
758   gboolean res = FALSE;
759   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
760
761   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
762
763   switch (GST_QUERY_TYPE (query)) {
764     case GST_QUERY_POSITION:{
765       GstFormat fmt;
766
767       gst_query_parse_position (query, &fmt, NULL);
768       if (fmt == GST_FORMAT_TIME
769           && GST_CLOCK_TIME_IS_VALID (qtdemux->segment.position)) {
770         gst_query_set_position (query, GST_FORMAT_TIME,
771             qtdemux->segment.position);
772         res = TRUE;
773       }
774     }
775       break;
776     case GST_QUERY_DURATION:{
777       GstFormat fmt;
778
779       gst_query_parse_duration (query, &fmt, NULL);
780       if (fmt == GST_FORMAT_TIME) {
781         /* First try to query upstream */
782         res = gst_pad_query_default (pad, parent, query);
783         if (!res) {
784           guint64 duration;
785           if (gst_qtdemux_get_duration (qtdemux, &duration) && duration > 0) {
786             gst_query_set_duration (query, GST_FORMAT_TIME, duration);
787             res = TRUE;
788           }
789         }
790       }
791       break;
792     }
793     case GST_QUERY_CONVERT:{
794       GstFormat src_fmt, dest_fmt;
795       gint64 src_value, dest_value = 0;
796
797       gst_query_parse_convert (query, &src_fmt, &src_value, &dest_fmt, NULL);
798
799       res = gst_qtdemux_src_convert (pad,
800           src_fmt, src_value, dest_fmt, &dest_value);
801       if (res) {
802         gst_query_set_convert (query, src_fmt, src_value, dest_fmt, dest_value);
803         res = TRUE;
804       }
805       break;
806     }
807     case GST_QUERY_FORMATS:
808       gst_query_set_formats (query, 2, GST_FORMAT_TIME, GST_FORMAT_BYTES);
809       res = TRUE;
810       break;
811     case GST_QUERY_SEEKING:{
812       GstFormat fmt;
813       gboolean seekable;
814
815       /* try upstream first */
816       res = gst_pad_query_default (pad, parent, query);
817
818       if (!res) {
819         gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
820         if (fmt == GST_FORMAT_TIME) {
821           GstClockTime duration = GST_CLOCK_TIME_NONE;
822
823           gst_qtdemux_get_duration (qtdemux, &duration);
824           seekable = TRUE;
825           if (!qtdemux->pullbased) {
826             GstQuery *q;
827
828             /* we might be able with help from upstream */
829             seekable = FALSE;
830             q = gst_query_new_seeking (GST_FORMAT_BYTES);
831             if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
832               gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
833               GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
834             }
835             gst_query_unref (q);
836           }
837           gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
838           res = TRUE;
839         }
840       }
841       break;
842     }
843     case GST_QUERY_SEGMENT:
844     {
845       GstFormat format;
846       gint64 start, stop;
847
848       format = qtdemux->segment.format;
849
850       start =
851           gst_segment_to_stream_time (&qtdemux->segment, format,
852           qtdemux->segment.start);
853       if ((stop = qtdemux->segment.stop) == -1)
854         stop = qtdemux->segment.duration;
855       else
856         stop = gst_segment_to_stream_time (&qtdemux->segment, format, stop);
857
858       gst_query_set_segment (query, qtdemux->segment.rate, format, start, stop);
859       res = TRUE;
860       break;
861     }
862     default:
863       res = gst_pad_query_default (pad, parent, query);
864       break;
865   }
866
867   return res;
868 }
869
870 static void
871 gst_qtdemux_push_tags (GstQTDemux * qtdemux, QtDemuxStream * stream)
872 {
873   if (G_LIKELY (stream->pad)) {
874     GST_DEBUG_OBJECT (qtdemux, "Checking pad %s:%s for tags",
875         GST_DEBUG_PAD_NAME (stream->pad));
876
877     if (G_UNLIKELY (stream->pending_tags)) {
878       GST_DEBUG_OBJECT (qtdemux, "Sending tags %" GST_PTR_FORMAT,
879           stream->pending_tags);
880       gst_pad_push_event (stream->pad,
881           gst_event_new_tag (stream->pending_tags));
882       stream->pending_tags = NULL;
883     }
884
885     if (G_UNLIKELY (stream->send_global_tags && qtdemux->tag_list)) {
886       GST_DEBUG_OBJECT (qtdemux, "Sending global tags %" GST_PTR_FORMAT,
887           qtdemux->tag_list);
888       gst_pad_push_event (stream->pad,
889           gst_event_new_tag (gst_tag_list_ref (qtdemux->tag_list)));
890       stream->send_global_tags = FALSE;
891     }
892   }
893 }
894
895 /* push event on all source pads; takes ownership of the event */
896 static void
897 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
898 {
899   guint n;
900   gboolean has_valid_stream = FALSE;
901   GstEventType etype = GST_EVENT_TYPE (event);
902
903   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
904       GST_EVENT_TYPE_NAME (event));
905
906   for (n = 0; n < qtdemux->n_streams; n++) {
907     GstPad *pad;
908     QtDemuxStream *stream = qtdemux->streams[n];
909     GST_DEBUG_OBJECT (qtdemux, "pushing on pad %i", n);
910
911     if ((pad = stream->pad)) {
912       has_valid_stream = TRUE;
913
914       if (etype == GST_EVENT_EOS) {
915         /* let's not send twice */
916         if (stream->sent_eos)
917           continue;
918         stream->sent_eos = TRUE;
919       }
920
921       gst_pad_push_event (pad, gst_event_ref (event));
922     }
923   }
924
925   gst_event_unref (event);
926
927   /* if it is EOS and there are no pads, post an error */
928   if (!has_valid_stream && etype == GST_EVENT_EOS) {
929     gst_qtdemux_post_no_playable_stream_error (qtdemux);
930   }
931 }
932
933 /* push a pending newsegment event, if any from the streaming thread */
934 static void
935 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
936 {
937   if (qtdemux->pending_newsegment) {
938     gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
939     qtdemux->pending_newsegment = NULL;
940   }
941 }
942
943 typedef struct
944 {
945   guint64 media_time;
946 } FindData;
947
948 static gint
949 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
950 {
951   if (s1->timestamp + s1->pts_offset > *media_time)
952     return 1;
953
954   return -1;
955 }
956
957 /* find the index of the sample that includes the data for @media_time using a
958  * binary search.  Only to be called in optimized cases of linear search below.
959  *
960  * Returns the index of the sample.
961  */
962 static guint32
963 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
964     guint64 media_time)
965 {
966   QtDemuxSample *result;
967   guint32 index;
968
969   /* convert media_time to mov format */
970   media_time =
971       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
972
973   result = gst_util_array_binary_search (str->samples, str->stbl_index + 1,
974       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
975       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
976
977   if (G_LIKELY (result))
978     index = result - str->samples;
979   else
980     index = 0;
981
982   return index;
983 }
984
985
986
987 /* find the index of the sample that includes the data for @media_offset using a
988  * linear search
989  *
990  * Returns the index of the sample.
991  */
992 static guint32
993 gst_qtdemux_find_index_for_given_media_offset_linear (GstQTDemux * qtdemux,
994     QtDemuxStream * str, gint64 media_offset)
995 {
996   QtDemuxSample *result = str->samples;
997   guint32 index = 0;
998
999   if (result == NULL || str->n_samples == 0)
1000     return -1;
1001
1002   if (media_offset == result->offset)
1003     return index;
1004
1005   result++;
1006   while (index < str->n_samples - 1) {
1007     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1008       goto parse_failed;
1009
1010     if (media_offset < result->offset)
1011       break;
1012
1013     index++;
1014     result++;
1015   }
1016   return index;
1017
1018   /* ERRORS */
1019 parse_failed:
1020   {
1021     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1022     return -1;
1023   }
1024 }
1025
1026 /* find the index of the sample that includes the data for @media_time using a
1027  * linear search, and keeping in mind that not all samples may have been parsed
1028  * yet.  If possible, it will delegate to binary search.
1029  *
1030  * Returns the index of the sample.
1031  */
1032 static guint32
1033 gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
1034     GstClockTime media_time)
1035 {
1036   guint32 index = 0;
1037   guint64 mov_time;
1038   QtDemuxSample *sample;
1039
1040   /* convert media_time to mov format */
1041   mov_time =
1042       gst_util_uint64_scale_ceil (media_time, str->timescale, GST_SECOND);
1043
1044   sample = str->samples;
1045   if (mov_time == sample->timestamp + sample->pts_offset)
1046     return index;
1047
1048   /* use faster search if requested time in already parsed range */
1049   sample = str->samples + str->stbl_index;
1050   if (str->stbl_index >= 0 &&
1051       mov_time <= (sample->timestamp + sample->pts_offset))
1052     return gst_qtdemux_find_index (qtdemux, str, media_time);
1053
1054   while (index < str->n_samples - 1) {
1055     if (!qtdemux_parse_samples (qtdemux, str, index + 1))
1056       goto parse_failed;
1057
1058     sample = str->samples + index + 1;
1059     if (mov_time < (sample->timestamp + sample->pts_offset))
1060       break;
1061
1062     index++;
1063   }
1064   return index;
1065
1066   /* ERRORS */
1067 parse_failed:
1068   {
1069     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
1070     return -1;
1071   }
1072 }
1073
1074 /* find the index of the keyframe needed to decode the sample at @index
1075  * of stream @str.
1076  *
1077  * Returns the index of the keyframe.
1078  */
1079 static guint32
1080 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
1081     guint32 index)
1082 {
1083   guint32 new_index = index;
1084
1085   if (index >= str->n_samples) {
1086     new_index = str->n_samples;
1087     goto beach;
1088   }
1089
1090   /* all keyframes, return index */
1091   if (str->all_keyframe) {
1092     new_index = index;
1093     goto beach;
1094   }
1095
1096   /* else go back until we have a keyframe */
1097   while (TRUE) {
1098     if (str->samples[new_index].keyframe)
1099       break;
1100
1101     if (new_index == 0)
1102       break;
1103
1104     new_index--;
1105   }
1106
1107 beach:
1108   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
1109       "gave %u", index, new_index);
1110
1111   return new_index;
1112 }
1113
1114 /* find the segment for @time_position for @stream
1115  *
1116  * Returns the index of the segment containing @time_position.
1117  * Returns the last segment and sets the @eos variable to TRUE
1118  * if the time is beyond the end. @eos may be NULL
1119  */
1120 static guint32
1121 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
1122     GstClockTime time_position)
1123 {
1124   gint i;
1125   guint32 seg_idx;
1126
1127   GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
1128       GST_TIME_ARGS (time_position));
1129
1130   seg_idx = -1;
1131   for (i = 0; i < stream->n_segments; i++) {
1132     QtDemuxSegment *segment = &stream->segments[i];
1133
1134     GST_LOG_OBJECT (qtdemux,
1135         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
1136         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
1137
1138     /* For the last segment we include stop_time in the last segment */
1139     if (i < stream->n_segments - 1) {
1140       if (segment->time <= time_position && time_position < segment->stop_time) {
1141         GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
1142         seg_idx = i;
1143         break;
1144       }
1145     } else {
1146       /* Last segment always matches */
1147       seg_idx = i;
1148       break;
1149     }
1150   }
1151   return seg_idx;
1152 }
1153
1154 /* move the stream @str to the sample position @index.
1155  *
1156  * Updates @str->sample_index and marks discontinuity if needed.
1157  */
1158 static void
1159 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
1160     guint32 index)
1161 {
1162   /* no change needed */
1163   if (index == str->sample_index)
1164     return;
1165
1166   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
1167       str->n_samples);
1168
1169   /* position changed, we have a discont */
1170   str->sample_index = index;
1171   str->offset_in_sample = 0;
1172   /* Each time we move in the stream we store the position where we are
1173    * starting from */
1174   str->from_sample = index;
1175   str->discont = TRUE;
1176 }
1177
1178 static void
1179 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
1180     gint64 * key_time, gint64 * key_offset)
1181 {
1182   guint64 min_offset;
1183   gint64 min_byte_offset = -1;
1184   gint n;
1185
1186   min_offset = desired_time;
1187
1188   /* for each stream, find the index of the sample in the segment
1189    * and move back to the previous keyframe. */
1190   for (n = 0; n < qtdemux->n_streams; n++) {
1191     QtDemuxStream *str;
1192     guint32 index, kindex;
1193     guint32 seg_idx;
1194     GstClockTime media_start;
1195     GstClockTime media_time;
1196     GstClockTime seg_time;
1197     QtDemuxSegment *seg;
1198
1199     str = qtdemux->streams[n];
1200
1201     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
1202     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
1203
1204     /* get segment and time in the segment */
1205     seg = &str->segments[seg_idx];
1206     seg_time = desired_time - seg->time;
1207
1208     /* get the media time in the segment */
1209     media_start = seg->media_start + seg_time;
1210
1211     /* get the index of the sample with media time */
1212     index = gst_qtdemux_find_index_linear (qtdemux, str, media_start);
1213     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u"
1214         " at offset %" G_GUINT64_FORMAT,
1215         GST_TIME_ARGS (media_start), index, str->samples[index].offset);
1216
1217     /* find previous keyframe */
1218     kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
1219
1220     /* if the keyframe is at a different position, we need to update the
1221      * requested seek time */
1222     if (index != kindex) {
1223       index = kindex;
1224
1225       /* get timestamp of keyframe */
1226       media_time = QTSAMPLE_DTS (str, &str->samples[kindex]);
1227       GST_DEBUG_OBJECT (qtdemux,
1228           "keyframe at %u with time %" GST_TIME_FORMAT " at offset %"
1229           G_GUINT64_FORMAT, kindex, GST_TIME_ARGS (media_time),
1230           str->samples[kindex].offset);
1231
1232       /* keyframes in the segment get a chance to change the
1233        * desired_offset. keyframes out of the segment are
1234        * ignored. */
1235       if (media_time >= seg->media_start) {
1236         GstClockTime seg_time;
1237
1238         /* this keyframe is inside the segment, convert back to
1239          * segment time */
1240         seg_time = (media_time - seg->media_start) + seg->time;
1241         if (seg_time < min_offset)
1242           min_offset = seg_time;
1243       }
1244     }
1245
1246     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
1247       min_byte_offset = str->samples[index].offset;
1248   }
1249
1250   if (key_time)
1251     *key_time = min_offset;
1252   if (key_offset)
1253     *key_offset = min_byte_offset;
1254 }
1255
1256 static gboolean
1257 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
1258     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
1259 {
1260   gboolean res;
1261
1262   g_return_val_if_fail (format != NULL, FALSE);
1263   g_return_val_if_fail (cur != NULL, FALSE);
1264   g_return_val_if_fail (stop != NULL, FALSE);
1265
1266   if (*format == GST_FORMAT_TIME)
1267     return TRUE;
1268
1269   res = TRUE;
1270   if (cur_type != GST_SEEK_TYPE_NONE)
1271     res = gst_pad_query_convert (pad, *format, *cur, GST_FORMAT_TIME, cur);
1272   if (res && stop_type != GST_SEEK_TYPE_NONE)
1273     res = gst_pad_query_convert (pad, *format, *stop, GST_FORMAT_TIME, stop);
1274
1275   if (res)
1276     *format = GST_FORMAT_TIME;
1277
1278   return res;
1279 }
1280
1281 /* perform seek in push based mode:
1282    find BYTE position to move to based on time and delegate to upstream
1283 */
1284 static gboolean
1285 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1286 {
1287   gdouble rate;
1288   GstFormat format;
1289   GstSeekFlags flags;
1290   GstSeekType cur_type, stop_type;
1291   gint64 cur, stop, key_cur;
1292   gboolean res;
1293   gint64 byte_cur;
1294   gint64 original_stop;
1295   guint32 seqnum;
1296
1297   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
1298
1299   gst_event_parse_seek (event, &rate, &format, &flags,
1300       &cur_type, &cur, &stop_type, &stop);
1301   seqnum = gst_event_get_seqnum (event);
1302
1303   /* only forward streaming and seeking is possible */
1304   if (rate <= 0)
1305     goto unsupported_seek;
1306
1307   /* convert to TIME if needed and possible */
1308   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1309           stop_type, &stop))
1310     goto no_format;
1311
1312   /* Upstrea seek in bytes will have undefined stop, but qtdemux stores
1313    * the original stop position to use when upstream pushes the new segment
1314    * for this seek */
1315   original_stop = stop;
1316   stop = -1;
1317
1318   /* find reasonable corresponding BYTE position,
1319    * also try to mind about keyframes, since we can not go back a bit for them
1320    * later on */
1321   gst_qtdemux_adjust_seek (qtdemux, cur, &key_cur, &byte_cur);
1322
1323   if (byte_cur == -1)
1324     goto abort_seek;
1325
1326   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
1327       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
1328       stop);
1329
1330   GST_OBJECT_LOCK (qtdemux);
1331   qtdemux->seek_offset = byte_cur;
1332   if (!(flags & GST_SEEK_FLAG_KEY_UNIT)) {
1333     qtdemux->push_seek_start = cur;
1334   } else {
1335     qtdemux->push_seek_start = key_cur;
1336   }
1337
1338   if (stop_type == GST_SEEK_TYPE_NONE) {
1339     qtdemux->push_seek_stop = qtdemux->segment.stop;
1340   } else {
1341     qtdemux->push_seek_stop = original_stop;
1342   }
1343   GST_OBJECT_UNLOCK (qtdemux);
1344
1345   /* BYTE seek event */
1346   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
1347       stop_type, stop);
1348   gst_event_set_seqnum (event, seqnum);
1349   res = gst_pad_push_event (qtdemux->sinkpad, event);
1350
1351   return res;
1352
1353   /* ERRORS */
1354 abort_seek:
1355   {
1356     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
1357         "seek aborted.");
1358     return FALSE;
1359   }
1360 unsupported_seek:
1361   {
1362     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
1363     return FALSE;
1364   }
1365 no_format:
1366   {
1367     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1368     return FALSE;
1369   }
1370 }
1371
1372 /* perform the seek.
1373  *
1374  * We set all segment_indexes in the streams to unknown and
1375  * adjust the time_position to the desired position. this is enough
1376  * to trigger a segment switch in the streaming thread to start
1377  * streaming from the desired position.
1378  *
1379  * Keyframe seeking is a little more complicated when dealing with
1380  * segments. Ideally we want to move to the previous keyframe in
1381  * the segment but there might not be a keyframe in the segment. In
1382  * fact, none of the segments could contain a keyframe. We take a
1383  * practical approach: seek to the previous keyframe in the segment,
1384  * if there is none, seek to the beginning of the segment.
1385  *
1386  * Called with STREAM_LOCK
1387  */
1388 static gboolean
1389 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment,
1390     guint32 seqnum)
1391 {
1392   gint64 desired_offset;
1393   gint n;
1394
1395   desired_offset = segment->position;
1396
1397   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
1398       GST_TIME_ARGS (desired_offset));
1399
1400   /* may not have enough fragmented info to do this adjustment,
1401    * and we can't scan (and probably should not) at this time with
1402    * possibly flushing upstream */
1403   if ((segment->flags & GST_SEEK_FLAG_KEY_UNIT) && !qtdemux->fragmented) {
1404     gint64 min_offset;
1405
1406     gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
1407     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
1408         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
1409     desired_offset = min_offset;
1410   }
1411
1412   /* and set all streams to the final position */
1413   for (n = 0; n < qtdemux->n_streams; n++) {
1414     QtDemuxStream *stream = qtdemux->streams[n];
1415
1416     stream->time_position = desired_offset;
1417     stream->sample_index = -1;
1418     stream->offset_in_sample = 0;
1419     stream->segment_index = -1;
1420     stream->sent_eos = FALSE;
1421     stream->segment_seqnum = seqnum;
1422
1423     if (segment->flags & GST_SEEK_FLAG_FLUSH)
1424       gst_segment_init (&stream->segment, GST_FORMAT_TIME);
1425   }
1426   segment->position = desired_offset;
1427   segment->time = desired_offset;
1428   qtdemux->segment_base = desired_offset;
1429
1430   /* we stop at the end */
1431   if (segment->stop == -1)
1432     segment->stop = segment->duration;
1433
1434   if (qtdemux->fragmented)
1435     qtdemux->fragmented_seek_pending = TRUE;
1436
1437   return TRUE;
1438 }
1439
1440 /* do a seek in pull based mode */
1441 static gboolean
1442 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
1443 {
1444   gdouble rate;
1445   GstFormat format;
1446   GstSeekFlags flags;
1447   GstSeekType cur_type, stop_type;
1448   gint64 cur, stop;
1449   gboolean flush;
1450   gboolean update;
1451   GstSegment seeksegment;
1452   guint32 seqnum = 0;
1453   GstEvent *flush_event;
1454
1455   if (event) {
1456     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
1457
1458     gst_event_parse_seek (event, &rate, &format, &flags,
1459         &cur_type, &cur, &stop_type, &stop);
1460     seqnum = gst_event_get_seqnum (event);
1461
1462     /* we have to have a format as the segment format. Try to convert
1463      * if not. */
1464     if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
1465             stop_type, &stop))
1466       goto no_format;
1467
1468     GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
1469   } else {
1470     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
1471     flags = 0;
1472   }
1473
1474   flush = flags & GST_SEEK_FLAG_FLUSH;
1475
1476   /* stop streaming, either by flushing or by pausing the task */
1477   if (flush) {
1478     flush_event = gst_event_new_flush_start ();
1479     if (seqnum)
1480       gst_event_set_seqnum (flush_event, seqnum);
1481     /* unlock upstream pull_range */
1482     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1483     /* make sure out loop function exits */
1484     gst_qtdemux_push_event (qtdemux, flush_event);
1485   } else {
1486     /* non flushing seek, pause the task */
1487     gst_pad_pause_task (qtdemux->sinkpad);
1488   }
1489
1490   /* wait for streaming to finish */
1491   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
1492
1493   /* copy segment, we need this because we still need the old
1494    * segment when we close the current segment. */
1495   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
1496
1497   if (event) {
1498     /* configure the segment with the seek variables */
1499     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
1500     gst_segment_do_seek (&seeksegment, rate, format, flags,
1501         cur_type, cur, stop_type, stop, &update);
1502   }
1503
1504   /* now do the seek, this actually never returns FALSE */
1505   gst_qtdemux_perform_seek (qtdemux, &seeksegment, seqnum);
1506
1507   /* prepare for streaming again */
1508   if (flush) {
1509     flush_event = gst_event_new_flush_stop (TRUE);
1510     if (seqnum)
1511       gst_event_set_seqnum (flush_event, seqnum);
1512
1513     gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (flush_event));
1514     gst_qtdemux_push_event (qtdemux, flush_event);
1515   }
1516
1517   /* commit the new segment */
1518   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
1519
1520   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1521     GstMessage *msg = gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
1522         qtdemux->segment.format, qtdemux->segment.position);
1523     if (seqnum)
1524       gst_message_set_seqnum (msg, seqnum);
1525     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
1526   }
1527
1528   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
1529       qtdemux->sinkpad, NULL);
1530
1531   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
1532
1533   return TRUE;
1534
1535   /* ERRORS */
1536 no_format:
1537   {
1538     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
1539     return FALSE;
1540   }
1541 }
1542
1543 static gboolean
1544 qtdemux_ensure_index (GstQTDemux * qtdemux)
1545 {
1546   guint i;
1547
1548   GST_DEBUG_OBJECT (qtdemux, "collecting all metadata for all streams");
1549
1550   /* Build complete index */
1551   for (i = 0; i < qtdemux->n_streams; i++) {
1552     QtDemuxStream *stream = qtdemux->streams[i];
1553
1554     if (!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1))
1555       goto parse_error;
1556   }
1557   return TRUE;
1558
1559   /* ERRORS */
1560 parse_error:
1561   {
1562     GST_LOG_OBJECT (qtdemux,
1563         "Building complete index of stream %u for seeking failed!", i);
1564     return FALSE;
1565   }
1566 }
1567
1568 static gboolean
1569 gst_qtdemux_handle_src_event (GstPad * pad, GstObject * parent,
1570     GstEvent * event)
1571 {
1572   gboolean res = TRUE;
1573   GstQTDemux *qtdemux = GST_QTDEMUX (parent);
1574
1575   switch (GST_EVENT_TYPE (event)) {
1576     case GST_EVENT_SEEK:
1577     {
1578 #ifndef GST_DISABLE_GST_DEBUG
1579       GstClockTime ts = gst_util_get_timestamp ();
1580 #endif
1581
1582       if (qtdemux->upstream_newsegment && qtdemux->fragmented) {
1583         /* seek should be handled by upstream, we might need to re-download fragments */
1584         GST_DEBUG_OBJECT (qtdemux,
1585             "let upstream handle seek for fragmented playback");
1586         goto upstream;
1587       }
1588
1589       /* Build complete index for seeking;
1590        * if not a fragmented file at least */
1591       if (!qtdemux->fragmented)
1592         if (!qtdemux_ensure_index (qtdemux))
1593           goto index_failed;
1594 #ifndef GST_DISABLE_GST_DEBUG
1595       ts = gst_util_get_timestamp () - ts;
1596       GST_INFO_OBJECT (qtdemux,
1597           "Time taken to parse index %" GST_TIME_FORMAT, GST_TIME_ARGS (ts));
1598 #endif
1599     }
1600       if (qtdemux->pullbased) {
1601         res = gst_qtdemux_do_seek (qtdemux, pad, event);
1602       } else if (gst_pad_push_event (qtdemux->sinkpad, gst_event_ref (event))) {
1603         GST_DEBUG_OBJECT (qtdemux, "Upstream successfully seeked");
1604         res = TRUE;
1605       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams
1606           && !qtdemux->fragmented) {
1607         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
1608       } else {
1609         GST_DEBUG_OBJECT (qtdemux,
1610             "ignoring seek in push mode in current state");
1611         res = FALSE;
1612       }
1613       gst_event_unref (event);
1614       break;
1615     case GST_EVENT_QOS:
1616     case GST_EVENT_NAVIGATION:
1617       res = FALSE;
1618       gst_event_unref (event);
1619       break;
1620     default:
1621     upstream:
1622       res = gst_pad_event_default (pad, parent, event);
1623       break;
1624   }
1625
1626 done:
1627   return res;
1628
1629   /* ERRORS */
1630 index_failed:
1631   {
1632     GST_ERROR_OBJECT (qtdemux, "Index failed");
1633     gst_event_unref (event);
1634     res = FALSE;
1635     goto done;
1636   }
1637 }
1638
1639 /* stream/index return sample that is min/max w.r.t. byte position,
1640  * time is min/max w.r.t. time of samples,
1641  * the latter need not be time of the former sample */
1642 static void
1643 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
1644     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
1645 {
1646   gint i, n, index;
1647   gint64 time, min_time;
1648   QtDemuxStream *stream;
1649
1650   min_time = -1;
1651   stream = NULL;
1652   index = -1;
1653
1654   for (n = 0; n < qtdemux->n_streams; ++n) {
1655     QtDemuxStream *str;
1656     gint inc;
1657     gboolean set_sample;
1658
1659     str = qtdemux->streams[n];
1660     set_sample = !set;
1661
1662     if (fw) {
1663       i = 0;
1664       inc = 1;
1665     } else {
1666       i = str->n_samples - 1;
1667       inc = -1;
1668     }
1669
1670     for (; (i >= 0) && (i < str->n_samples); i += inc) {
1671       if (str->samples[i].size == 0)
1672         continue;
1673
1674       if (fw && (str->samples[i].offset < byte_pos))
1675         continue;
1676
1677       if (!fw && (str->samples[i].offset + str->samples[i].size > byte_pos))
1678         continue;
1679
1680       /* move stream to first available sample */
1681       if (set) {
1682         gst_qtdemux_move_stream (qtdemux, str, i);
1683         set_sample = TRUE;
1684       }
1685
1686       /* avoid index from sparse streams since they might be far away */
1687       if (!str->sparse) {
1688         /* determine min/max time */
1689         time = QTSAMPLE_PTS (str, &str->samples[i]);
1690         if (min_time == -1 || (!fw && time > min_time) ||
1691             (fw && time < min_time)) {
1692           min_time = time;
1693         }
1694
1695         /* determine stream with leading sample, to get its position */
1696         if (!stream ||
1697             (fw && (str->samples[i].offset < stream->samples[index].offset)) ||
1698             (!fw && (str->samples[i].offset > stream->samples[index].offset))) {
1699           stream = str;
1700           index = i;
1701         }
1702       }
1703       break;
1704     }
1705
1706     /* no sample for this stream, mark eos */
1707     if (!set_sample)
1708       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
1709   }
1710
1711   if (_time)
1712     *_time = min_time;
1713   if (_stream)
1714     *_stream = stream;
1715   if (_index)
1716     *_index = index;
1717 }
1718
1719 static QtDemuxStream *
1720 _create_stream (void)
1721 {
1722   QtDemuxStream *stream;
1723
1724   stream = g_new0 (QtDemuxStream, 1);
1725   /* new streams always need a discont */
1726   stream->discont = TRUE;
1727   /* we enable clipping for raw audio/video streams */
1728   stream->need_clip = FALSE;
1729   stream->need_process = FALSE;
1730   stream->segment_index = -1;
1731   stream->time_position = 0;
1732   stream->sample_index = -1;
1733   stream->offset_in_sample = 0;
1734   stream->new_stream = TRUE;
1735   return stream;
1736 }
1737
1738 static gboolean
1739 gst_qtdemux_setcaps (GstQTDemux * demux, GstCaps * caps)
1740 {
1741   GstStructure *structure;
1742   const gchar *variant;
1743   const GstCaps *mediacaps = NULL;
1744
1745   GST_DEBUG_OBJECT (demux, "Sink set caps: %" GST_PTR_FORMAT, caps);
1746
1747   structure = gst_caps_get_structure (caps, 0);
1748   variant = gst_structure_get_string (structure, "variant");
1749
1750   if (variant && strcmp (variant, "mss-fragmented") == 0) {
1751     QtDemuxStream *stream;
1752     const GValue *value;
1753
1754     demux->fragmented = TRUE;
1755     demux->mss_mode = TRUE;
1756
1757     if (demux->n_streams > 1) {
1758       /* can't do this, we can only renegotiate for another mss format */
1759       return FALSE;
1760     }
1761
1762     value = gst_structure_get_value (structure, "media-caps");
1763     /* create stream */
1764     if (value) {
1765       const GValue *timescale_v;
1766
1767       /* TODO update when stream changes during playback */
1768
1769       if (demux->n_streams == 0) {
1770         stream = _create_stream ();
1771         demux->streams[demux->n_streams] = stream;
1772         demux->n_streams = 1;
1773       } else {
1774         stream = demux->streams[0];
1775       }
1776
1777       timescale_v = gst_structure_get_value (structure, "timescale");
1778       if (timescale_v) {
1779         stream->timescale = g_value_get_uint64 (timescale_v);
1780       } else {
1781         /* default mss timescale */
1782         stream->timescale = 10000000;
1783       }
1784       demux->timescale = stream->timescale;
1785
1786       mediacaps = gst_value_get_caps (value);
1787       if (!stream->caps || !gst_caps_is_equal_fixed (mediacaps, stream->caps)) {
1788         GST_DEBUG_OBJECT (demux, "We have a new caps %" GST_PTR_FORMAT,
1789             mediacaps);
1790         stream->new_caps = TRUE;
1791       }
1792       gst_caps_replace (&stream->caps, (GstCaps *) mediacaps);
1793       structure = gst_caps_get_structure (mediacaps, 0);
1794       if (g_str_has_prefix (gst_structure_get_name (structure), "video")) {
1795         stream->subtype = FOURCC_vide;
1796
1797         gst_structure_get_int (structure, "width", &stream->width);
1798         gst_structure_get_int (structure, "height", &stream->height);
1799         gst_structure_get_fraction (structure, "framerate", &stream->fps_n,
1800             &stream->fps_d);
1801       } else if (g_str_has_prefix (gst_structure_get_name (structure), "audio")) {
1802         gint rate = 0;
1803         stream->subtype = FOURCC_soun;
1804         gst_structure_get_int (structure, "channels", &stream->n_channels);
1805         gst_structure_get_int (structure, "rate", &rate);
1806         stream->rate = rate;
1807       }
1808     }
1809     gst_caps_replace (&demux->media_caps, (GstCaps *) mediacaps);
1810   } else {
1811     demux->mss_mode = FALSE;
1812   }
1813
1814   return TRUE;
1815 }
1816
1817 static void
1818 gst_qtdemux_reset (GstQTDemux * qtdemux, gboolean hard)
1819 {
1820   gint n;
1821
1822   GST_DEBUG_OBJECT (qtdemux, "Resetting demux");
1823   gst_pad_stop_task (qtdemux->sinkpad);
1824
1825   if (hard || qtdemux->upstream_newsegment) {
1826     qtdemux->state = QTDEMUX_STATE_INITIAL;
1827     qtdemux->neededbytes = 16;
1828     qtdemux->todrop = 0;
1829     qtdemux->pullbased = FALSE;
1830     qtdemux->posted_redirect = FALSE;
1831     qtdemux->first_mdat = -1;
1832     qtdemux->header_size = 0;
1833     qtdemux->mdatoffset = -1;
1834     qtdemux->restoredata_offset = -1;
1835     if (qtdemux->mdatbuffer)
1836       gst_buffer_unref (qtdemux->mdatbuffer);
1837     if (qtdemux->restoredata_buffer)
1838       gst_buffer_unref (qtdemux->restoredata_buffer);
1839     qtdemux->mdatbuffer = NULL;
1840     qtdemux->restoredata_buffer = NULL;
1841     qtdemux->mdatleft = 0;
1842     if (qtdemux->comp_brands)
1843       gst_buffer_unref (qtdemux->comp_brands);
1844     qtdemux->comp_brands = NULL;
1845     qtdemux->last_moov_offset = -1;
1846     if (qtdemux->moov_node)
1847       g_node_destroy (qtdemux->moov_node);
1848     qtdemux->moov_node = NULL;
1849     qtdemux->moov_node_compressed = NULL;
1850     if (qtdemux->tag_list)
1851       gst_mini_object_unref (GST_MINI_OBJECT_CAST (qtdemux->tag_list));
1852     qtdemux->tag_list = NULL;
1853 #if 0
1854     if (qtdemux->element_index)
1855       gst_object_unref (qtdemux->element_index);
1856     qtdemux->element_index = NULL;
1857 #endif
1858     qtdemux->major_brand = 0;
1859     if (qtdemux->pending_newsegment)
1860       gst_event_unref (qtdemux->pending_newsegment);
1861     qtdemux->pending_newsegment = NULL;
1862     qtdemux->upstream_newsegment = FALSE;
1863     qtdemux->upstream_seekable = FALSE;
1864     qtdemux->upstream_size = 0;
1865
1866     qtdemux->fragment_start = -1;
1867     qtdemux->fragment_start_offset = -1;
1868     qtdemux->duration = 0;
1869     qtdemux->moof_offset = 0;
1870     qtdemux->chapters_track_id = 0;
1871     qtdemux->have_group_id = FALSE;
1872     qtdemux->group_id = G_MAXUINT;
1873   }
1874   qtdemux->offset = 0;
1875   gst_adapter_clear (qtdemux->adapter);
1876   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
1877   qtdemux->segment_base = 0;
1878
1879   if (hard) {
1880     for (n = 0; n < qtdemux->n_streams; n++) {
1881       gst_qtdemux_stream_free (qtdemux, qtdemux->streams[n]);
1882       qtdemux->streams[n] = NULL;
1883     }
1884     qtdemux->n_streams = 0;
1885     qtdemux->n_video_streams = 0;
1886     qtdemux->n_audio_streams = 0;
1887     qtdemux->n_sub_streams = 0;
1888     qtdemux->exposed = FALSE;
1889     qtdemux->fragmented = FALSE;
1890     qtdemux->mss_mode = FALSE;
1891     gst_caps_replace (&qtdemux->media_caps, NULL);
1892     qtdemux->timescale = 0;
1893     qtdemux->got_moov = FALSE;
1894   } else if (qtdemux->mss_mode) {
1895     for (n = 0; n < qtdemux->n_streams; n++)
1896       gst_qtdemux_stream_clear (qtdemux, qtdemux->streams[n]);
1897   } else {
1898     for (n = 0; n < qtdemux->n_streams; n++) {
1899       qtdemux->streams[n]->sent_eos = FALSE;
1900       qtdemux->streams[n]->segment_seqnum = 0;
1901       qtdemux->streams[n]->time_position = 0;
1902     }
1903   }
1904 }
1905
1906 static gboolean
1907 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstObject * parent,
1908     GstEvent * event)
1909 {
1910   GstQTDemux *demux = GST_QTDEMUX (parent);
1911   gboolean res = TRUE;
1912
1913   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
1914
1915   switch (GST_EVENT_TYPE (event)) {
1916     case GST_EVENT_SEGMENT:
1917     {
1918       gint64 offset = 0;
1919       QtDemuxStream *stream;
1920       gint idx;
1921       GstSegment segment;
1922       GstEvent *segment_event;
1923
1924       /* some debug output */
1925       gst_event_copy_segment (event, &segment);
1926       GST_DEBUG_OBJECT (demux, "received newsegment %" GST_SEGMENT_FORMAT,
1927           &segment);
1928
1929       if (segment.format == GST_FORMAT_TIME) {
1930         GST_DEBUG_OBJECT (demux, "new pending_newsegment");
1931         gst_event_replace (&demux->pending_newsegment, event);
1932         demux->upstream_newsegment = TRUE;
1933       } else {
1934         GST_DEBUG_OBJECT (demux, "Not storing upstream newsegment, "
1935             "not in time format");
1936
1937         /* chain will send initial newsegment after pads have been added */
1938         if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
1939           GST_DEBUG_OBJECT (demux, "still starting, eating event");
1940           goto exit;
1941         }
1942       }
1943
1944       /* check if this matches a time seek we received previously
1945        * FIXME for backwards compatibility reasons we use the
1946        * seek_offset here to compare. In the future we might want to
1947        * change this to use the seqnum as it uniquely should identify
1948        * the segment that corresponds to the seek. */
1949       GST_DEBUG_OBJECT (demux, "Stored seek offset: %" G_GINT64_FORMAT
1950           ", received segment offset %" G_GINT64_FORMAT,
1951           demux->seek_offset, segment.start);
1952       if (segment.format == GST_FORMAT_BYTES
1953           && demux->seek_offset == segment.start) {
1954         GST_OBJECT_LOCK (demux);
1955         offset = segment.start;
1956
1957         segment.format = GST_FORMAT_TIME;
1958         segment.start = demux->push_seek_start;
1959         segment.stop = demux->push_seek_stop;
1960         GST_DEBUG_OBJECT (demux, "Replaced segment with stored seek "
1961             "segment %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
1962             GST_TIME_ARGS (segment.start), GST_TIME_ARGS (segment.stop));
1963         GST_OBJECT_UNLOCK (demux);
1964       }
1965
1966       /* we only expect a BYTE segment, e.g. following a seek */
1967       if (segment.format == GST_FORMAT_BYTES) {
1968         if (GST_CLOCK_TIME_IS_VALID (segment.start)) {
1969           offset = segment.start;
1970
1971           gst_qtdemux_find_sample (demux, segment.start, TRUE, FALSE, NULL,
1972               NULL, (gint64 *) & segment.start);
1973           if ((gint64) segment.start < 0)
1974             segment.start = 0;
1975         }
1976         if (GST_CLOCK_TIME_IS_VALID (segment.stop)) {
1977           gst_qtdemux_find_sample (demux, segment.stop, FALSE, FALSE, NULL,
1978               NULL, (gint64 *) & segment.stop);
1979           /* keyframe seeking should already arrange for start >= stop,
1980            * but make sure in other rare cases */
1981           segment.stop = MAX (segment.stop, segment.start);
1982         }
1983       } else if (segment.format == GST_FORMAT_TIME) {
1984         /* NOP */
1985 #if 0
1986         gst_qtdemux_push_event (demux, gst_event_ref (event));
1987         gst_event_new_new_segment_full (segment.update, segment.rate,
1988             segment.arate, GST_FORMAT_TIME, segment.start, segment.stop,
1989             segment.start);
1990         gst_adapter_clear (demux->adapter);
1991         demux->neededbytes = 16;
1992         goto exit;
1993 #endif
1994       } else {
1995         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
1996         goto exit;
1997       }
1998
1999       /* accept upstream's notion of segment and distribute along */
2000       segment.format = GST_FORMAT_TIME;
2001       segment.position = segment.time = segment.start;
2002       segment.duration = demux->segment.duration;
2003       segment.base = gst_segment_to_running_time (&demux->segment,
2004           GST_FORMAT_TIME, demux->segment.position);
2005
2006       gst_segment_copy_into (&segment, &demux->segment);
2007       GST_DEBUG_OBJECT (demux, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
2008       segment_event = gst_event_new_segment (&segment);
2009       gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
2010       gst_qtdemux_push_event (demux, segment_event);
2011
2012       /* clear leftover in current segment, if any */
2013       gst_adapter_clear (demux->adapter);
2014       /* set up streaming thread */
2015       gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
2016       demux->offset = offset;
2017       if (stream) {
2018         demux->todrop = stream->samples[idx].offset - offset;
2019         demux->neededbytes = demux->todrop + stream->samples[idx].size;
2020       } else {
2021         /* set up for EOS */
2022         if (demux->upstream_newsegment) {
2023           demux->neededbytes = 16;
2024         } else {
2025           demux->neededbytes = -1;
2026         }
2027         demux->todrop = 0;
2028       }
2029     exit:
2030       gst_event_unref (event);
2031       res = TRUE;
2032       goto drop;
2033     }
2034     case GST_EVENT_FLUSH_STOP:
2035     {
2036       guint64 dur;
2037
2038       dur = demux->segment.duration;
2039       gst_qtdemux_reset (demux, FALSE);
2040       demux->segment.duration = dur;
2041       break;
2042     }
2043     case GST_EVENT_EOS:
2044       /* If we are in push mode, and get an EOS before we've seen any streams,
2045        * then error out - we have nowhere to send the EOS */
2046       if (!demux->pullbased) {
2047         gint i;
2048         gboolean has_valid_stream = FALSE;
2049         for (i = 0; i < demux->n_streams; i++) {
2050           if (demux->streams[i]->pad != NULL) {
2051             has_valid_stream = TRUE;
2052             break;
2053           }
2054         }
2055         if (!has_valid_stream)
2056           gst_qtdemux_post_no_playable_stream_error (demux);
2057         else {
2058           GST_DEBUG_OBJECT (demux, "Data still available after EOS: %u",
2059               (guint) gst_adapter_available (demux->adapter));
2060           if (gst_qtdemux_process_adapter (demux, TRUE) != GST_FLOW_OK) {
2061             res = FALSE;
2062           }
2063         }
2064       }
2065       break;
2066     case GST_EVENT_CAPS:{
2067       GstCaps *caps = NULL;
2068
2069       gst_event_parse_caps (event, &caps);
2070       gst_qtdemux_setcaps (demux, caps);
2071       res = TRUE;
2072       gst_event_unref (event);
2073       goto drop;
2074     }
2075     default:
2076       break;
2077   }
2078
2079   res = gst_pad_event_default (demux->sinkpad, parent, event) & res;
2080
2081 drop:
2082   return res;
2083 }
2084
2085 #if 0
2086 static void
2087 gst_qtdemux_set_index (GstElement * element, GstIndex * index)
2088 {
2089   GstQTDemux *demux = GST_QTDEMUX (element);
2090
2091   GST_OBJECT_LOCK (demux);
2092   if (demux->element_index)
2093     gst_object_unref (demux->element_index);
2094   if (index) {
2095     demux->element_index = gst_object_ref (index);
2096   } else {
2097     demux->element_index = NULL;
2098   }
2099   GST_OBJECT_UNLOCK (demux);
2100   /* object lock might be taken again */
2101   if (index)
2102     gst_index_get_writer_id (index, GST_OBJECT (element), &demux->index_id);
2103   GST_DEBUG_OBJECT (demux, "Set index %" GST_PTR_FORMAT "for writer id %d",
2104       demux->element_index, demux->index_id);
2105 }
2106
2107 static GstIndex *
2108 gst_qtdemux_get_index (GstElement * element)
2109 {
2110   GstIndex *result = NULL;
2111   GstQTDemux *demux = GST_QTDEMUX (element);
2112
2113   GST_OBJECT_LOCK (demux);
2114   if (demux->element_index)
2115     result = gst_object_ref (demux->element_index);
2116   GST_OBJECT_UNLOCK (demux);
2117
2118   GST_DEBUG_OBJECT (demux, "Returning index %" GST_PTR_FORMAT, result);
2119
2120   return result;
2121 }
2122 #endif
2123
2124 static void
2125 gst_qtdemux_stbl_free (QtDemuxStream * stream)
2126 {
2127   g_free ((gpointer) stream->stco.data);
2128   stream->stco.data = NULL;
2129   g_free ((gpointer) stream->stsz.data);
2130   stream->stsz.data = NULL;
2131   g_free ((gpointer) stream->stsc.data);
2132   stream->stsc.data = NULL;
2133   g_free ((gpointer) stream->stts.data);
2134   stream->stts.data = NULL;
2135   g_free ((gpointer) stream->stss.data);
2136   stream->stss.data = NULL;
2137   g_free ((gpointer) stream->stps.data);
2138   stream->stps.data = NULL;
2139   g_free ((gpointer) stream->ctts.data);
2140   stream->ctts.data = NULL;
2141 }
2142
2143 static void
2144 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
2145 {
2146   if (stream->allocator)
2147     gst_object_unref (stream->allocator);
2148   while (stream->buffers) {
2149     gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
2150     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
2151   }
2152   if (stream->rgb8_palette) {
2153     gst_memory_unref (stream->rgb8_palette);
2154     stream->rgb8_palette = NULL;
2155   }
2156   g_free (stream->samples);
2157   stream->samples = NULL;
2158   g_free (stream->segments);
2159   stream->segments = NULL;
2160   if (stream->pending_tags)
2161     gst_tag_list_unref (stream->pending_tags);
2162   stream->pending_tags = NULL;
2163   g_free (stream->redirect_uri);
2164   stream->redirect_uri = NULL;
2165   /* free stbl sub-atoms */
2166   gst_qtdemux_stbl_free (stream);
2167   /* fragments */
2168   g_free (stream->ra_entries);
2169   stream->ra_entries = NULL;
2170   stream->n_ra_entries = 0;
2171
2172   stream->sent_eos = FALSE;
2173   stream->segment_index = -1;
2174   stream->time_position = 0;
2175   stream->sample_index = -1;
2176   stream->stbl_index = -1;
2177   stream->n_samples = 0;
2178   stream->sparse = FALSE;
2179 }
2180
2181 static void
2182 gst_qtdemux_stream_free (GstQTDemux * qtdemux, QtDemuxStream * stream)
2183 {
2184   gst_qtdemux_stream_clear (qtdemux, stream);
2185   if (stream->caps)
2186     gst_caps_unref (stream->caps);
2187   stream->caps = NULL;
2188   if (stream->pad) {
2189     gst_element_remove_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
2190     gst_flow_combiner_remove_pad (qtdemux->flowcombiner, stream->pad);
2191   }
2192   g_free (stream);
2193 }
2194
2195 static void
2196 gst_qtdemux_remove_stream (GstQTDemux * qtdemux, int i)
2197 {
2198   g_assert (i >= 0 && i < qtdemux->n_streams && qtdemux->streams[i] != NULL);
2199
2200   gst_qtdemux_stream_free (qtdemux, qtdemux->streams[i]);
2201   qtdemux->streams[i] = qtdemux->streams[qtdemux->n_streams - 1];
2202   qtdemux->streams[qtdemux->n_streams - 1] = NULL;
2203   qtdemux->n_streams--;
2204 }
2205
2206 static GstStateChangeReturn
2207 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
2208 {
2209   GstQTDemux *qtdemux = GST_QTDEMUX (element);
2210   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
2211
2212   switch (transition) {
2213     case GST_STATE_CHANGE_PAUSED_TO_READY:
2214       break;
2215     default:
2216       break;
2217   }
2218
2219   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2220
2221   switch (transition) {
2222     case GST_STATE_CHANGE_PAUSED_TO_READY:{
2223       gst_qtdemux_reset (qtdemux, TRUE);
2224       break;
2225     }
2226     default:
2227       break;
2228   }
2229
2230   return result;
2231 }
2232
2233 static void
2234 qtdemux_parse_ftyp (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2235 {
2236   /* counts as header data */
2237   qtdemux->header_size += length;
2238
2239   /* only consider at least a sufficiently complete ftyp atom */
2240   if (length >= 20) {
2241     GstBuffer *buf;
2242
2243     qtdemux->major_brand = QT_FOURCC (buffer + 8);
2244     GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
2245         GST_FOURCC_ARGS (qtdemux->major_brand));
2246     buf = qtdemux->comp_brands = gst_buffer_new_and_alloc (length - 16);
2247     gst_buffer_fill (buf, 0, buffer + 16, length - 16);
2248   }
2249 }
2250
2251 static void
2252 qtdemux_handle_xmp_taglist (GstQTDemux * qtdemux, GstTagList * taglist)
2253 {
2254   /* Strip out bogus fields */
2255   if (taglist) {
2256     gst_tag_list_remove_tag (taglist, GST_TAG_VIDEO_CODEC);
2257
2258     GST_DEBUG_OBJECT (qtdemux, "Found XMP tags %" GST_PTR_FORMAT, taglist);
2259
2260     if (qtdemux->tag_list) {
2261       /* prioritize native tags using _KEEP mode */
2262       gst_tag_list_insert (qtdemux->tag_list, taglist, GST_TAG_MERGE_KEEP);
2263       gst_tag_list_unref (taglist);
2264     } else
2265       qtdemux->tag_list = taglist;
2266   }
2267 }
2268
2269 static void
2270 qtdemux_parse_uuid (GstQTDemux * qtdemux, const guint8 * buffer, gint length)
2271 {
2272   static guint8 xmp_uuid[] = { 0xBE, 0x7A, 0xCF, 0xCB,
2273     0x97, 0xA9, 0x42, 0xE8,
2274     0x9C, 0x71, 0x99, 0x94,
2275     0x91, 0xE3, 0xAF, 0xAC
2276   };
2277   static guint8 playready_uuid[] = {
2278     0xd0, 0x8a, 0x4f, 0x18, 0x10, 0xf3, 0x4a, 0x82,
2279     0xb6, 0xc8, 0x32, 0xd8, 0xab, 0xa1, 0x83, 0xd3
2280   };
2281   guint offset;
2282
2283   /* counts as header data */
2284   qtdemux->header_size += length;
2285
2286   offset = (QT_UINT32 (buffer) == 0) ? 16 : 8;
2287
2288   if (length <= offset + 16) {
2289     GST_DEBUG_OBJECT (qtdemux, "uuid atom is too short, skipping");
2290     return;
2291   }
2292
2293   if (memcmp (buffer + offset, xmp_uuid, 16) == 0) {
2294     GstBuffer *buf;
2295     GstTagList *taglist;
2296
2297     buf = _gst_buffer_new_wrapped ((guint8 *) buffer + offset + 16,
2298         length - offset - 16, NULL);
2299     taglist = gst_tag_list_from_xmp_buffer (buf);
2300     gst_buffer_unref (buf);
2301
2302     qtdemux_handle_xmp_taglist (qtdemux, taglist);
2303
2304   } else if (memcmp (buffer + offset, playready_uuid, 16) == 0) {
2305     int len;
2306     const gunichar2 *s_utf16;
2307     char *contents;
2308
2309     len = GST_READ_UINT16_LE (buffer + offset + 0x30);
2310     s_utf16 = (const gunichar2 *) (buffer + offset + 0x32);
2311     contents = g_utf16_to_utf8 (s_utf16, len / 2, NULL, NULL, NULL);
2312     GST_ERROR_OBJECT (qtdemux, "contents: %s", contents);
2313
2314     g_free (contents);
2315
2316     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT,
2317         (_("Cannot play stream because it is encrypted with PlayReady DRM.")),
2318         (NULL));
2319   } else {
2320     GST_DEBUG_OBJECT (qtdemux, "Ignoring unknown uuid: %08x-%08x-%08x-%08x",
2321         GST_READ_UINT32_LE (buffer + offset),
2322         GST_READ_UINT32_LE (buffer + offset + 4),
2323         GST_READ_UINT32_LE (buffer + offset + 8),
2324         GST_READ_UINT32_LE (buffer + offset + 12));
2325   }
2326 }
2327
2328 /* caller verifies at least 8 bytes in buf */
2329 static void
2330 extract_initial_length_and_fourcc (const guint8 * data, guint size,
2331     guint64 * plength, guint32 * pfourcc)
2332 {
2333   guint64 length;
2334   guint32 fourcc;
2335
2336   length = QT_UINT32 (data);
2337   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2338   fourcc = QT_FOURCC (data + 4);
2339   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
2340
2341   if (length == 0) {
2342     length = G_MAXUINT32;
2343   } else if (length == 1 && size >= 16) {
2344     /* this means we have an extended size, which is the 64 bit value of
2345      * the next 8 bytes */
2346     length = QT_UINT64 (data + 8);
2347     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
2348   }
2349
2350   if (plength)
2351     *plength = length;
2352   if (pfourcc)
2353     *pfourcc = fourcc;
2354 }
2355
2356 static gboolean
2357 qtdemux_parse_mehd (GstQTDemux * qtdemux, GstByteReader * br)
2358 {
2359   guint32 version = 0;
2360   GstClockTime duration = 0;
2361
2362   if (!gst_byte_reader_get_uint32_be (br, &version))
2363     goto failed;
2364
2365   version >>= 24;
2366   if (version == 1) {
2367     if (!gst_byte_reader_get_uint64_be (br, &duration))
2368       goto failed;
2369   } else {
2370     guint32 dur = 0;
2371
2372     if (!gst_byte_reader_get_uint32_be (br, &dur))
2373       goto failed;
2374     duration = dur;
2375   }
2376
2377   GST_INFO_OBJECT (qtdemux, "mehd duration: %" G_GUINT64_FORMAT, duration);
2378   qtdemux->duration = duration;
2379
2380   return TRUE;
2381
2382 failed:
2383   {
2384     GST_DEBUG_OBJECT (qtdemux, "parsing mehd failed");
2385     return FALSE;
2386   }
2387 }
2388
2389 static gboolean
2390 qtdemux_parse_trex (GstQTDemux * qtdemux, QtDemuxStream * stream,
2391     guint32 * ds_duration, guint32 * ds_size, guint32 * ds_flags)
2392 {
2393   if (!stream->parsed_trex && qtdemux->moov_node) {
2394     GNode *mvex, *trex;
2395     GstByteReader trex_data;
2396
2397     mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
2398     if (mvex) {
2399       trex = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_trex,
2400           &trex_data);
2401       while (trex) {
2402         guint32 id = 0, dur = 0, size = 0, flags = 0, dummy = 0;
2403
2404         /* skip version/flags */
2405         if (!gst_byte_reader_skip (&trex_data, 4))
2406           goto next;
2407         if (!gst_byte_reader_get_uint32_be (&trex_data, &id))
2408           goto next;
2409         if (id != stream->track_id)
2410           goto next;
2411         /* sample description index; ignore */
2412         if (!gst_byte_reader_get_uint32_be (&trex_data, &dummy))
2413           goto next;
2414         if (!gst_byte_reader_get_uint32_be (&trex_data, &dur))
2415           goto next;
2416         if (!gst_byte_reader_get_uint32_be (&trex_data, &size))
2417           goto next;
2418         if (!gst_byte_reader_get_uint32_be (&trex_data, &flags))
2419           goto next;
2420
2421         GST_DEBUG_OBJECT (qtdemux, "fragment defaults for stream %d; "
2422             "duration %d,  size %d, flags 0x%x", stream->track_id,
2423             dur, size, flags);
2424
2425         stream->parsed_trex = TRUE;
2426         stream->def_sample_duration = dur;
2427         stream->def_sample_size = size;
2428         stream->def_sample_flags = flags;
2429
2430       next:
2431         /* iterate all siblings */
2432         trex = qtdemux_tree_get_sibling_by_type_full (trex, FOURCC_trex,
2433             &trex_data);
2434       }
2435     }
2436   }
2437
2438   *ds_duration = stream->def_sample_duration;
2439   *ds_size = stream->def_sample_size;
2440   *ds_flags = stream->def_sample_flags;
2441
2442   /* even then, above values are better than random ... */
2443   if (G_UNLIKELY (!stream->parsed_trex)) {
2444     GST_WARNING_OBJECT (qtdemux,
2445         "failed to find fragment defaults for stream %d", stream->track_id);
2446     return FALSE;
2447   }
2448
2449   return TRUE;
2450 }
2451
2452 /* This method should be called whenever a more accurate duration might
2453  * have been found. It will update all relevant variables if/where needed
2454  */
2455 static void
2456 check_update_duration (GstQTDemux * qtdemux, GstClockTime duration)
2457 {
2458   guint i;
2459   guint64 movdur;
2460   GstClockTime prevdur;
2461
2462   movdur = GSTTIME_TO_QTTIME (qtdemux, duration);
2463
2464   if (movdur > qtdemux->duration) {
2465     prevdur = QTTIME_TO_GSTTIME (qtdemux, qtdemux->duration);
2466     GST_DEBUG_OBJECT (qtdemux,
2467         "Updating total duration to %" GST_TIME_FORMAT " was %" GST_TIME_FORMAT,
2468         GST_TIME_ARGS (duration), GST_TIME_ARGS (prevdur));
2469     qtdemux->duration = movdur;
2470     GST_DEBUG_OBJECT (qtdemux,
2471         "qtdemux->segment.duration: %" GST_TIME_FORMAT " .stop: %"
2472         GST_TIME_FORMAT, GST_TIME_ARGS (qtdemux->segment.duration),
2473         GST_TIME_ARGS (qtdemux->segment.stop));
2474     if (qtdemux->segment.duration == prevdur) {
2475       /* If the current segment has duration/stop identical to previous duration
2476        * update them also (because they were set at that point in time with
2477        * the wrong duration */
2478       /* We convert the value *from* the timescale version to avoid rounding errors */
2479       GstClockTime fixeddur = QTTIME_TO_GSTTIME (qtdemux, movdur);
2480       GST_DEBUG_OBJECT (qtdemux, "Updated segment.duration and segment.stop");
2481       qtdemux->segment.duration = fixeddur;
2482       qtdemux->segment.stop = fixeddur;
2483     }
2484   }
2485   for (i = 0; i < qtdemux->n_streams; i++) {
2486     QtDemuxStream *stream = qtdemux->streams[i];
2487     if (stream) {
2488       movdur = GSTTIME_TO_QTSTREAMTIME (stream, duration);
2489       if (movdur > stream->duration) {
2490         GST_DEBUG_OBJECT (qtdemux,
2491             "Updating stream #%d duration to %" GST_TIME_FORMAT, i,
2492             GST_TIME_ARGS (duration));
2493         stream->duration = movdur;
2494         if (stream->dummy_segment) {
2495           /* Update all dummy values to new duration */
2496           stream->segments[0].stop_time = duration;
2497           stream->segments[0].duration = duration;
2498           stream->segments[0].media_stop = duration;
2499         }
2500       }
2501     }
2502   }
2503 }
2504
2505 static gboolean
2506 qtdemux_parse_trun (GstQTDemux * qtdemux, GstByteReader * trun,
2507     QtDemuxStream * stream, guint32 d_sample_duration, guint32 d_sample_size,
2508     guint32 d_sample_flags, gint64 moof_offset, gint64 moof_length,
2509     gint64 * base_offset, gint64 * running_offset, gint64 decode_ts)
2510 {
2511   GstClockTime gst_ts = GST_CLOCK_TIME_NONE;
2512   guint64 timestamp;
2513   gint32 data_offset = 0;
2514   guint32 flags = 0, first_flags = 0, samples_count = 0;
2515   gint i;
2516   guint8 *data;
2517   guint entry_size, dur_offset, size_offset, flags_offset = 0, ct_offset = 0;
2518   QtDemuxSample *sample;
2519   gboolean ismv = FALSE;
2520
2521   GST_LOG_OBJECT (qtdemux, "parsing trun stream %d; "
2522       "default dur %d, size %d, flags 0x%x, base offset %" G_GINT64_FORMAT ", "
2523       "decode ts %" G_GINT64_FORMAT, stream->track_id, d_sample_duration,
2524       d_sample_size, d_sample_flags, *base_offset, decode_ts);
2525
2526   if (stream->pending_seek && moof_offset < stream->pending_seek->moof_offset) {
2527     GST_INFO_OBJECT (stream->pad, "skipping trun before seek target fragment");
2528     return TRUE;
2529   }
2530
2531   /* presence of stss or not can't really tell us much,
2532    * and flags and so on tend to be marginally reliable in these files */
2533   if (stream->subtype == FOURCC_soun) {
2534     GST_DEBUG_OBJECT (qtdemux,
2535         "sound track in fragmented file; marking all keyframes");
2536     stream->all_keyframe = TRUE;
2537   }
2538
2539   if (!gst_byte_reader_skip (trun, 1) ||
2540       !gst_byte_reader_get_uint24_be (trun, &flags))
2541     goto fail;
2542
2543   if (!gst_byte_reader_get_uint32_be (trun, &samples_count))
2544     goto fail;
2545
2546   if (flags & TR_DATA_OFFSET) {
2547     /* note this is really signed */
2548     if (!gst_byte_reader_get_int32_be (trun, &data_offset))
2549       goto fail;
2550     GST_LOG_OBJECT (qtdemux, "trun data offset %d", data_offset);
2551     /* default base offset = first byte of moof */
2552     if (*base_offset == -1) {
2553       GST_LOG_OBJECT (qtdemux, "base_offset at moof");
2554       *base_offset = moof_offset;
2555     }
2556     *running_offset = *base_offset + data_offset;
2557   } else {
2558     /* if no offset at all, that would mean data starts at moof start,
2559      * which is a bit wrong and is ismv crappy way, so compensate
2560      * assuming data is in mdat following moof */
2561     if (*base_offset == -1) {
2562       *base_offset = moof_offset + moof_length + 8;
2563       GST_LOG_OBJECT (qtdemux, "base_offset assumed in mdat after moof");
2564       ismv = TRUE;
2565     }
2566     if (*running_offset == -1)
2567       *running_offset = *base_offset;
2568   }
2569
2570   GST_LOG_OBJECT (qtdemux, "running offset now %" G_GINT64_FORMAT,
2571       *running_offset);
2572   GST_LOG_OBJECT (qtdemux, "trun offset %d, flags 0x%x, entries %d",
2573       data_offset, flags, samples_count);
2574
2575   if (flags & TR_FIRST_SAMPLE_FLAGS) {
2576     if (G_UNLIKELY (flags & TR_SAMPLE_FLAGS)) {
2577       GST_DEBUG_OBJECT (qtdemux,
2578           "invalid flags; SAMPLE and FIRST_SAMPLE present, discarding latter");
2579       flags ^= TR_FIRST_SAMPLE_FLAGS;
2580     } else {
2581       if (!gst_byte_reader_get_uint32_be (trun, &first_flags))
2582         goto fail;
2583       GST_LOG_OBJECT (qtdemux, "first flags: 0x%x", first_flags);
2584     }
2585   }
2586
2587   /* FIXME ? spec says other bits should also be checked to determine
2588    * entry size (and prefix size for that matter) */
2589   entry_size = 0;
2590   dur_offset = size_offset = 0;
2591   if (flags & TR_SAMPLE_DURATION) {
2592     GST_LOG_OBJECT (qtdemux, "entry duration present");
2593     dur_offset = entry_size;
2594     entry_size += 4;
2595   }
2596   if (flags & TR_SAMPLE_SIZE) {
2597     GST_LOG_OBJECT (qtdemux, "entry size present");
2598     size_offset = entry_size;
2599     entry_size += 4;
2600   }
2601   if (flags & TR_SAMPLE_FLAGS) {
2602     GST_LOG_OBJECT (qtdemux, "entry flags present");
2603     flags_offset = entry_size;
2604     entry_size += 4;
2605   }
2606   if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2607     GST_LOG_OBJECT (qtdemux, "entry ct offset present");
2608     ct_offset = entry_size;
2609     entry_size += 4;
2610   }
2611
2612   if (!qt_atom_parser_has_chunks (trun, samples_count, entry_size))
2613     goto fail;
2614   data = (guint8 *) gst_byte_reader_peek_data_unchecked (trun);
2615
2616   if (stream->n_samples >=
2617       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample))
2618     goto index_too_big;
2619
2620   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
2621       stream->n_samples, (guint) sizeof (QtDemuxSample),
2622       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
2623
2624   /* create a new array of samples if it's the first sample parsed */
2625   if (stream->n_samples == 0)
2626     stream->samples = g_try_new0 (QtDemuxSample, samples_count);
2627   /* or try to reallocate it with space enough to insert the new samples */
2628   else
2629     stream->samples = g_try_renew (QtDemuxSample, stream->samples,
2630         stream->n_samples + samples_count);
2631   if (stream->samples == NULL)
2632     goto out_of_memory;
2633
2634   if (qtdemux->fragment_start != -1) {
2635     timestamp = GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->fragment_start);
2636     qtdemux->fragment_start = -1;
2637   } else {
2638     if (G_UNLIKELY (stream->n_samples == 0)) {
2639       if (decode_ts > 0) {
2640         timestamp = decode_ts;
2641       } else if (stream->pending_seek != NULL) {
2642         /* if we don't have a timestamp from a tfdt box, we'll use the one
2643          * from the mfra seek table */
2644         GST_INFO_OBJECT (stream->pad, "pending seek ts = %" GST_TIME_FORMAT,
2645             GST_TIME_ARGS (stream->pending_seek->ts));
2646
2647         /* FIXME: this is not fully correct, the timestamp refers to the random
2648          * access sample refered to in the tfra entry, which may not necessarily
2649          * be the first sample in the tfrag/trun (but hopefully/usually is) */
2650         timestamp = GSTTIME_TO_QTSTREAMTIME (stream, stream->pending_seek->ts);
2651       } else {
2652         timestamp = 0;
2653       }
2654
2655       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2656       GST_INFO_OBJECT (stream->pad, "first sample ts %" GST_TIME_FORMAT,
2657           GST_TIME_ARGS (gst_ts));
2658     } else {
2659       /* subsequent fragments extend stream */
2660       timestamp =
2661           stream->samples[stream->n_samples - 1].timestamp +
2662           stream->samples[stream->n_samples - 1].duration;
2663
2664       gst_ts = QTSTREAMTIME_TO_GSTTIME (stream, timestamp);
2665       GST_INFO_OBJECT (qtdemux, "first sample ts %" GST_TIME_FORMAT
2666           " (extends previous samples)", GST_TIME_ARGS (gst_ts));
2667     }
2668   }
2669
2670   sample = stream->samples + stream->n_samples;
2671   for (i = 0; i < samples_count; i++) {
2672     guint32 dur, size, sflags, ct;
2673
2674     /* first read sample data */
2675     if (flags & TR_SAMPLE_DURATION) {
2676       dur = QT_UINT32 (data + dur_offset);
2677     } else {
2678       dur = d_sample_duration;
2679     }
2680     if (flags & TR_SAMPLE_SIZE) {
2681       size = QT_UINT32 (data + size_offset);
2682     } else {
2683       size = d_sample_size;
2684     }
2685     if (flags & TR_FIRST_SAMPLE_FLAGS) {
2686       if (i == 0) {
2687         sflags = first_flags;
2688       } else {
2689         sflags = d_sample_flags;
2690       }
2691     } else if (flags & TR_SAMPLE_FLAGS) {
2692       sflags = QT_UINT32 (data + flags_offset);
2693     } else {
2694       sflags = d_sample_flags;
2695     }
2696     if (flags & TR_COMPOSITION_TIME_OFFSETS) {
2697       ct = QT_UINT32 (data + ct_offset);
2698     } else {
2699       ct = 0;
2700     }
2701     data += entry_size;
2702
2703     /* fill the sample information */
2704     sample->offset = *running_offset;
2705     sample->pts_offset = ct;
2706     sample->size = size;
2707     sample->timestamp = timestamp;
2708     sample->duration = dur;
2709     /* sample-is-difference-sample */
2710     /* ismv seems to use 0x40 for keyframe, 0xc0 for non-keyframe,
2711      * now idea how it relates to bitfield other than massive LE/BE confusion */
2712     sample->keyframe = ismv ? ((sflags & 0xff) == 0x40) : !(sflags & 0x10000);
2713     *running_offset += size;
2714     timestamp += dur;
2715     sample++;
2716   }
2717
2718   /* Update total duration if needed */
2719   check_update_duration (qtdemux, QTSTREAMTIME_TO_GSTTIME (stream, timestamp));
2720
2721   stream->n_samples += samples_count;
2722
2723   if (stream->pending_seek != NULL)
2724     stream->pending_seek = NULL;
2725
2726   return TRUE;
2727
2728 fail:
2729   {
2730     GST_WARNING_OBJECT (qtdemux, "failed to parse trun");
2731     return FALSE;
2732   }
2733 out_of_memory:
2734   {
2735     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
2736         stream->n_samples);
2737     return FALSE;
2738   }
2739 index_too_big:
2740   {
2741     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
2742         "be larger than %uMB (broken file?)", stream->n_samples,
2743         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
2744     return FALSE;
2745   }
2746 }
2747
2748 /* find stream with @id */
2749 static inline QtDemuxStream *
2750 qtdemux_find_stream (GstQTDemux * qtdemux, guint32 id)
2751 {
2752   QtDemuxStream *stream;
2753   gint i;
2754
2755   /* check */
2756   if (G_UNLIKELY (!id)) {
2757     GST_DEBUG_OBJECT (qtdemux, "invalid track id 0");
2758     return NULL;
2759   }
2760
2761   /* try to get it fast and simple */
2762   if (G_LIKELY (id <= qtdemux->n_streams)) {
2763     stream = qtdemux->streams[id - 1];
2764     if (G_LIKELY (stream->track_id == id))
2765       return stream;
2766   }
2767
2768   /* linear search otherwise */
2769   for (i = 0; i < qtdemux->n_streams; i++) {
2770     stream = qtdemux->streams[i];
2771     if (stream->track_id == id)
2772       return stream;
2773   }
2774   if (qtdemux->mss_mode) {
2775     /* mss should have only 1 stream anyway */
2776     return qtdemux->streams[0];
2777   }
2778
2779   return NULL;
2780 }
2781
2782 static gboolean
2783 qtdemux_parse_mfhd (GstQTDemux * qtdemux, GstByteReader * mfhd,
2784     guint32 * fragment_number)
2785 {
2786   if (!gst_byte_reader_skip (mfhd, 4))
2787     goto fail;
2788   if (!gst_byte_reader_get_uint32_be (mfhd, fragment_number))
2789     goto fail;
2790   return TRUE;
2791 fail:
2792   {
2793     GST_WARNING_OBJECT (qtdemux, "Failed to parse mfhd atom");
2794     return FALSE;
2795   }
2796 }
2797
2798 static gboolean
2799 qtdemux_parse_tfhd (GstQTDemux * qtdemux, GstByteReader * tfhd,
2800     QtDemuxStream ** stream, guint32 * default_sample_duration,
2801     guint32 * default_sample_size, guint32 * default_sample_flags,
2802     gint64 * base_offset)
2803 {
2804   guint32 flags = 0;
2805   guint32 track_id = 0;
2806
2807   if (!gst_byte_reader_skip (tfhd, 1) ||
2808       !gst_byte_reader_get_uint24_be (tfhd, &flags))
2809     goto invalid_track;
2810
2811   if (!gst_byte_reader_get_uint32_be (tfhd, &track_id))
2812     goto invalid_track;
2813
2814   *stream = qtdemux_find_stream (qtdemux, track_id);
2815   if (G_UNLIKELY (!*stream))
2816     goto unknown_stream;
2817
2818   if (flags & TF_BASE_DATA_OFFSET)
2819     if (!gst_byte_reader_get_uint64_be (tfhd, (guint64 *) base_offset))
2820       goto invalid_track;
2821
2822   /* obtain stream defaults */
2823   qtdemux_parse_trex (qtdemux, *stream,
2824       default_sample_duration, default_sample_size, default_sample_flags);
2825
2826   /* FIXME: Handle TF_SAMPLE_DESCRIPTION_INDEX properly */
2827   if (flags & TF_SAMPLE_DESCRIPTION_INDEX)
2828     if (!gst_byte_reader_skip (tfhd, 4))
2829       goto invalid_track;
2830
2831   if (flags & TF_DEFAULT_SAMPLE_DURATION)
2832     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_duration))
2833       goto invalid_track;
2834
2835   if (flags & TF_DEFAULT_SAMPLE_SIZE)
2836     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_size))
2837       goto invalid_track;
2838
2839   if (flags & TF_DEFAULT_SAMPLE_FLAGS)
2840     if (!gst_byte_reader_get_uint32_be (tfhd, default_sample_flags))
2841       goto invalid_track;
2842
2843   return TRUE;
2844
2845 invalid_track:
2846   {
2847     GST_WARNING_OBJECT (qtdemux, "invalid track fragment header");
2848     return FALSE;
2849   }
2850 unknown_stream:
2851   {
2852     GST_DEBUG_OBJECT (qtdemux, "unknown stream in tfhd");
2853     return TRUE;
2854   }
2855 }
2856
2857 static gboolean
2858 qtdemux_parse_tfdt (GstQTDemux * qtdemux, GstByteReader * br,
2859     guint64 * decode_time)
2860 {
2861   guint32 version = 0;
2862
2863   if (!gst_byte_reader_get_uint32_be (br, &version))
2864     return FALSE;
2865
2866   version >>= 24;
2867   if (version == 1) {
2868     if (!gst_byte_reader_get_uint64_be (br, decode_time))
2869       goto failed;
2870   } else {
2871     guint32 dec_time = 0;
2872     if (!gst_byte_reader_get_uint32_be (br, &dec_time))
2873       goto failed;
2874     *decode_time = dec_time;
2875   }
2876
2877   GST_INFO_OBJECT (qtdemux, "Track fragment decode time: %" G_GUINT64_FORMAT,
2878       *decode_time);
2879
2880   return TRUE;
2881
2882 failed:
2883   {
2884     GST_DEBUG_OBJECT (qtdemux, "parsing tfdt failed");
2885     return FALSE;
2886   }
2887 }
2888
2889 static gboolean
2890 qtdemux_parse_moof (GstQTDemux * qtdemux, const guint8 * buffer, guint length,
2891     guint64 moof_offset, QtDemuxStream * stream)
2892 {
2893   GNode *moof_node, *traf_node, *tfhd_node, *trun_node, *tfdt_node, *mfhd_node;
2894   GstByteReader mfhd_data, trun_data, tfhd_data, tfdt_data;
2895   guint32 ds_size = 0, ds_duration = 0, ds_flags = 0;
2896   gint64 base_offset, running_offset;
2897   guint32 frag_num;
2898
2899   /* NOTE @stream ignored */
2900
2901   moof_node = g_node_new ((guint8 *) buffer);
2902   qtdemux_parse_node (qtdemux, moof_node, buffer, length);
2903   qtdemux_node_dump (qtdemux, moof_node);
2904
2905   /* Get fragment number from mfhd and check it's valid */
2906   mfhd_node =
2907       qtdemux_tree_get_child_by_type_full (moof_node, FOURCC_mfhd, &mfhd_data);
2908   if (mfhd_node == NULL)
2909     goto missing_mfhd;
2910   if (!qtdemux_parse_mfhd (qtdemux, &mfhd_data, &frag_num))
2911     goto fail;
2912   GST_DEBUG_OBJECT (qtdemux, "Fragment #%d", frag_num);
2913
2914   /* unknown base_offset to start with */
2915   base_offset = running_offset = -1;
2916   traf_node = qtdemux_tree_get_child_by_type (moof_node, FOURCC_traf);
2917   while (traf_node) {
2918     guint64 decode_time = 0;
2919
2920     /* Fragment Header node */
2921     tfhd_node =
2922         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfhd,
2923         &tfhd_data);
2924     if (!tfhd_node)
2925       goto missing_tfhd;
2926     if (!qtdemux_parse_tfhd (qtdemux, &tfhd_data, &stream, &ds_duration,
2927             &ds_size, &ds_flags, &base_offset))
2928       goto missing_tfhd;
2929     tfdt_node =
2930         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_tfdt,
2931         &tfdt_data);
2932     if (tfdt_node) {
2933       GstClockTime decode_time_ts;
2934
2935       /* We'll use decode_time to interpolate timestamps
2936        * in case the input timestamps are missing */
2937       qtdemux_parse_tfdt (qtdemux, &tfdt_data, &decode_time);
2938
2939       decode_time_ts = QTSTREAMTIME_TO_GSTTIME (stream, decode_time);
2940
2941       GST_DEBUG_OBJECT (qtdemux, "decode time %" G_GINT64_FORMAT
2942           " (%" GST_TIME_FORMAT ")", decode_time,
2943           GST_TIME_ARGS (decode_time_ts));
2944     }
2945
2946     if (G_UNLIKELY (!stream)) {
2947       /* we lost track of offset, we'll need to regain it,
2948        * but can delay complaining until later or avoid doing so altogether */
2949       base_offset = -2;
2950       goto next;
2951     }
2952     if (G_UNLIKELY (base_offset < -1))
2953       goto lost_offset;
2954     /* Track Run node */
2955     trun_node =
2956         qtdemux_tree_get_child_by_type_full (traf_node, FOURCC_trun,
2957         &trun_data);
2958     while (trun_node) {
2959       qtdemux_parse_trun (qtdemux, &trun_data, stream,
2960           ds_duration, ds_size, ds_flags, moof_offset, length, &base_offset,
2961           &running_offset, decode_time);
2962       /* iterate all siblings */
2963       trun_node = qtdemux_tree_get_sibling_by_type_full (trun_node, FOURCC_trun,
2964           &trun_data);
2965     }
2966     /* if no new base_offset provided for next traf,
2967      * base is end of current traf */
2968     base_offset = running_offset;
2969     running_offset = -1;
2970   next:
2971     /* iterate all siblings */
2972     traf_node = qtdemux_tree_get_sibling_by_type (traf_node, FOURCC_traf);
2973   }
2974   g_node_destroy (moof_node);
2975   return TRUE;
2976
2977 missing_tfhd:
2978   {
2979     GST_DEBUG_OBJECT (qtdemux, "missing tfhd box");
2980     goto fail;
2981   }
2982 missing_mfhd:
2983   {
2984     GST_DEBUG_OBJECT (qtdemux, "Missing mfhd box");
2985     goto fail;
2986   }
2987 lost_offset:
2988   {
2989     GST_DEBUG_OBJECT (qtdemux, "lost offset");
2990     goto fail;
2991   }
2992 fail:
2993   {
2994     g_node_destroy (moof_node);
2995     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
2996         (_("This file is corrupt and cannot be played.")), (NULL));
2997     return FALSE;
2998   }
2999 }
3000
3001 #if 0
3002 /* might be used if some day we actually use mfra & co
3003  * for random access to fragments,
3004  * but that will require quite some modifications and much less relying
3005  * on a sample array */
3006 #endif
3007
3008 static gboolean
3009 qtdemux_parse_tfra (GstQTDemux * qtdemux, GNode * tfra_node)
3010 {
3011   QtDemuxStream *stream;
3012   guint32 ver_flags, track_id, len, num_entries, i;
3013   guint value_size, traf_size, trun_size, sample_size;
3014   guint64 time = 0, moof_offset = 0;
3015 #if 0
3016   GstBuffer *buf = NULL;
3017   GstFlowReturn ret;
3018 #endif
3019   GstByteReader tfra;
3020
3021   gst_byte_reader_init (&tfra, tfra_node->data, QT_UINT32 (tfra_node->data));
3022
3023   if (!gst_byte_reader_skip (&tfra, 8))
3024     return FALSE;
3025
3026   if (!gst_byte_reader_get_uint32_be (&tfra, &ver_flags))
3027     return FALSE;
3028
3029   if (!gst_byte_reader_get_uint32_be (&tfra, &track_id)
3030       || !gst_byte_reader_get_uint32_be (&tfra, &len)
3031       || !gst_byte_reader_get_uint32_be (&tfra, &num_entries))
3032     return FALSE;
3033
3034   GST_DEBUG_OBJECT (qtdemux, "parsing tfra box for track id %u", track_id);
3035
3036   stream = qtdemux_find_stream (qtdemux, track_id);
3037   if (stream == NULL)
3038     goto unknown_trackid;
3039
3040   value_size = ((ver_flags >> 24) == 1) ? sizeof (guint64) : sizeof (guint32);
3041   sample_size = (len & 3) + 1;
3042   trun_size = ((len & 12) >> 2) + 1;
3043   traf_size = ((len & 48) >> 4) + 1;
3044
3045   GST_DEBUG_OBJECT (qtdemux, "%u entries, sizes: value %u, traf %u, trun %u, "
3046       "sample %u", num_entries, value_size, traf_size, trun_size, sample_size);
3047
3048   if (num_entries == 0)
3049     goto no_samples;
3050
3051   if (!qt_atom_parser_has_chunks (&tfra, num_entries,
3052           value_size + value_size + traf_size + trun_size + sample_size))
3053     goto corrupt_file;
3054
3055   g_free (stream->ra_entries);
3056   stream->ra_entries = g_new (QtDemuxRandomAccessEntry, num_entries);
3057   stream->n_ra_entries = num_entries;
3058
3059   for (i = 0; i < num_entries; i++) {
3060     qt_atom_parser_get_offset (&tfra, value_size, &time);
3061     qt_atom_parser_get_offset (&tfra, value_size, &moof_offset);
3062     qt_atom_parser_get_uint_with_size_unchecked (&tfra, traf_size);
3063     qt_atom_parser_get_uint_with_size_unchecked (&tfra, trun_size);
3064     qt_atom_parser_get_uint_with_size_unchecked (&tfra, sample_size);
3065
3066     time = QTSTREAMTIME_TO_GSTTIME (stream, time);
3067
3068     GST_LOG_OBJECT (qtdemux, "fragment time: %" GST_TIME_FORMAT ", "
3069         " moof_offset: %" G_GUINT64_FORMAT, GST_TIME_ARGS (time), moof_offset);
3070
3071     stream->ra_entries[i].ts = time;
3072     stream->ra_entries[i].moof_offset = moof_offset;
3073
3074     /* don't want to go through the entire file and read all moofs at startup */
3075 #if 0
3076     ret = gst_qtdemux_pull_atom (qtdemux, moof_offset, 0, &buf);
3077     if (ret != GST_FLOW_OK)
3078       goto corrupt_file;
3079     qtdemux_parse_moof (qtdemux, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
3080         moof_offset, stream);
3081     gst_buffer_unref (buf);
3082 #endif
3083   }
3084
3085   check_update_duration (qtdemux, time);
3086
3087   return TRUE;
3088
3089 /* ERRORS */
3090 unknown_trackid:
3091   {
3092     GST_WARNING_OBJECT (qtdemux, "Couldn't find stream for track %u", track_id);
3093     return FALSE;
3094   }
3095 corrupt_file:
3096   {
3097     GST_WARNING_OBJECT (qtdemux, "broken traf box, ignoring");
3098     return FALSE;
3099   }
3100 no_samples:
3101   {
3102     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
3103     return FALSE;
3104   }
3105 }
3106
3107 static gboolean
3108 qtdemux_pull_mfro_mfra (GstQTDemux * qtdemux)
3109 {
3110   GstMapInfo mfro_map = GST_MAP_INFO_INIT;
3111   GstMapInfo mfra_map = GST_MAP_INFO_INIT;
3112   GstBuffer *mfro = NULL, *mfra = NULL;
3113   GstFlowReturn flow;
3114   gboolean ret = FALSE;
3115   GNode *mfra_node, *tfra_node;
3116   guint64 mfra_offset = 0;
3117   guint32 fourcc, mfra_size;
3118   gint64 len;
3119
3120   /* query upstream size in bytes */
3121   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &len))
3122     goto size_query_failed;
3123
3124   /* mfro box should be at the very end of the file */
3125   flow = gst_qtdemux_pull_atom (qtdemux, len - 16, 16, &mfro);
3126   if (flow != GST_FLOW_OK)
3127     goto exit;
3128
3129   gst_buffer_map (mfro, &mfro_map, GST_MAP_READ);
3130
3131   fourcc = QT_FOURCC (mfro_map.data + 4);
3132   if (fourcc != FOURCC_mfro)
3133     goto exit;
3134
3135   GST_INFO_OBJECT (qtdemux, "Found mfro box");
3136   if (mfro_map.size < 16)
3137     goto invalid_mfro_size;
3138
3139   mfra_size = QT_UINT32 (mfro_map.data + 12);
3140   if (mfra_size >= len)
3141     goto invalid_mfra_size;
3142
3143   mfra_offset = len - mfra_size;
3144
3145   GST_INFO_OBJECT (qtdemux, "mfra offset: %" G_GUINT64_FORMAT ", size %u",
3146       mfra_offset, mfra_size);
3147
3148   /* now get and parse mfra box */
3149   flow = gst_qtdemux_pull_atom (qtdemux, mfra_offset, mfra_size, &mfra);
3150   if (flow != GST_FLOW_OK)
3151     goto broken_file;
3152
3153   gst_buffer_map (mfra, &mfra_map, GST_MAP_READ);
3154
3155   mfra_node = g_node_new ((guint8 *) mfra_map.data);
3156   qtdemux_parse_node (qtdemux, mfra_node, mfra_map.data, mfra_map.size);
3157
3158   tfra_node = qtdemux_tree_get_child_by_type (mfra_node, FOURCC_tfra);
3159
3160   while (tfra_node) {
3161     qtdemux_parse_tfra (qtdemux, tfra_node);
3162     /* iterate all siblings */
3163     tfra_node = qtdemux_tree_get_sibling_by_type (tfra_node, FOURCC_tfra);
3164   }
3165   g_node_destroy (mfra_node);
3166
3167   GST_INFO_OBJECT (qtdemux, "parsed movie fragment random access box (mfra)");
3168   ret = TRUE;
3169
3170 exit:
3171
3172   if (mfro) {
3173     if (mfro_map.memory != NULL)
3174       gst_buffer_unmap (mfro, &mfro_map);
3175     gst_buffer_unref (mfro);
3176   }
3177   if (mfra) {
3178     if (mfra_map.memory != NULL)
3179       gst_buffer_unmap (mfra, &mfra_map);
3180     gst_buffer_unref (mfra);
3181   }
3182   return ret;
3183
3184 /* ERRORS */
3185 size_query_failed:
3186   {
3187     GST_WARNING_OBJECT (qtdemux, "could not query upstream size");
3188     goto exit;
3189   }
3190 invalid_mfro_size:
3191   {
3192     GST_WARNING_OBJECT (qtdemux, "mfro size is too small");
3193     goto exit;
3194   }
3195 invalid_mfra_size:
3196   {
3197     GST_WARNING_OBJECT (qtdemux, "mfra_size in mfro box is invalid");
3198     goto exit;
3199   }
3200 broken_file:
3201   {
3202     GST_WARNING_OBJECT (qtdemux, "bogus mfra offset or size, broken file");
3203     goto exit;
3204   }
3205 }
3206
3207 static GstFlowReturn
3208 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
3209 {
3210   guint64 length = 0;
3211   guint32 fourcc = 0;
3212   GstBuffer *buf = NULL;
3213   GstFlowReturn ret = GST_FLOW_OK;
3214   guint64 cur_offset = qtdemux->offset;
3215   GstMapInfo map;
3216
3217   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
3218   if (G_UNLIKELY (ret != GST_FLOW_OK))
3219     goto beach;
3220   gst_buffer_map (buf, &map, GST_MAP_READ);
3221   if (G_LIKELY (map.size >= 8))
3222     extract_initial_length_and_fourcc (map.data, map.size, &length, &fourcc);
3223   gst_buffer_unmap (buf, &map);
3224   gst_buffer_unref (buf);
3225
3226   /* maybe we already got most we needed, so only consider this eof */
3227   if (G_UNLIKELY (length == 0)) {
3228     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
3229         (_("Invalid atom size.")),
3230         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
3231             GST_FOURCC_ARGS (fourcc)));
3232     ret = GST_FLOW_EOS;
3233     goto beach;
3234   }
3235
3236   switch (fourcc) {
3237     case FOURCC_moof:
3238       /* record for later parsing when needed */
3239       if (!qtdemux->moof_offset) {
3240         qtdemux->moof_offset = qtdemux->offset;
3241       }
3242       if (qtdemux_pull_mfro_mfra (qtdemux)) {
3243         /* FIXME */
3244       }
3245       if (qtdemux->got_moov) {
3246         GST_INFO_OBJECT (qtdemux, "moof header, got moov, done with headers");
3247         ret = GST_FLOW_EOS;
3248         goto beach;
3249       }
3250       break;
3251     case FOURCC_mdat:
3252     case FOURCC_free:
3253     case FOURCC_wide:
3254     case FOURCC_PICT:
3255     case FOURCC_pnot:
3256     {
3257       GST_LOG_OBJECT (qtdemux,
3258           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
3259           GST_FOURCC_ARGS (fourcc), cur_offset);
3260       qtdemux->offset += length;
3261       break;
3262     }
3263     case FOURCC_moov:
3264     {
3265       GstBuffer *moov = NULL;
3266
3267       if (qtdemux->got_moov) {
3268         GST_DEBUG_OBJECT (qtdemux, "Skipping moov atom as we have one already");
3269         qtdemux->offset += length;
3270         goto beach;
3271       }
3272
3273       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
3274       if (ret != GST_FLOW_OK)
3275         goto beach;
3276       gst_buffer_map (moov, &map, GST_MAP_READ);
3277
3278       if (length != map.size) {
3279         /* Some files have a 'moov' atom at the end of the file which contains
3280          * a terminal 'free' atom where the body of the atom is missing.
3281          * Check for, and permit, this special case.
3282          */
3283         if (map.size >= 8) {
3284           guint8 *final_data = map.data + (map.size - 8);
3285           guint32 final_length = QT_UINT32 (final_data);
3286           guint32 final_fourcc = QT_FOURCC (final_data + 4);
3287
3288           if (final_fourcc == FOURCC_free
3289               && map.size + final_length - 8 == length) {
3290             /* Ok, we've found that special case. Allocate a new buffer with
3291              * that free atom actually present. */
3292             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
3293             gst_buffer_fill (newmoov, 0, map.data, map.size);
3294             gst_buffer_memset (newmoov, map.size, 0, final_length - 8);
3295             gst_buffer_unmap (moov, &map);
3296             gst_buffer_unref (moov);
3297             moov = newmoov;
3298             gst_buffer_map (moov, &map, GST_MAP_READ);
3299           }
3300         }
3301       }
3302
3303       if (length != map.size) {
3304         GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
3305             (_("This file is incomplete and cannot be played.")),
3306             ("We got less than expected (received %" G_GSIZE_FORMAT
3307                 ", wanted %u, offset %" G_GUINT64_FORMAT ")", map.size,
3308                 (guint) length, cur_offset));
3309         gst_buffer_unmap (moov, &map);
3310         gst_buffer_unref (moov);
3311         ret = GST_FLOW_ERROR;
3312         goto beach;
3313       }
3314       qtdemux->offset += length;
3315
3316       qtdemux_parse_moov (qtdemux, map.data, length);
3317       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
3318
3319       qtdemux_parse_tree (qtdemux);
3320       g_node_destroy (qtdemux->moov_node);
3321       gst_buffer_unmap (moov, &map);
3322       gst_buffer_unref (moov);
3323       qtdemux->moov_node = NULL;
3324       qtdemux->got_moov = TRUE;
3325
3326       break;
3327     }
3328     case FOURCC_ftyp:
3329     {
3330       GstBuffer *ftyp = NULL;
3331
3332       /* extract major brand; might come in handy for ISO vs QT issues */
3333       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
3334       if (ret != GST_FLOW_OK)
3335         goto beach;
3336       qtdemux->offset += length;
3337       gst_buffer_map (ftyp, &map, GST_MAP_READ);
3338       qtdemux_parse_ftyp (qtdemux, map.data, map.size);
3339       gst_buffer_unmap (ftyp, &map);
3340       gst_buffer_unref (ftyp);
3341       break;
3342     }
3343     case FOURCC_uuid:
3344     {
3345       GstBuffer *uuid = NULL;
3346
3347       /* uuid are extension atoms */
3348       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &uuid);
3349       if (ret != GST_FLOW_OK)
3350         goto beach;
3351       qtdemux->offset += length;
3352       gst_buffer_map (uuid, &map, GST_MAP_READ);
3353       qtdemux_parse_uuid (qtdemux, map.data, map.size);
3354       gst_buffer_unmap (uuid, &map);
3355       gst_buffer_unref (uuid);
3356       break;
3357     }
3358     default:
3359     {
3360       GstBuffer *unknown = NULL;
3361
3362       GST_LOG_OBJECT (qtdemux,
3363           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
3364           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
3365           cur_offset);
3366       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
3367       if (ret != GST_FLOW_OK)
3368         goto beach;
3369       gst_buffer_map (unknown, &map, GST_MAP_READ);
3370       GST_MEMDUMP ("Unknown tag", map.data, map.size);
3371       gst_buffer_unmap (unknown, &map);
3372       gst_buffer_unref (unknown);
3373       qtdemux->offset += length;
3374       break;
3375     }
3376   }
3377
3378 beach:
3379   if (ret == GST_FLOW_EOS && (qtdemux->got_moov || qtdemux->media_caps)) {
3380     /* digested all data, show what we have */
3381     qtdemux_prepare_streams (qtdemux);
3382     ret = qtdemux_expose_streams (qtdemux);
3383
3384     qtdemux->state = QTDEMUX_STATE_MOVIE;
3385     GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
3386         qtdemux->state);
3387     return ret;
3388   }
3389   return ret;
3390 }
3391
3392 /* Seeks to the previous keyframe of the indexed stream and
3393  * aligns other streams with respect to the keyframe timestamp
3394  * of indexed stream. Only called in case of Reverse Playback
3395  */
3396 static GstFlowReturn
3397 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
3398 {
3399   guint8 n = 0;
3400   guint32 seg_idx = 0, k_index = 0;
3401   guint32 ref_seg_idx, ref_k_index;
3402   GstClockTime k_pos = 0, last_stop = 0;
3403   QtDemuxSegment *seg = NULL;
3404   QtDemuxStream *ref_str = NULL;
3405   guint64 seg_media_start_mov;  /* segment media start time in mov format */
3406   guint64 target_ts;
3407
3408   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
3409    * and finally align all the other streams on that timestamp with their
3410    * respective keyframes */
3411   for (n = 0; n < qtdemux->n_streams; n++) {
3412     QtDemuxStream *str = qtdemux->streams[n];
3413
3414     /* No candidate yet, take the first stream */
3415     if (!ref_str) {
3416       ref_str = str;
3417       continue;
3418     }
3419
3420     /* So that stream has a segment, we prefer video streams */
3421     if (str->subtype == FOURCC_vide) {
3422       ref_str = str;
3423       break;
3424     }
3425   }
3426
3427   if (G_UNLIKELY (!ref_str)) {
3428     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
3429     goto eos;
3430   }
3431
3432   if (G_UNLIKELY (!ref_str->from_sample)) {
3433     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
3434     goto eos;
3435   }
3436
3437   /* So that stream has been playing from from_sample to to_sample. We will
3438    * get the timestamp of the previous sample and search for a keyframe before
3439    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
3440   if (ref_str->subtype == FOURCC_vide) {
3441     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
3442         ref_str->from_sample - 1);
3443   } else {
3444     if (ref_str->from_sample >= 10)
3445       k_index = ref_str->from_sample - 10;
3446     else
3447       k_index = 0;
3448   }
3449
3450   target_ts =
3451       ref_str->samples[k_index].timestamp +
3452       ref_str->samples[k_index].pts_offset;
3453
3454   /* get current segment for that stream */
3455   seg = &ref_str->segments[ref_str->segment_index];
3456   /* Use segment start in original timescale for comparisons */
3457   seg_media_start_mov = seg->trak_media_start;
3458
3459   GST_LOG_OBJECT (qtdemux, "keyframe index %u ts %" G_GUINT64_FORMAT
3460       " seg start %" G_GUINT64_FORMAT " %" GST_TIME_FORMAT "\n",
3461       k_index, target_ts, seg_media_start_mov,
3462       GST_TIME_ARGS (seg->media_start));
3463
3464   /* Crawl back through segments to find the one containing this I frame */
3465   while (target_ts < seg_media_start_mov) {
3466     GST_DEBUG_OBJECT (qtdemux,
3467         "keyframe position (sample %u) is out of segment %u " " target %"
3468         G_GUINT64_FORMAT " seg start %" G_GUINT64_FORMAT, k_index,
3469         ref_str->segment_index, target_ts, seg_media_start_mov);
3470
3471     if (G_UNLIKELY (!ref_str->segment_index)) {
3472       /* Reached first segment, let's consider it's EOS */
3473       goto eos;
3474     }
3475     ref_str->segment_index--;
3476     seg = &ref_str->segments[ref_str->segment_index];
3477     /* Use segment start in original timescale for comparisons */
3478     seg_media_start_mov = seg->trak_media_start;
3479   }
3480   /* Calculate time position of the keyframe and where we should stop */
3481   k_pos =
3482       QTSTREAMTIME_TO_GSTTIME (ref_str,
3483       target_ts - seg->trak_media_start) + seg->time;
3484   last_stop =
3485       QTSTREAMTIME_TO_GSTTIME (ref_str,
3486       ref_str->samples[ref_str->from_sample].timestamp -
3487       seg->trak_media_start) + seg->time;
3488
3489   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
3490       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
3491       k_index, GST_TIME_ARGS (k_pos));
3492
3493   /* Set last_stop with the keyframe timestamp we pushed of that stream */
3494   qtdemux->segment.position = last_stop;
3495   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
3496       GST_TIME_ARGS (last_stop));
3497
3498   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
3499     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
3500     goto eos;
3501   }
3502
3503   ref_seg_idx = ref_str->segment_index;
3504   ref_k_index = k_index;
3505
3506   /* Align them all on this */
3507   for (n = 0; n < qtdemux->n_streams; n++) {
3508     guint32 index = 0;
3509     GstClockTime seg_time = 0;
3510     QtDemuxStream *str = qtdemux->streams[n];
3511
3512     /* aligning reference stream again might lead to backing up to yet another
3513      * keyframe (due to timestamp rounding issues),
3514      * potentially putting more load on downstream; so let's try to avoid */
3515     if (str == ref_str) {
3516       seg_idx = ref_seg_idx;
3517       seg = &str->segments[seg_idx];
3518       k_index = ref_k_index;
3519       GST_DEBUG_OBJECT (qtdemux, "reference stream %d segment %d, "
3520           "sample at index %d", n, ref_str->segment_index, k_index);
3521     } else {
3522       seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
3523       GST_DEBUG_OBJECT (qtdemux,
3524           "stream %d align segment %d for keyframe pos %" GST_TIME_FORMAT, n,
3525           seg_idx, GST_TIME_ARGS (k_pos));
3526
3527       /* get segment and time in the segment */
3528       seg = &str->segments[seg_idx];
3529       seg_time = k_pos - seg->time;
3530
3531       /* get the media time in the segment.
3532        * No adjustment for empty "filler" segments */
3533       if (seg->media_start != GST_CLOCK_TIME_NONE)
3534         seg_time += seg->media_start;
3535
3536       /* get the index of the sample with media time */
3537       index = gst_qtdemux_find_index_linear (qtdemux, str, seg_time);
3538       GST_DEBUG_OBJECT (qtdemux,
3539           "stream %d sample for %" GST_TIME_FORMAT " at %u", n,
3540           GST_TIME_ARGS (seg_time), index);
3541
3542       /* find previous keyframe */
3543       k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
3544     }
3545
3546     /* Remember until where we want to go */
3547     str->to_sample = str->from_sample - 1;
3548     /* Define our time position */
3549     target_ts =
3550         str->samples[k_index].timestamp + str->samples[k_index].pts_offset;
3551     str->time_position = QTSTREAMTIME_TO_GSTTIME (str, target_ts) + seg->time;
3552     if (seg->media_start != GST_CLOCK_TIME_NONE)
3553       str->time_position -= seg->media_start;
3554
3555     /* Now seek back in time */
3556     gst_qtdemux_move_stream (qtdemux, str, k_index);
3557     GST_DEBUG_OBJECT (qtdemux, "stream %d keyframe at %u, time position %"
3558         GST_TIME_FORMAT " playing from sample %u to %u", n, k_index,
3559         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
3560   }
3561
3562   return GST_FLOW_OK;
3563
3564 eos:
3565   return GST_FLOW_EOS;
3566 }
3567
3568 /* activate the given segment number @seg_idx of @stream at time @offset.
3569  * @offset is an absolute global position over all the segments.
3570  *
3571  * This will push out a NEWSEGMENT event with the right values and
3572  * position the stream index to the first decodable sample before
3573  * @offset.
3574  *
3575  * PULL-BASED
3576  */
3577 static gboolean
3578 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
3579     guint32 seg_idx, GstClockTime offset)
3580 {
3581   GstEvent *event;
3582   QtDemuxSegment *segment;
3583   guint32 index, kf_index;
3584   GstClockTime seg_time;
3585   GstClockTime start, stop, time;
3586   gdouble rate;
3587
3588   GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" GST_TIME_FORMAT,
3589       seg_idx, GST_TIME_ARGS (offset));
3590
3591   /* update the current segment */
3592   stream->segment_index = seg_idx;
3593
3594   /* get the segment */
3595   segment = &stream->segments[seg_idx];
3596
3597   if (G_UNLIKELY (offset < segment->time)) {
3598     GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" GST_TIME_FORMAT,
3599         GST_TIME_ARGS (segment->time));
3600     return FALSE;
3601   }
3602
3603   /* segment lies beyond total indicated duration */
3604   if (G_UNLIKELY (qtdemux->segment.duration != GST_CLOCK_TIME_NONE &&
3605           segment->time > qtdemux->segment.duration)) {
3606     GST_WARNING_OBJECT (qtdemux, "file duration %" GST_TIME_FORMAT
3607         " < segment->time %" GST_TIME_FORMAT,
3608         GST_TIME_ARGS (qtdemux->segment.duration),
3609         GST_TIME_ARGS (segment->time));
3610     return FALSE;
3611   }
3612
3613   /* get time in this segment */
3614   seg_time = offset - segment->time;
3615
3616   GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
3617       GST_TIME_ARGS (seg_time));
3618
3619   if (G_UNLIKELY (seg_time > segment->duration)) {
3620     GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
3621         GST_TIME_ARGS (segment->duration));
3622     seg_time = segment->duration;
3623   }
3624
3625   /* qtdemux->segment.stop is in outside-time-realm, whereas
3626    * segment->media_stop is in track-time-realm.
3627    *
3628    * In order to compare the two, we need to bring segment.stop
3629    * into the track-time-realm */
3630
3631   stop = qtdemux->segment.stop;
3632   if (stop == GST_CLOCK_TIME_NONE)
3633     stop = qtdemux->segment.duration;
3634   if (stop == GST_CLOCK_TIME_NONE)
3635     stop = segment->media_stop;
3636   else
3637     stop =
3638         MIN (segment->media_stop, stop - segment->time + segment->media_start);
3639
3640   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3641     start = segment->time + seg_time;
3642     time = offset;
3643   } else if (qtdemux->segment.rate >= 0) {
3644     start = MIN (segment->media_start + seg_time, stop);
3645     time = offset;
3646   } else {
3647     if (segment->media_start >= qtdemux->segment.start) {
3648       time = segment->time;
3649     } else {
3650       time = segment->time + (qtdemux->segment.start - segment->media_start);
3651     }
3652
3653     start = MAX (segment->media_start, qtdemux->segment.start);
3654     stop = MIN (segment->media_start + seg_time, stop);
3655   }
3656
3657   GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
3658       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
3659       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
3660
3661   /* combine global rate with that of the segment */
3662   rate = segment->rate * qtdemux->segment.rate;
3663
3664   /* Copy flags from main segment */
3665   stream->segment.flags = qtdemux->segment.flags;
3666
3667   /* update the segment values used for clipping */
3668   /* accumulate previous segments */
3669   if (GST_CLOCK_TIME_IS_VALID (stream->segment.stop))
3670     stream->segment.base += (stream->segment.stop - stream->segment.start) /
3671         ABS (stream->segment.rate);
3672   stream->segment.rate = rate;
3673   stream->segment.start = start;
3674   stream->segment.stop = stop;
3675   stream->segment.time = time;
3676   stream->segment.position = start;
3677   stream->segment.base =
3678       segment->time >
3679       qtdemux->segment_base ? segment->time - qtdemux->segment_base : 0;
3680
3681   /* now prepare and send the segment */
3682   if (stream->pad) {
3683     event = gst_event_new_segment (&stream->segment);
3684     if (stream->segment_seqnum) {
3685       gst_event_set_seqnum (event, stream->segment_seqnum);
3686       stream->segment_seqnum = 0;
3687     }
3688     gst_pad_push_event (stream->pad, event);
3689     /* clear to send tags on this pad now */
3690     gst_qtdemux_push_tags (qtdemux, stream);
3691   }
3692
3693   /* in the fragmented case, we pick a fragment that starts before our
3694    * desired position and rely on downstream to wait for a keyframe
3695    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
3696    * tfra entries tells us which trun/sample the key unit is in, but we don't
3697    * make use of this additional information at the moment) */
3698   if (qtdemux->fragmented) {
3699     stream->to_sample = G_MAXUINT32;
3700     return TRUE;
3701   }
3702
3703   /* and move to the keyframe before the indicated media time of the
3704    * segment */
3705   if (G_LIKELY (!QTSEGMENT_IS_EMPTY (segment))) {
3706     if (qtdemux->segment.rate >= 0) {
3707       index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
3708       stream->to_sample = G_MAXUINT32;
3709       GST_DEBUG_OBJECT (qtdemux,
3710           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3711           GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
3712           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3713     } else {
3714       index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
3715       stream->to_sample = index;
3716       GST_DEBUG_OBJECT (qtdemux,
3717           "moving data pointer to %" GST_TIME_FORMAT ", index: %u, pts %"
3718           GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
3719           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[index])));
3720     }
3721   } else {
3722     GST_DEBUG_OBJECT (qtdemux, "No need to look for keyframe, "
3723         "this is an empty segment");
3724     return TRUE;
3725   }
3726
3727   /* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
3728    * encountered an error and printed a message so we return appropriately */
3729   if (index == -1)
3730     return FALSE;
3731
3732   /* we're at the right spot */
3733   if (index == stream->sample_index) {
3734     GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
3735     return TRUE;
3736   }
3737
3738   /* find keyframe of the target index */
3739   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
3740
3741 /* *INDENT-OFF* */
3742 /* indent does stupid stuff with stream->samples[].timestamp */
3743
3744   /* if we move forwards, we don't have to go back to the previous
3745    * keyframe since we already sent that. We can also just jump to
3746    * the keyframe right before the target index if there is one. */
3747   if (index > stream->sample_index) {
3748     /* moving forwards check if we move past a keyframe */
3749     if (kf_index > stream->sample_index) {
3750       GST_DEBUG_OBJECT (qtdemux,
3751            "moving forwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3752            GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3753            GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3754       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3755     } else {
3756       GST_DEBUG_OBJECT (qtdemux,
3757           "moving forwards, keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" ) already sent", kf_index,
3758           GST_TIME_ARGS (QTSAMPLE_PTS (stream, &stream->samples[kf_index])),
3759           GST_TIME_ARGS (QTSAMPLE_DTS (stream, &stream->samples[kf_index])));
3760     }
3761   } else {
3762     GST_DEBUG_OBJECT (qtdemux,
3763         "moving backwards to keyframe at %u (pts %" GST_TIME_FORMAT " dts %"GST_TIME_FORMAT" )", kf_index,
3764         GST_TIME_ARGS (QTSAMPLE_PTS(stream, &stream->samples[kf_index])),
3765         GST_TIME_ARGS (QTSAMPLE_DTS(stream, &stream->samples[kf_index])));
3766     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
3767   }
3768
3769 /* *INDENT-ON* */
3770
3771   return TRUE;
3772 }
3773
3774 /* prepare to get the current sample of @stream, getting essential values.
3775  *
3776  * This function will also prepare and send the segment when needed.
3777  *
3778  * Return FALSE if the stream is EOS.
3779  *
3780  * PULL-BASED
3781  */
3782 static gboolean
3783 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
3784     QtDemuxStream * stream, gboolean * empty, guint64 * offset, guint * size,
3785     GstClockTime * dts, GstClockTime * pts, GstClockTime * duration,
3786     gboolean * keyframe)
3787 {
3788   QtDemuxSample *sample;
3789   GstClockTime time_position;
3790   guint32 seg_idx;
3791
3792   g_return_val_if_fail (stream != NULL, FALSE);
3793
3794   time_position = stream->time_position;
3795   if (G_UNLIKELY (time_position == GST_CLOCK_TIME_NONE))
3796     goto eos;
3797
3798   seg_idx = stream->segment_index;
3799   if (G_UNLIKELY (seg_idx == -1)) {
3800     /* find segment corresponding to time_position if we are looking
3801      * for a segment. */
3802     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
3803   }
3804
3805   /* different segment, activate it, sample_index will be set. */
3806   if (G_UNLIKELY (stream->segment_index != seg_idx))
3807     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
3808
3809   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (&stream->segments[stream->
3810                   segment_index]))) {
3811     QtDemuxSegment *seg = &stream->segments[stream->segment_index];
3812
3813     GST_LOG_OBJECT (qtdemux, "Empty segment activated,"
3814         " prepare empty sample");
3815
3816     *empty = TRUE;
3817     *pts = *dts = time_position;
3818     *duration = seg->duration - (time_position - seg->time);
3819
3820     return TRUE;
3821   }
3822
3823   *empty = FALSE;
3824
3825   if (stream->sample_index == -1)
3826     stream->sample_index = 0;
3827
3828   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
3829       stream->sample_index, stream->n_samples);
3830
3831   if (G_UNLIKELY (stream->sample_index >= stream->n_samples)) {
3832     if (!qtdemux->fragmented)
3833       goto eos;
3834
3835     GST_INFO_OBJECT (qtdemux, "out of samples, trying to add more");
3836     do {
3837       GstFlowReturn flow;
3838
3839       GST_OBJECT_LOCK (qtdemux);
3840       flow = qtdemux_add_fragmented_samples (qtdemux);
3841       GST_OBJECT_UNLOCK (qtdemux);
3842
3843       if (flow != GST_FLOW_OK)
3844         goto eos;
3845     }
3846     while (stream->sample_index >= stream->n_samples);
3847   }
3848
3849   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3850     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3851         stream->sample_index);
3852     return FALSE;
3853   }
3854
3855   /* now get the info for the sample we're at */
3856   sample = &stream->samples[stream->sample_index];
3857
3858   *dts = QTSAMPLE_DTS (stream, sample);
3859   *pts = QTSAMPLE_PTS (stream, sample);
3860   *offset = sample->offset;
3861   *size = sample->size;
3862   *duration = QTSAMPLE_DUR_DTS (stream, sample, *dts);
3863   *keyframe = QTSAMPLE_KEYFRAME (stream, sample);
3864
3865   return TRUE;
3866
3867   /* special cases */
3868 eos:
3869   {
3870     stream->time_position = GST_CLOCK_TIME_NONE;
3871     return FALSE;
3872   }
3873 }
3874
3875 /* move to the next sample in @stream.
3876  *
3877  * Moves to the next segment when needed.
3878  */
3879 static void
3880 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
3881 {
3882   QtDemuxSample *sample;
3883   QtDemuxSegment *segment;
3884
3885   /* get current segment */
3886   segment = &stream->segments[stream->segment_index];
3887
3888   if (G_UNLIKELY (QTSEGMENT_IS_EMPTY (segment))) {
3889     GST_DEBUG_OBJECT (qtdemux, "Empty segment, no samples to advance");
3890     goto next_segment;
3891   }
3892
3893   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
3894     /* Mark the stream as EOS */
3895     GST_DEBUG_OBJECT (qtdemux,
3896         "reached max allowed sample %u, mark EOS", stream->to_sample);
3897     stream->time_position = GST_CLOCK_TIME_NONE;
3898     return;
3899   }
3900
3901   /* move to next sample */
3902   stream->sample_index++;
3903   stream->offset_in_sample = 0;
3904
3905   /* reached the last sample, we need the next segment */
3906   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
3907     goto next_segment;
3908
3909   if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
3910     GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
3911         stream->sample_index);
3912     return;
3913   }
3914
3915   /* get next sample */
3916   sample = &stream->samples[stream->sample_index];
3917
3918   /* see if we are past the segment */
3919   if (G_UNLIKELY (QTSAMPLE_DTS (stream, sample) >= segment->media_stop))
3920     goto next_segment;
3921
3922   if (QTSAMPLE_DTS (stream, sample) >= segment->media_start) {
3923     /* inside the segment, update time_position, looks very familiar to
3924      * GStreamer segments, doesn't it? */
3925     stream->time_position =
3926         QTSAMPLE_DTS (stream, sample) - segment->media_start + segment->time;
3927   } else {
3928     /* not yet in segment, time does not yet increment. This means
3929      * that we are still prerolling keyframes to the decoder so it can
3930      * decode the first sample of the segment. */
3931     stream->time_position = segment->time;
3932   }
3933   return;
3934
3935   /* move to the next segment */
3936 next_segment:
3937   {
3938     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
3939
3940     if (stream->segment_index == stream->n_segments - 1) {
3941       /* are we at the end of the last segment, we're EOS */
3942       stream->time_position = GST_CLOCK_TIME_NONE;
3943     } else {
3944       /* else we're only at the end of the current segment */
3945       stream->time_position = segment->stop_time;
3946     }
3947     /* make sure we select a new segment */
3948     stream->segment_index = -1;
3949   }
3950 }
3951
3952 static void
3953 gst_qtdemux_sync_streams (GstQTDemux * demux)
3954 {
3955   gint i;
3956
3957   if (demux->n_streams <= 1)
3958     return;
3959
3960   for (i = 0; i < demux->n_streams; i++) {
3961     QtDemuxStream *stream;
3962     GstClockTime end_time;
3963
3964     stream = demux->streams[i];
3965
3966     if (!stream->pad)
3967       continue;
3968
3969     /* TODO advance time on subtitle streams here, if any some day */
3970
3971     /* some clips/trailers may have unbalanced streams at the end,
3972      * so send EOS on shorter stream to prevent stalling others */
3973
3974     /* do not mess with EOS if SEGMENT seeking */
3975     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
3976       continue;
3977
3978     if (demux->pullbased) {
3979       /* loop mode is sample time based */
3980       if (!STREAM_IS_EOS (stream))
3981         continue;
3982     } else {
3983       /* push mode is byte position based */
3984       if (stream->n_samples &&
3985           stream->samples[stream->n_samples - 1].offset >= demux->offset)
3986         continue;
3987     }
3988
3989     if (stream->sent_eos)
3990       continue;
3991
3992     /* only act if some gap */
3993     end_time = stream->segments[stream->n_segments - 1].stop_time;
3994     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
3995         ", stream end: %" GST_TIME_FORMAT,
3996         GST_TIME_ARGS (demux->segment.position), GST_TIME_ARGS (end_time));
3997     if (GST_CLOCK_TIME_IS_VALID (end_time)
3998         && (end_time + 2 * GST_SECOND < demux->segment.position)) {
3999       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
4000           GST_PAD_NAME (stream->pad));
4001       stream->sent_eos = TRUE;
4002       gst_pad_push_event (stream->pad, gst_event_new_eos ());
4003     }
4004   }
4005 }
4006
4007 /* EOS and NOT_LINKED need to be combined. This means that we return:
4008  *
4009  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
4010  *  GST_FLOW_EOS: when all pads EOS or NOT_LINKED.
4011  */
4012 static GstFlowReturn
4013 gst_qtdemux_combine_flows (GstQTDemux * demux, GstFlowReturn ret)
4014 {
4015   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
4016
4017   ret = gst_flow_combiner_update_flow (demux->flowcombiner, ret);
4018
4019   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
4020   return ret;
4021 }
4022
4023 /* the input buffer metadata must be writable. Returns NULL when the buffer is
4024  * completely clipped
4025  *
4026  * Should be used only with raw buffers */
4027 static GstBuffer *
4028 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4029     GstBuffer * buf)
4030 {
4031   guint64 start, stop, cstart, cstop, diff;
4032   GstClockTime pts, duration;
4033   gsize size, osize;
4034   gint num_rate, denom_rate;
4035   gint frame_size;
4036   gboolean clip_data;
4037   guint offset;
4038
4039   osize = size = gst_buffer_get_size (buf);
4040   offset = 0;
4041
4042   /* depending on the type, setup the clip parameters */
4043   if (stream->subtype == FOURCC_soun) {
4044     frame_size = stream->bytes_per_frame;
4045     num_rate = GST_SECOND;
4046     denom_rate = (gint) stream->rate;
4047     clip_data = TRUE;
4048   } else if (stream->subtype == FOURCC_vide) {
4049     frame_size = size;
4050     num_rate = stream->fps_n;
4051     denom_rate = stream->fps_d;
4052     clip_data = FALSE;
4053   } else
4054     goto wrong_type;
4055
4056   if (frame_size <= 0)
4057     goto bad_frame_size;
4058
4059   /* we can only clip if we have a valid pts */
4060   pts = GST_BUFFER_PTS (buf);
4061   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (pts)))
4062     goto no_pts;
4063
4064   duration = GST_BUFFER_DURATION (buf);
4065
4066   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (duration))) {
4067     duration =
4068         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
4069   }
4070
4071   start = pts;
4072   stop = start + duration;
4073
4074   if (G_UNLIKELY (!gst_segment_clip (&stream->segment,
4075               GST_FORMAT_TIME, start, stop, &cstart, &cstop)))
4076     goto clipped;
4077
4078   /* see if some clipping happened */
4079   diff = cstart - start;
4080   if (diff > 0) {
4081     pts += diff;
4082     duration -= diff;
4083
4084     if (clip_data) {
4085       /* bring clipped time to samples and to bytes */
4086       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4087       diff *= frame_size;
4088
4089       GST_DEBUG_OBJECT (qtdemux,
4090           "clipping start to %" GST_TIME_FORMAT " %"
4091           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
4092
4093       offset = diff;
4094       size -= diff;
4095     }
4096   }
4097   diff = stop - cstop;
4098   if (diff > 0) {
4099     duration -= diff;
4100
4101     if (clip_data) {
4102       /* bring clipped time to samples and then to bytes */
4103       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
4104       diff *= frame_size;
4105       GST_DEBUG_OBJECT (qtdemux,
4106           "clipping stop to %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
4107           " bytes", GST_TIME_ARGS (cstop), diff);
4108       size -= diff;
4109     }
4110   }
4111
4112   if (offset != 0 || size != osize)
4113     gst_buffer_resize (buf, offset, size);
4114
4115   GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE;
4116   GST_BUFFER_PTS (buf) = pts;
4117   GST_BUFFER_DURATION (buf) = duration;
4118
4119   return buf;
4120
4121   /* dropped buffer */
4122 wrong_type:
4123   {
4124     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
4125     return buf;
4126   }
4127 bad_frame_size:
4128   {
4129     GST_DEBUG_OBJECT (qtdemux, "bad frame size");
4130     return buf;
4131   }
4132 no_pts:
4133   {
4134     GST_DEBUG_OBJECT (qtdemux, "no pts on buffer");
4135     return buf;
4136   }
4137 clipped:
4138   {
4139     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
4140     gst_buffer_unref (buf);
4141     return NULL;
4142   }
4143 }
4144
4145 /* the input buffer metadata must be writable,
4146  * but time/duration etc not yet set and need not be preserved */
4147 static GstBuffer *
4148 gst_qtdemux_process_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
4149     GstBuffer * buf)
4150 {
4151   GstMapInfo map;
4152   guint nsize = 0;
4153   gchar *str;
4154
4155   /* not many cases for now */
4156   if (G_UNLIKELY (stream->fourcc == FOURCC_mp4s)) {
4157     /* send a one time dvd clut event */
4158     if (stream->pending_event && stream->pad)
4159       gst_pad_push_event (stream->pad, stream->pending_event);
4160     stream->pending_event = NULL;
4161   }
4162
4163   if (G_UNLIKELY (stream->subtype != FOURCC_text
4164           && stream->subtype != FOURCC_sbtl &&
4165           stream->subtype != FOURCC_subp)) {
4166     return buf;
4167   }
4168
4169   gst_buffer_map (buf, &map, GST_MAP_READ);
4170
4171   /* empty buffer is sent to terminate previous subtitle */
4172   if (map.size <= 2) {
4173     gst_buffer_unmap (buf, &map);
4174     gst_buffer_unref (buf);
4175     return NULL;
4176   }
4177   if (stream->subtype == FOURCC_subp) {
4178     /* That's all the processing needed for subpictures */
4179     gst_buffer_unmap (buf, &map);
4180     return buf;
4181   }
4182
4183   nsize = GST_READ_UINT16_BE (map.data);
4184   nsize = MIN (nsize, map.size - 2);
4185
4186   GST_LOG_OBJECT (qtdemux, "3GPP timed text subtitle: %d/%" G_GSIZE_FORMAT "",
4187       nsize, map.size);
4188
4189   /* takes care of UTF-8 validation or UTF-16 recognition,
4190    * no other encoding expected */
4191   str = gst_tag_freeform_string_to_utf8 ((gchar *) map.data + 2, nsize, NULL);
4192   gst_buffer_unmap (buf, &map);
4193   if (str) {
4194     gst_buffer_unref (buf);
4195     buf = _gst_buffer_new_wrapped (str, strlen (str), g_free);
4196   } else {
4197     /* this should not really happen unless the subtitle is corrupted */
4198     gst_buffer_unref (buf);
4199     buf = NULL;
4200   }
4201
4202   /* FIXME ? convert optional subsequent style info to markup */
4203
4204   return buf;
4205 }
4206
4207 /* Sets a buffer's attributes properly and pushes it downstream.
4208  * Also checks for additional actions and custom processing that may
4209  * need to be done first.
4210  */
4211 static GstFlowReturn
4212 gst_qtdemux_decorate_and_push_buffer (GstQTDemux * qtdemux,
4213     QtDemuxStream * stream, GstBuffer * buf,
4214     GstClockTime dts, GstClockTime pts, GstClockTime duration,
4215     gboolean keyframe, GstClockTime position, guint64 byte_position)
4216 {
4217   GstFlowReturn ret = GST_FLOW_OK;
4218
4219   /* offset the timestamps according to the edit list */
4220
4221   if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
4222     gchar *url;
4223     GstMapInfo map;
4224
4225     gst_buffer_map (buf, &map, GST_MAP_READ);
4226     url = g_strndup ((gchar *) map.data, map.size);
4227     gst_buffer_unmap (buf, &map);
4228     if (url != NULL && strlen (url) != 0) {
4229       /* we have RTSP redirect now */
4230       gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4231           gst_message_new_element (GST_OBJECT_CAST (qtdemux),
4232               gst_structure_new ("redirect",
4233                   "new-location", G_TYPE_STRING, url, NULL)));
4234       qtdemux->posted_redirect = TRUE;
4235     } else {
4236       GST_WARNING_OBJECT (qtdemux, "Redirect URI of stream is empty, not "
4237           "posting");
4238     }
4239     g_free (url);
4240   }
4241
4242   /* position reporting */
4243   if (qtdemux->segment.rate >= 0) {
4244     qtdemux->segment.position = position;
4245     gst_qtdemux_sync_streams (qtdemux);
4246   }
4247
4248   if (G_UNLIKELY (!stream->pad)) {
4249     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
4250     gst_buffer_unref (buf);
4251     goto exit;
4252   }
4253
4254   /* send out pending buffers */
4255   while (stream->buffers) {
4256     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
4257
4258     if (G_UNLIKELY (stream->discont)) {
4259       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4260       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
4261       stream->discont = FALSE;
4262     } else {
4263       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4264     }
4265
4266     gst_pad_push (stream->pad, buffer);
4267
4268     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
4269   }
4270
4271   /* we're going to modify the metadata */
4272   buf = gst_buffer_make_writable (buf);
4273
4274   if (G_UNLIKELY (stream->need_process))
4275     buf = gst_qtdemux_process_buffer (qtdemux, stream, buf);
4276
4277   if (!buf) {
4278     goto exit;
4279   }
4280
4281   GST_BUFFER_DTS (buf) = dts;
4282   GST_BUFFER_PTS (buf) = pts;
4283   GST_BUFFER_DURATION (buf) = duration;
4284   GST_BUFFER_OFFSET (buf) = -1;
4285   GST_BUFFER_OFFSET_END (buf) = -1;
4286
4287   if (G_UNLIKELY (stream->rgb8_palette))
4288     gst_buffer_append_memory (buf, gst_memory_ref (stream->rgb8_palette));
4289
4290   if (G_UNLIKELY (stream->padding)) {
4291     gst_buffer_resize (buf, stream->padding, -1);
4292   }
4293 #if 0
4294   if (G_UNLIKELY (qtdemux->element_index)) {
4295     GstClockTime stream_time;
4296
4297     stream_time =
4298         gst_segment_to_stream_time (&stream->segment, GST_FORMAT_TIME,
4299         timestamp);
4300     if (GST_CLOCK_TIME_IS_VALID (stream_time)) {
4301       GST_LOG_OBJECT (qtdemux,
4302           "adding association %" GST_TIME_FORMAT "-> %"
4303           G_GUINT64_FORMAT, GST_TIME_ARGS (stream_time), byte_position);
4304       gst_index_add_association (qtdemux->element_index,
4305           qtdemux->index_id,
4306           keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
4307           GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, stream_time,
4308           GST_FORMAT_BYTES, byte_position, NULL);
4309     }
4310   }
4311 #endif
4312
4313   if (stream->need_clip)
4314     buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
4315
4316   if (G_UNLIKELY (buf == NULL))
4317     goto exit;
4318
4319   if (G_UNLIKELY (stream->discont)) {
4320     GST_LOG_OBJECT (qtdemux, "marking discont buffer");
4321     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4322     stream->discont = FALSE;
4323   } else {
4324     GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
4325   }
4326
4327   if (!keyframe) {
4328     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4329     stream->on_keyframe = FALSE;
4330   } else {
4331     stream->on_keyframe = TRUE;
4332   }
4333
4334
4335   GST_LOG_OBJECT (qtdemux,
4336       "Pushing buffer with dts %" GST_TIME_FORMAT ", pts %" GST_TIME_FORMAT
4337       ", duration %" GST_TIME_FORMAT " on pad %s", GST_TIME_ARGS (dts),
4338       GST_TIME_ARGS (pts), GST_TIME_ARGS (duration),
4339       GST_PAD_NAME (stream->pad));
4340
4341   ret = gst_pad_push (stream->pad, buf);
4342
4343   if (GST_CLOCK_TIME_IS_VALID (pts) && GST_CLOCK_TIME_IS_VALID (duration)) {
4344     /* mark position in stream, we'll need this to know when to send GAP event */
4345     stream->segment.position = pts + duration;
4346   }
4347
4348 exit:
4349   return ret;
4350 }
4351
4352 static const QtDemuxRandomAccessEntry *
4353 gst_qtdemux_stream_seek_fragment (GstQTDemux * qtdemux, QtDemuxStream * stream,
4354     GstClockTime pos, gboolean after)
4355 {
4356   QtDemuxRandomAccessEntry *entries = stream->ra_entries;
4357   guint n_entries = stream->n_ra_entries;
4358   guint i;
4359
4360   /* we assume the table is sorted */
4361   for (i = 0; i < n_entries; ++i) {
4362     if (entries[i].ts > pos)
4363       break;
4364   }
4365
4366   /* FIXME: maybe save first moof_offset somewhere instead, but for now it's
4367    * probably okay to assume that the index lists the very first fragment */
4368   if (i == 0)
4369     return &entries[0];
4370
4371   if (after)
4372     return &entries[i];
4373   else
4374     return &entries[i - 1];
4375 }
4376
4377 static gboolean
4378 gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
4379 {
4380   const QtDemuxRandomAccessEntry *best_entry = NULL;
4381   guint i;
4382
4383   GST_OBJECT_LOCK (qtdemux);
4384
4385   g_assert (qtdemux->n_streams > 0);
4386
4387   for (i = 0; i < qtdemux->n_streams; i++) {
4388     const QtDemuxRandomAccessEntry *entry;
4389     QtDemuxStream *stream;
4390     gboolean is_audio_or_video;
4391
4392     stream = qtdemux->streams[i];
4393
4394     g_free (stream->samples);
4395     stream->samples = NULL;
4396     stream->n_samples = 0;
4397     stream->stbl_index = -1;    /* no samples have yet been parsed */
4398     stream->sample_index = -1;
4399
4400     if (stream->ra_entries == NULL)
4401       continue;
4402
4403     if (stream->subtype == FOURCC_vide || stream->subtype == FOURCC_soun)
4404       is_audio_or_video = TRUE;
4405     else
4406       is_audio_or_video = FALSE;
4407
4408     entry =
4409         gst_qtdemux_stream_seek_fragment (qtdemux, stream,
4410         stream->time_position, !is_audio_or_video);
4411
4412     GST_INFO_OBJECT (stream->pad, "%" GST_TIME_FORMAT " at offset "
4413         "%" G_GUINT64_FORMAT, GST_TIME_ARGS (entry->ts), entry->moof_offset);
4414
4415     stream->pending_seek = entry;
4416
4417     /* decide position to jump to just based on audio/video tracks, not subs */
4418     if (!is_audio_or_video)
4419       continue;
4420
4421     if (best_entry == NULL || entry->moof_offset < best_entry->moof_offset)
4422       best_entry = entry;
4423   }
4424
4425   if (best_entry == NULL) {
4426     GST_OBJECT_UNLOCK (qtdemux);
4427     return FALSE;
4428   }
4429
4430   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
4431       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
4432       GST_TIME_ARGS (qtdemux->streams[0]->time_position),
4433       best_entry->moof_offset, GST_TIME_ARGS (best_entry->ts));
4434
4435   qtdemux->moof_offset = best_entry->moof_offset;
4436
4437   qtdemux_add_fragmented_samples (qtdemux);
4438
4439   GST_OBJECT_UNLOCK (qtdemux);
4440   return TRUE;
4441 }
4442
4443 static GstFlowReturn
4444 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
4445 {
4446   GstFlowReturn ret = GST_FLOW_OK;
4447   GstBuffer *buf = NULL;
4448   QtDemuxStream *stream;
4449   GstClockTime min_time;
4450   guint64 offset = 0;
4451   GstClockTime dts = GST_CLOCK_TIME_NONE;
4452   GstClockTime pts = GST_CLOCK_TIME_NONE;
4453   GstClockTime duration = 0;
4454   gboolean keyframe = FALSE;
4455   guint sample_size = 0;
4456   gboolean empty = 0;
4457   guint size;
4458   gint index;
4459   gint i;
4460
4461   gst_qtdemux_push_pending_newsegment (qtdemux);
4462
4463   if (qtdemux->fragmented_seek_pending) {
4464     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
4465     gst_qtdemux_do_fragmented_seek (qtdemux);
4466     GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
4467     qtdemux->fragmented_seek_pending = FALSE;
4468   }
4469
4470   /* Figure out the next stream sample to output, min_time is expressed in
4471    * global time and runs over the edit list segments. */
4472   min_time = G_MAXUINT64;
4473   index = -1;
4474   for (i = 0; i < qtdemux->n_streams; i++) {
4475     GstClockTime position;
4476
4477     stream = qtdemux->streams[i];
4478     position = stream->time_position;
4479
4480     /* position of -1 is EOS */
4481     if (position != GST_CLOCK_TIME_NONE && position < min_time) {
4482       min_time = position;
4483       index = i;
4484     }
4485   }
4486   /* all are EOS */
4487   if (G_UNLIKELY (index == -1)) {
4488     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
4489     goto eos;
4490   }
4491
4492   /* check for segment end */
4493   if (G_UNLIKELY (qtdemux->segment.stop != -1
4494           && ((qtdemux->segment.rate >= 0 && qtdemux->segment.stop <= min_time)
4495               || (qtdemux->segment.rate < 0
4496                   && qtdemux->segment.start > min_time))
4497           && qtdemux->streams[index]->on_keyframe)) {
4498     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
4499     qtdemux->streams[index]->time_position = GST_CLOCK_TIME_NONE;
4500     goto eos_stream;
4501   }
4502
4503   /* gap events for subtitle streams */
4504   for (i = 0; i < qtdemux->n_streams; i++) {
4505     stream = qtdemux->streams[i];
4506     if (stream->pad && (stream->subtype == FOURCC_subp
4507             || stream->subtype == FOURCC_text
4508             || stream->subtype == FOURCC_sbtl)) {
4509       /* send one second gap events until the stream catches up */
4510       /* gaps can only be sent after segment is activated (segment.stop is no longer -1) */
4511       while (GST_CLOCK_TIME_IS_VALID (stream->segment.stop) &&
4512           GST_CLOCK_TIME_IS_VALID (stream->segment.position) &&
4513           stream->segment.position + GST_SECOND < min_time) {
4514         GstEvent *gap =
4515             gst_event_new_gap (stream->segment.position, GST_SECOND);
4516         gst_pad_push_event (stream->pad, gap);
4517         stream->segment.position += GST_SECOND;
4518       }
4519     }
4520   }
4521
4522   stream = qtdemux->streams[index];
4523   if (stream->new_caps) {
4524     gst_qtdemux_configure_stream (qtdemux, stream);
4525     qtdemux_do_allocation (qtdemux, stream);
4526   }
4527
4528   /* fetch info for the current sample of this stream */
4529   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &empty,
4530               &offset, &sample_size, &dts, &pts, &duration, &keyframe)))
4531     goto eos_stream;
4532
4533   GST_DEBUG_OBJECT (qtdemux,
4534       "pushing from stream %d, empty %d offset %" G_GUINT64_FORMAT
4535       ", size %d, dts=%" GST_TIME_FORMAT ", pts=%" GST_TIME_FORMAT
4536       ", duration %" GST_TIME_FORMAT, index, empty, offset, sample_size,
4537       GST_TIME_ARGS (dts), GST_TIME_ARGS (pts), GST_TIME_ARGS (duration));
4538
4539   if (G_UNLIKELY (empty)) {
4540     /* empty segment, push a gap and move to the next one */
4541     gst_pad_push_event (stream->pad, gst_event_new_gap (pts, duration));
4542     stream->segment.position = pts + duration;
4543     goto next;
4544   }
4545
4546   /* hmm, empty sample, skip and move to next sample */
4547   if (G_UNLIKELY (sample_size <= 0))
4548     goto next;
4549
4550   /* last pushed sample was out of boundary, goto next sample */
4551   if (G_UNLIKELY (GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS))
4552     goto next;
4553
4554   if (stream->max_buffer_size == 0 || sample_size <= stream->max_buffer_size) {
4555     size = sample_size;
4556   } else {
4557     GST_DEBUG_OBJECT (qtdemux,
4558         "size %d larger than stream max_buffer_size %d, trimming",
4559         sample_size, stream->max_buffer_size);
4560     size =
4561         MIN (sample_size - stream->offset_in_sample, stream->max_buffer_size);
4562   }
4563
4564   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
4565       offset);
4566
4567   if (stream->use_allocator) {
4568     /* if we have a per-stream allocator, use it */
4569     buf = gst_buffer_new_allocate (stream->allocator, size, &stream->params);
4570   }
4571
4572   ret = gst_qtdemux_pull_atom (qtdemux, offset + stream->offset_in_sample,
4573       size, &buf);
4574   if (G_UNLIKELY (ret != GST_FLOW_OK))
4575     goto beach;
4576
4577   if (size != sample_size) {
4578     pts += gst_util_uint64_scale_int (GST_SECOND,
4579         stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4580     dts += gst_util_uint64_scale_int (GST_SECOND,
4581         stream->offset_in_sample / stream->bytes_per_frame, stream->timescale);
4582     duration = gst_util_uint64_scale_int (GST_SECOND,
4583         size / stream->bytes_per_frame, stream->timescale);
4584   }
4585
4586   ret = gst_qtdemux_decorate_and_push_buffer (qtdemux, stream, buf,
4587       dts, pts, duration, keyframe, min_time, offset);
4588
4589   if (size != sample_size) {
4590     QtDemuxSample *sample = &stream->samples[stream->sample_index];
4591     QtDemuxSegment *segment = &stream->segments[stream->segment_index];
4592
4593     GstClockTime time_position = QTSTREAMTIME_TO_GSTTIME (stream,
4594         sample->timestamp + stream->offset_in_sample / stream->bytes_per_frame);
4595     if (time_position >= segment->media_start) {
4596       /* inside the segment, update time_position, looks very familiar to
4597        * GStreamer segments, doesn't it? */
4598       stream->time_position = (time_position - segment->media_start) +
4599           segment->time;
4600     } else {
4601       /* not yet in segment, time does not yet increment. This means
4602        * that we are still prerolling keyframes to the decoder so it can
4603        * decode the first sample of the segment. */
4604       stream->time_position = segment->time;
4605     }
4606   }
4607
4608   /* combine flows */
4609   ret = gst_qtdemux_combine_flows (qtdemux, ret);
4610   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
4611    * we have no more data for the pad to push */
4612   if (ret == GST_FLOW_EOS)
4613     ret = GST_FLOW_OK;
4614
4615   stream->offset_in_sample += size;
4616   if (stream->offset_in_sample >= sample_size) {
4617     gst_qtdemux_advance_sample (qtdemux, stream);
4618   }
4619   goto beach;
4620
4621 next:
4622   gst_qtdemux_advance_sample (qtdemux, stream);
4623
4624 beach:
4625   return ret;
4626
4627   /* special cases */
4628 eos:
4629   {
4630     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
4631     ret = GST_FLOW_EOS;
4632     goto beach;
4633   }
4634 eos_stream:
4635   {
4636     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
4637     /* EOS will be raised if all are EOS */
4638     ret = GST_FLOW_OK;
4639     goto beach;
4640   }
4641 }
4642
4643 static void
4644 gst_qtdemux_loop (GstPad * pad)
4645 {
4646   GstQTDemux *qtdemux;
4647   guint64 cur_offset;
4648   GstFlowReturn ret;
4649
4650   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
4651
4652   cur_offset = qtdemux->offset;
4653   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
4654       cur_offset, qtdemux->state);
4655
4656   switch (qtdemux->state) {
4657     case QTDEMUX_STATE_INITIAL:
4658     case QTDEMUX_STATE_HEADER:
4659       ret = gst_qtdemux_loop_state_header (qtdemux);
4660       break;
4661     case QTDEMUX_STATE_MOVIE:
4662       ret = gst_qtdemux_loop_state_movie (qtdemux);
4663       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_EOS) {
4664         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
4665       }
4666       break;
4667     default:
4668       /* ouch */
4669       goto invalid_state;
4670   }
4671
4672   /* if something went wrong, pause */
4673   if (ret != GST_FLOW_OK)
4674     goto pause;
4675
4676 done:
4677   gst_object_unref (qtdemux);
4678   return;
4679
4680   /* ERRORS */
4681 invalid_state:
4682   {
4683     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4684         (NULL), ("streaming stopped, invalid state"));
4685     gst_pad_pause_task (pad);
4686     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4687     goto done;
4688   }
4689 pause:
4690   {
4691     const gchar *reason = gst_flow_get_name (ret);
4692
4693     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
4694
4695     gst_pad_pause_task (pad);
4696
4697     /* fatal errors need special actions */
4698     /* check EOS */
4699     if (ret == GST_FLOW_EOS) {
4700       if (qtdemux->n_streams == 0) {
4701         /* we have no streams, post an error */
4702         gst_qtdemux_post_no_playable_stream_error (qtdemux);
4703       }
4704       if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4705         gint64 stop;
4706
4707         if ((stop = qtdemux->segment.stop) == -1)
4708           stop = qtdemux->segment.duration;
4709
4710         if (qtdemux->segment.rate >= 0) {
4711           GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
4712           gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4713               gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4714                   GST_FORMAT_TIME, stop));
4715           gst_qtdemux_push_event (qtdemux,
4716               gst_event_new_segment_done (GST_FORMAT_TIME, stop));
4717         } else {
4718           /*  For Reverse Playback */
4719           GST_LOG_OBJECT (qtdemux, "Sending segment done, at start of segment");
4720           gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
4721               gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
4722                   GST_FORMAT_TIME, qtdemux->segment.start));
4723           gst_qtdemux_push_event (qtdemux,
4724               gst_event_new_segment_done (GST_FORMAT_TIME,
4725                   qtdemux->segment.start));
4726         }
4727       } else {
4728         GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
4729         gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4730       }
4731     } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
4732       GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
4733           (NULL), ("streaming stopped, reason %s", reason));
4734       gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
4735     }
4736     goto done;
4737   }
4738 }
4739
4740 /*
4741  * has_next_entry
4742  *
4743  * Returns if there are samples to be played.
4744  */
4745 static gboolean
4746 has_next_entry (GstQTDemux * demux)
4747 {
4748   QtDemuxStream *stream;
4749   int i;
4750
4751   GST_DEBUG_OBJECT (demux, "Checking if there are samples not played yet");
4752
4753   for (i = 0; i < demux->n_streams; i++) {
4754     stream = demux->streams[i];
4755
4756     if (stream->sample_index == -1) {
4757       stream->sample_index = 0;
4758       stream->offset_in_sample = 0;
4759     }
4760
4761     if (stream->sample_index >= stream->n_samples) {
4762       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4763       continue;
4764     }
4765     GST_DEBUG_OBJECT (demux, "Found a sample");
4766     return TRUE;
4767   }
4768
4769   GST_DEBUG_OBJECT (demux, "There wasn't any next sample");
4770   return FALSE;
4771 }
4772
4773 /*
4774  * next_entry_size
4775  *
4776  * Returns the size of the first entry at the current offset.
4777  * If -1, there are none (which means EOS or empty file).
4778  */
4779 static guint64
4780 next_entry_size (GstQTDemux * demux)
4781 {
4782   QtDemuxStream *stream;
4783   int i;
4784   int smallidx = -1;
4785   guint64 smalloffs = (guint64) - 1;
4786   QtDemuxSample *sample;
4787
4788   GST_LOG_OBJECT (demux, "Finding entry at offset %" G_GUINT64_FORMAT,
4789       demux->offset);
4790
4791   for (i = 0; i < demux->n_streams; i++) {
4792     stream = demux->streams[i];
4793
4794     if (stream->sample_index == -1) {
4795       stream->sample_index = 0;
4796       stream->offset_in_sample = 0;
4797     }
4798
4799     if (stream->sample_index >= stream->n_samples) {
4800       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
4801       continue;
4802     }
4803
4804     if (!qtdemux_parse_samples (demux, stream, stream->sample_index)) {
4805       GST_LOG_OBJECT (demux, "Parsing of index %u from stbl atom failed!",
4806           stream->sample_index);
4807       return -1;
4808     }
4809
4810     sample = &stream->samples[stream->sample_index];
4811
4812     GST_LOG_OBJECT (demux,
4813         "Checking Stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
4814         " / size:%" G_GUINT32_FORMAT ")", i, stream->sample_index,
4815         sample->offset, sample->size);
4816
4817     if (((smalloffs == -1)
4818             || (sample->offset < smalloffs)) && (sample->size)) {
4819       smallidx = i;
4820       smalloffs = sample->offset;
4821     }
4822   }
4823
4824   GST_LOG_OBJECT (demux,
4825       "stream %d offset %" G_GUINT64_FORMAT " demux->offset :%"
4826       G_GUINT64_FORMAT, smallidx, smalloffs, demux->offset);
4827
4828   if (smallidx == -1)
4829     return -1;
4830
4831   stream = demux->streams[smallidx];
4832   sample = &stream->samples[stream->sample_index];
4833
4834   if (sample->offset >= demux->offset) {
4835     demux->todrop = sample->offset - demux->offset;
4836     return sample->size + demux->todrop;
4837   }
4838
4839   GST_DEBUG_OBJECT (demux,
4840       "There wasn't any entry at offset %" G_GUINT64_FORMAT, demux->offset);
4841   return -1;
4842 }
4843
4844 static void
4845 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
4846 {
4847   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
4848
4849   gst_element_post_message (GST_ELEMENT_CAST (demux),
4850       gst_message_new_element (GST_OBJECT_CAST (demux),
4851           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
4852 }
4853
4854 static gboolean
4855 qtdemux_seek_offset (GstQTDemux * demux, guint64 offset)
4856 {
4857   GstEvent *event;
4858   gboolean res = 0;
4859
4860   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
4861
4862   event =
4863       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
4864       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
4865       GST_SEEK_TYPE_NONE, -1);
4866
4867   res = gst_pad_push_event (demux->sinkpad, event);
4868
4869   return res;
4870 }
4871
4872 /* check for seekable upstream, above and beyond a mere query */
4873 static void
4874 gst_qtdemux_check_seekability (GstQTDemux * demux)
4875 {
4876   GstQuery *query;
4877   gboolean seekable = FALSE;
4878   gint64 start = -1, stop = -1;
4879
4880   if (demux->upstream_size)
4881     return;
4882
4883   query = gst_query_new_seeking (GST_FORMAT_BYTES);
4884   if (!gst_pad_peer_query (demux->sinkpad, query)) {
4885     GST_DEBUG_OBJECT (demux, "seeking query failed");
4886     goto done;
4887   }
4888
4889   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
4890
4891   /* try harder to query upstream size if we didn't get it the first time */
4892   if (seekable && stop == -1) {
4893     GST_DEBUG_OBJECT (demux, "doing duration query to fix up unset stop");
4894     gst_pad_peer_query_duration (demux->sinkpad, GST_FORMAT_BYTES, &stop);
4895   }
4896
4897   /* if upstream doesn't know the size, it's likely that it's not seekable in
4898    * practice even if it technically may be seekable */
4899   if (seekable && (start != 0 || stop <= start)) {
4900     GST_DEBUG_OBJECT (demux, "seekable but unknown start/stop -> disable");
4901     seekable = FALSE;
4902   }
4903
4904 done:
4905   gst_query_unref (query);
4906
4907   GST_DEBUG_OBJECT (demux, "seekable: %d (%" G_GUINT64_FORMAT " - %"
4908       G_GUINT64_FORMAT ")", seekable, start, stop);
4909   demux->upstream_seekable = seekable;
4910   demux->upstream_size = seekable ? stop : -1;
4911 }
4912
4913 /* FIXME, unverified after edit list updates */
4914 static GstFlowReturn
4915 gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
4916 {
4917   GstQTDemux *demux;
4918
4919   demux = GST_QTDEMUX (parent);
4920
4921   if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT)) {
4922     gint i;
4923
4924     GST_DEBUG_OBJECT (demux, "Got DISCONT, marking all streams as DISCONT");
4925
4926     for (i = 0; i < demux->n_streams; i++) {
4927       demux->streams[i]->discont = TRUE;
4928     }
4929   }
4930
4931   gst_adapter_push (demux->adapter, inbuf);
4932
4933   GST_DEBUG_OBJECT (demux,
4934       "pushing in inbuf %p, neededbytes:%u, available:%" G_GSIZE_FORMAT, inbuf,
4935       demux->neededbytes, gst_adapter_available (demux->adapter));
4936
4937   return gst_qtdemux_process_adapter (demux, FALSE);
4938 }
4939
4940 static GstFlowReturn
4941 gst_qtdemux_process_adapter (GstQTDemux * demux, gboolean force)
4942 {
4943   GstFlowReturn ret = GST_FLOW_OK;
4944
4945   /* we never really mean to buffer that much */
4946   if (demux->neededbytes == -1) {
4947     goto eos;
4948   }
4949
4950   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
4951       (ret == GST_FLOW_OK || (ret == GST_FLOW_NOT_LINKED && force))) {
4952
4953     GST_DEBUG_OBJECT (demux,
4954         "state:%d , demux->neededbytes:%d, demux->offset:%" G_GUINT64_FORMAT,
4955         demux->state, demux->neededbytes, demux->offset);
4956
4957     switch (demux->state) {
4958       case QTDEMUX_STATE_INITIAL:{
4959         const guint8 *data;
4960         guint32 fourcc;
4961         guint64 size;
4962
4963         gst_qtdemux_check_seekability (demux);
4964
4965         data = gst_adapter_map (demux->adapter, demux->neededbytes);
4966
4967         /* get fourcc/length, set neededbytes */
4968         extract_initial_length_and_fourcc ((guint8 *) data, demux->neededbytes,
4969             &size, &fourcc);
4970         gst_adapter_unmap (demux->adapter);
4971         data = NULL;
4972         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
4973             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
4974         if (size == 0) {
4975           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
4976               (_("This file is invalid and cannot be played.")),
4977               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
4978                   GST_FOURCC_ARGS (fourcc)));
4979           ret = GST_FLOW_ERROR;
4980           break;
4981         }
4982         if (fourcc == FOURCC_mdat) {
4983           gint next_entry = next_entry_size (demux);
4984           if (demux->n_streams > 0 && (next_entry != -1 || !demux->fragmented)) {
4985             /* we have the headers, start playback */
4986             demux->state = QTDEMUX_STATE_MOVIE;
4987             demux->neededbytes = next_entry;
4988             demux->mdatleft = size;
4989           } else {
4990             /* no headers yet, try to get them */
4991             guint bs;
4992             gboolean res;
4993             guint64 old, target;
4994
4995           buffer_data:
4996             old = demux->offset;
4997             target = old + size;
4998
4999             /* try to jump over the atom with a seek */
5000             /* only bother if it seems worth doing so,
5001              * and avoids possible upstream/server problems */
5002             if (demux->upstream_seekable &&
5003                 demux->upstream_size > 4 * (1 << 20)) {
5004               res = qtdemux_seek_offset (demux, target);
5005             } else {
5006               GST_DEBUG_OBJECT (demux, "skipping seek");
5007               res = FALSE;
5008             }
5009
5010             if (res) {
5011               GST_DEBUG_OBJECT (demux, "seek success");
5012               /* remember the offset fo the first mdat so we can seek back to it
5013                * after we have the headers */
5014               if (fourcc == FOURCC_mdat && demux->first_mdat == -1) {
5015                 demux->first_mdat = old;
5016                 GST_DEBUG_OBJECT (demux, "first mdat at %" G_GUINT64_FORMAT,
5017                     demux->first_mdat);
5018               }
5019               /* seek worked, continue reading */
5020               demux->offset = target;
5021               demux->neededbytes = 16;
5022               demux->state = QTDEMUX_STATE_INITIAL;
5023             } else {
5024               /* seek failed, need to buffer */
5025               demux->offset = old;
5026               GST_DEBUG_OBJECT (demux, "seek failed/skipped");
5027               /* there may be multiple mdat (or alike) buffers */
5028               /* sanity check */
5029               if (demux->mdatbuffer)
5030                 bs = gst_buffer_get_size (demux->mdatbuffer);
5031               else
5032                 bs = 0;
5033               if (size + bs > 10 * (1 << 20))
5034                 goto no_moov;
5035               demux->state = QTDEMUX_STATE_BUFFER_MDAT;
5036               demux->neededbytes = size;
5037               if (!demux->mdatbuffer)
5038                 demux->mdatoffset = demux->offset;
5039             }
5040           }
5041         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
5042           GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5043               (_("This file is invalid and cannot be played.")),
5044               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
5045                   GST_FOURCC_ARGS (fourcc), size));
5046           ret = GST_FLOW_ERROR;
5047           break;
5048         } else {
5049           /* this means we already started buffering and still no moov header,
5050            * let's continue buffering everything till we get moov */
5051           if (demux->mdatbuffer && !(fourcc == FOURCC_moov
5052                   || fourcc == FOURCC_moof))
5053             goto buffer_data;
5054           demux->neededbytes = size;
5055           demux->state = QTDEMUX_STATE_HEADER;
5056         }
5057         break;
5058       }
5059       case QTDEMUX_STATE_HEADER:{
5060         const guint8 *data;
5061         guint32 fourcc;
5062
5063         GST_DEBUG_OBJECT (demux, "In header");
5064
5065         data = gst_adapter_map (demux->adapter, demux->neededbytes);
5066
5067         /* parse the header */
5068         extract_initial_length_and_fourcc (data, demux->neededbytes, NULL,
5069             &fourcc);
5070         if (fourcc == FOURCC_moov) {
5071           /* in usual fragmented setup we could try to scan for more
5072            * and end up at the the moov (after mdat) again */
5073           if (demux->got_moov && demux->n_streams > 0 &&
5074               (!demux->fragmented
5075                   || demux->last_moov_offset == demux->offset)) {
5076             GST_DEBUG_OBJECT (demux,
5077                 "Skipping moov atom as we have (this) one already");
5078           } else {
5079             GST_DEBUG_OBJECT (demux, "Parsing [moov]");
5080
5081             if (demux->got_moov && demux->fragmented) {
5082               GST_DEBUG_OBJECT (demux,
5083                   "Got a second moov, clean up data from old one");
5084               if (demux->moov_node)
5085                 g_node_destroy (demux->moov_node);
5086               demux->moov_node = NULL;
5087               demux->moov_node_compressed = NULL;
5088             } else {
5089               /* prepare newsegment to send when streaming actually starts */
5090               if (!demux->pending_newsegment)
5091                 demux->pending_newsegment =
5092                     gst_event_new_segment (&demux->segment);
5093             }
5094
5095             demux->last_moov_offset = demux->offset;
5096
5097             qtdemux_parse_moov (demux, data, demux->neededbytes);
5098             qtdemux_node_dump (demux, demux->moov_node);
5099             qtdemux_parse_tree (demux);
5100             qtdemux_prepare_streams (demux);
5101             if (!demux->got_moov)
5102               qtdemux_expose_streams (demux);
5103             else {
5104               gint n;
5105
5106               for (n = 0; n < demux->n_streams; n++) {
5107                 QtDemuxStream *stream = demux->streams[n];
5108
5109                 gst_qtdemux_configure_stream (demux, stream);
5110               }
5111             }
5112
5113             demux->got_moov = TRUE;
5114
5115             g_node_destroy (demux->moov_node);
5116             demux->moov_node = NULL;
5117             GST_DEBUG_OBJECT (demux, "Finished parsing the header");
5118           }
5119         } else if (fourcc == FOURCC_moof) {
5120           if ((demux->got_moov || demux->media_caps) && demux->fragmented) {
5121             guint64 dist = 0;
5122             GstClockTime prev_pts;
5123             guint64 prev_offset;
5124
5125             GST_DEBUG_OBJECT (demux, "Parsing [moof]");
5126
5127             /*
5128              * The timestamp of the moof buffer is relevant as some scenarios
5129              * won't have the initial timestamp in the atoms. Whenever a new
5130              * buffer has started, we get that buffer's PTS and use it as a base
5131              * timestamp for the trun entries.
5132              *
5133              * To keep track of the current buffer timestamp and starting point
5134              * we use gst_adapter_prev_pts that gives us the PTS and the distance
5135              * from the beggining of the buffer, with the distance and demux->offset
5136              * we know if it is still the same buffer or not.
5137              */
5138             prev_pts = gst_adapter_prev_pts (demux->adapter, &dist);
5139             prev_offset = demux->offset - dist;
5140             if (demux->fragment_start_offset == -1
5141                 || prev_offset > demux->fragment_start_offset) {
5142               demux->fragment_start_offset = prev_offset;
5143               demux->fragment_start = prev_pts;
5144               GST_DEBUG_OBJECT (demux,
5145                   "New fragment start found at: %" G_GUINT64_FORMAT " : %"
5146                   GST_TIME_FORMAT, demux->fragment_start_offset,
5147                   GST_TIME_ARGS (demux->fragment_start));
5148             }
5149
5150             if (!qtdemux_parse_moof (demux, data, demux->neededbytes,
5151                     demux->offset, NULL)) {
5152               gst_adapter_unmap (demux->adapter);
5153               ret = GST_FLOW_ERROR;
5154               goto done;
5155             }
5156             /* in MSS we need to expose the pads after the first moof as we won't get a moov */
5157             if (demux->mss_mode && !demux->exposed) {
5158               if (!demux->pending_newsegment) {
5159                 GstSegment segment;
5160                 gst_segment_init (&segment, GST_FORMAT_TIME);
5161                 GST_DEBUG_OBJECT (demux, "new pending_newsegment");
5162                 demux->pending_newsegment = gst_event_new_segment (&segment);
5163               }
5164               qtdemux_expose_streams (demux);
5165             }
5166           } else {
5167             GST_DEBUG_OBJECT (demux, "Discarding [moof]");
5168           }
5169         } else if (fourcc == FOURCC_ftyp) {
5170           GST_DEBUG_OBJECT (demux, "Parsing [ftyp]");
5171           qtdemux_parse_ftyp (demux, data, demux->neededbytes);
5172         } else if (fourcc == FOURCC_uuid) {
5173           GST_DEBUG_OBJECT (demux, "Parsing [uuid]");
5174           qtdemux_parse_uuid (demux, data, demux->neededbytes);
5175         } else {
5176           GST_WARNING_OBJECT (demux,
5177               "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
5178               GST_FOURCC_ARGS (fourcc));
5179           /* Let's jump that one and go back to initial state */
5180         }
5181         gst_adapter_unmap (demux->adapter);
5182         data = NULL;
5183
5184         if (demux->mdatbuffer && demux->n_streams) {
5185           gsize remaining_data_size = 0;
5186
5187           /* the mdat was before the header */
5188           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
5189               demux->n_streams, demux->mdatbuffer);
5190           /* restore our adapter/offset view of things with upstream;
5191            * put preceding buffered data ahead of current moov data.
5192            * This should also handle evil mdat, moov, mdat cases and alike */
5193           gst_adapter_flush (demux->adapter, demux->neededbytes);
5194
5195           /* Store any remaining data after the mdat for later usage */
5196           remaining_data_size = gst_adapter_available (demux->adapter);
5197           if (remaining_data_size > 0) {
5198             g_assert (demux->restoredata_buffer == NULL);
5199             demux->restoredata_buffer =
5200                 gst_adapter_take_buffer (demux->adapter, remaining_data_size);
5201             demux->restoredata_offset = demux->offset + demux->neededbytes;
5202             GST_DEBUG_OBJECT (demux,
5203                 "Stored %" G_GSIZE_FORMAT " post mdat bytes at offset %"
5204                 G_GUINT64_FORMAT, remaining_data_size,
5205                 demux->restoredata_offset);
5206           }
5207
5208           gst_adapter_push (demux->adapter, demux->mdatbuffer);
5209           demux->mdatbuffer = NULL;
5210           demux->offset = demux->mdatoffset;
5211           demux->neededbytes = next_entry_size (demux);
5212           demux->state = QTDEMUX_STATE_MOVIE;
5213           demux->mdatleft = gst_adapter_available (demux->adapter);
5214         } else {
5215           GST_DEBUG_OBJECT (demux, "Carrying on normally");
5216           gst_adapter_flush (demux->adapter, demux->neededbytes);
5217
5218           /* only go back to the mdat if there are samples to play */
5219           if (demux->got_moov && demux->first_mdat != -1
5220               && has_next_entry (demux)) {
5221             gboolean res;
5222
5223             /* we need to seek back */
5224             res = qtdemux_seek_offset (demux, demux->first_mdat);
5225             if (res) {
5226               demux->offset = demux->first_mdat;
5227             } else {
5228               GST_DEBUG_OBJECT (demux, "Seek back failed");
5229             }
5230           } else {
5231             demux->offset += demux->neededbytes;
5232           }
5233           demux->neededbytes = 16;
5234           demux->state = QTDEMUX_STATE_INITIAL;
5235         }
5236
5237         break;
5238       }
5239       case QTDEMUX_STATE_BUFFER_MDAT:{
5240         GstBuffer *buf;
5241         guint8 fourcc[4];
5242
5243         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %" G_GUINT64_FORMAT,
5244             demux->offset);
5245         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5246         gst_buffer_extract (buf, 0, fourcc, 4);
5247         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
5248             GST_FOURCC_ARGS (QT_FOURCC (fourcc)));
5249         if (demux->mdatbuffer)
5250           demux->mdatbuffer = gst_buffer_append (demux->mdatbuffer, buf);
5251         else
5252           demux->mdatbuffer = buf;
5253         demux->offset += demux->neededbytes;
5254         demux->neededbytes = 16;
5255         demux->state = QTDEMUX_STATE_INITIAL;
5256         gst_qtdemux_post_progress (demux, 1, 1);
5257
5258         break;
5259       }
5260       case QTDEMUX_STATE_MOVIE:{
5261         GstBuffer *outbuf;
5262         QtDemuxStream *stream = NULL;
5263         QtDemuxSample *sample;
5264         int i = -1;
5265         GstClockTime dts, pts, duration;
5266         gboolean keyframe;
5267
5268         GST_DEBUG_OBJECT (demux,
5269             "BEGIN // in MOVIE for offset %" G_GUINT64_FORMAT, demux->offset);
5270
5271         if (demux->fragmented) {
5272           GST_DEBUG_OBJECT (demux, "mdat remaining %" G_GUINT64_FORMAT,
5273               demux->mdatleft);
5274           if (G_LIKELY (demux->todrop < demux->mdatleft)) {
5275             /* if needed data starts within this atom,
5276              * then it should not exceed this atom */
5277             if (G_UNLIKELY (demux->neededbytes > demux->mdatleft)) {
5278               GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
5279                   (_("This file is invalid and cannot be played.")),
5280                   ("sample data crosses atom boundary"));
5281               ret = GST_FLOW_ERROR;
5282               break;
5283             }
5284             demux->mdatleft -= demux->neededbytes;
5285           } else {
5286             GST_DEBUG_OBJECT (demux, "data atom emptied; resuming atom scan");
5287             /* so we are dropping more than left in this atom */
5288             demux->todrop -= demux->mdatleft;
5289             demux->neededbytes -= demux->mdatleft;
5290             demux->mdatleft = 0;
5291             /* need to resume atom parsing so we do not miss any other pieces */
5292             demux->state = QTDEMUX_STATE_INITIAL;
5293             demux->neededbytes = 16;
5294
5295             /* check if there was any stored post mdat data from previous buffers */
5296             if (demux->restoredata_buffer) {
5297               g_assert (gst_adapter_available (demux->adapter) == 0);
5298
5299               gst_adapter_push (demux->adapter, demux->restoredata_buffer);
5300               demux->restoredata_buffer = NULL;
5301               demux->offset = demux->restoredata_offset;
5302             }
5303
5304             break;
5305           }
5306         }
5307
5308         if (demux->todrop) {
5309           GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
5310           gst_adapter_flush (demux->adapter, demux->todrop);
5311           demux->neededbytes -= demux->todrop;
5312           demux->offset += demux->todrop;
5313         }
5314
5315         /* first buffer? */
5316         /* initial newsegment sent here after having added pads,
5317          * possible others in sink_event */
5318         if (G_UNLIKELY (demux->pending_newsegment)) {
5319           gst_qtdemux_push_pending_newsegment (demux);
5320           /* clear to send tags on all streams */
5321           for (i = 0; i < demux->n_streams; i++) {
5322             stream = demux->streams[i];
5323             gst_qtdemux_push_tags (demux, stream);
5324             if (stream->sparse) {
5325               GST_INFO_OBJECT (demux, "Sending gap event on stream %d", i);
5326               gst_pad_push_event (stream->pad,
5327                   gst_event_new_gap (stream->segment.position,
5328                       GST_CLOCK_TIME_NONE));
5329             }
5330           }
5331         }
5332
5333         /* Figure out which stream this packet belongs to */
5334         for (i = 0; i < demux->n_streams; i++) {
5335           stream = demux->streams[i];
5336           if (stream->sample_index >= stream->n_samples)
5337             continue;
5338           GST_LOG_OBJECT (demux,
5339               "Checking stream %d (sample_index:%d / offset:%" G_GUINT64_FORMAT
5340               " / size:%d)", i, stream->sample_index,
5341               stream->samples[stream->sample_index].offset,
5342               stream->samples[stream->sample_index].size);
5343
5344           if (stream->samples[stream->sample_index].offset == demux->offset)
5345             break;
5346         }
5347
5348         if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
5349           goto unknown_stream;
5350
5351         if (stream->new_caps) {
5352           gst_qtdemux_configure_stream (demux, stream);
5353         }
5354
5355         /* Put data in a buffer, set timestamps, caps, ... */
5356         sample = &stream->samples[stream->sample_index];
5357
5358         if (G_LIKELY (!(STREAM_IS_EOS (stream)))) {
5359           outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
5360           GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
5361               GST_FOURCC_ARGS (stream->fourcc));
5362
5363           g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
5364
5365           dts = QTSAMPLE_DTS (stream, sample);
5366           pts = QTSAMPLE_PTS (stream, sample);
5367           duration = QTSAMPLE_DUR_DTS (stream, sample, dts);
5368           keyframe = QTSAMPLE_KEYFRAME (stream, sample);
5369
5370           /* check for segment end */
5371           if (G_UNLIKELY (demux->segment.stop != -1
5372                   && demux->segment.stop <= pts && stream->on_keyframe)) {
5373             GST_DEBUG_OBJECT (demux, "we reached the end of our segment.");
5374             stream->time_position = GST_CLOCK_TIME_NONE;        /* this means EOS */
5375
5376             /* check if all streams are eos */
5377             ret = GST_FLOW_EOS;
5378             for (i = 0; i < demux->n_streams; i++) {
5379               if (!STREAM_IS_EOS (demux->streams[i])) {
5380                 ret = GST_FLOW_OK;
5381                 break;
5382               }
5383             }
5384
5385             if (ret == GST_FLOW_EOS) {
5386               GST_DEBUG_OBJECT (demux, "All streams are EOS, signal upstream");
5387               goto eos;
5388             }
5389           } else {
5390             ret = gst_qtdemux_decorate_and_push_buffer (demux, stream, outbuf,
5391                 dts, pts, duration, keyframe, dts, demux->offset);
5392           }
5393
5394           /* combine flows */
5395           ret = gst_qtdemux_combine_flows (demux, ret);
5396         } else {
5397           /* skip this data, stream is EOS */
5398           gst_adapter_flush (demux->adapter, demux->neededbytes);
5399         }
5400
5401         stream->sample_index++;
5402         stream->offset_in_sample = 0;
5403
5404         /* update current offset and figure out size of next buffer */
5405         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
5406             demux->offset, demux->neededbytes);
5407         demux->offset += demux->neededbytes;
5408         GST_LOG_OBJECT (demux, "offset is now %" G_GUINT64_FORMAT,
5409             demux->offset);
5410
5411         if ((demux->neededbytes = next_entry_size (demux)) == -1) {
5412           if (demux->fragmented) {
5413             GST_DEBUG_OBJECT (demux, "(temporarily) out of fragmented samples");
5414             /* there may be more to follow, only finish this atom */
5415             demux->todrop = demux->mdatleft;
5416             demux->neededbytes = demux->todrop;
5417             break;
5418           }
5419           goto eos;
5420         }
5421         break;
5422       }
5423       default:
5424         goto invalid_state;
5425     }
5426   }
5427
5428   /* when buffering movie data, at least show user something is happening */
5429   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
5430       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
5431     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
5432         demux->neededbytes);
5433   }
5434 done:
5435
5436   return ret;
5437
5438   /* ERRORS */
5439 unknown_stream:
5440   {
5441     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
5442     ret = GST_FLOW_ERROR;
5443     goto done;
5444   }
5445 eos:
5446   {
5447     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
5448     ret = GST_FLOW_EOS;
5449     goto done;
5450   }
5451 invalid_state:
5452   {
5453     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5454         (NULL), ("qtdemuxer invalid state %d", demux->state));
5455     ret = GST_FLOW_ERROR;
5456     goto done;
5457   }
5458 no_moov:
5459   {
5460     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
5461         (NULL), ("no 'moov' atom within the first 10 MB"));
5462     ret = GST_FLOW_ERROR;
5463     goto done;
5464   }
5465 }
5466
5467 static gboolean
5468 qtdemux_sink_activate (GstPad * sinkpad, GstObject * parent)
5469 {
5470   GstQuery *query;
5471   gboolean pull_mode;
5472
5473   query = gst_query_new_scheduling ();
5474
5475   if (!gst_pad_peer_query (sinkpad, query)) {
5476     gst_query_unref (query);
5477     goto activate_push;
5478   }
5479
5480   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5481       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5482   gst_query_unref (query);
5483
5484   if (!pull_mode)
5485     goto activate_push;
5486
5487   GST_DEBUG_OBJECT (sinkpad, "activating pull");
5488   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5489
5490 activate_push:
5491   {
5492     GST_DEBUG_OBJECT (sinkpad, "activating push");
5493     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5494   }
5495 }
5496
5497 static gboolean
5498 qtdemux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5499     GstPadMode mode, gboolean active)
5500 {
5501   gboolean res;
5502   GstQTDemux *demux = GST_QTDEMUX (parent);
5503
5504   switch (mode) {
5505     case GST_PAD_MODE_PUSH:
5506       demux->pullbased = FALSE;
5507       res = TRUE;
5508       break;
5509     case GST_PAD_MODE_PULL:
5510       if (active) {
5511         demux->pullbased = TRUE;
5512         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
5513             sinkpad, NULL);
5514       } else {
5515         res = gst_pad_stop_task (sinkpad);
5516       }
5517       break;
5518     default:
5519       res = FALSE;
5520       break;
5521   }
5522   return res;
5523 }
5524
5525 #ifdef HAVE_ZLIB
5526 static void *
5527 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
5528 {
5529   return g_malloc (items * size);
5530 }
5531
5532 static void
5533 qtdemux_zfree (void *opaque, void *addr)
5534 {
5535   g_free (addr);
5536 }
5537
5538 static void *
5539 qtdemux_inflate (void *z_buffer, guint z_length, guint length)
5540 {
5541   guint8 *buffer;
5542   z_stream *z;
5543   int ret;
5544
5545   z = g_new0 (z_stream, 1);
5546   z->zalloc = qtdemux_zalloc;
5547   z->zfree = qtdemux_zfree;
5548   z->opaque = NULL;
5549
5550   z->next_in = z_buffer;
5551   z->avail_in = z_length;
5552
5553   buffer = (guint8 *) g_malloc (length);
5554   ret = inflateInit (z);
5555   while (z->avail_in > 0) {
5556     if (z->avail_out == 0) {
5557       length += 1024;
5558       buffer = (guint8 *) g_realloc (buffer, length);
5559       z->next_out = buffer + z->total_out;
5560       z->avail_out = 1024;
5561     }
5562     ret = inflate (z, Z_SYNC_FLUSH);
5563     if (ret != Z_OK)
5564       break;
5565   }
5566   if (ret != Z_STREAM_END) {
5567     g_warning ("inflate() returned %d", ret);
5568   }
5569
5570   g_free (z);
5571   return buffer;
5572 }
5573 #endif /* HAVE_ZLIB */
5574
5575 static gboolean
5576 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, guint length)
5577 {
5578   GNode *cmov;
5579
5580   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
5581
5582   /* counts as header data */
5583   qtdemux->header_size += length;
5584
5585   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
5586   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
5587
5588   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
5589   if (cmov) {
5590     guint32 method;
5591     GNode *dcom;
5592     GNode *cmvd;
5593
5594     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
5595     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
5596     if (dcom == NULL || cmvd == NULL)
5597       goto invalid_compression;
5598
5599     method = QT_FOURCC ((guint8 *) dcom->data + 8);
5600     switch (method) {
5601 #ifdef HAVE_ZLIB
5602       case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
5603         guint uncompressed_length;
5604         guint compressed_length;
5605         guint8 *buf;
5606
5607         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
5608         compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
5609         GST_LOG ("length = %u", uncompressed_length);
5610
5611         buf =
5612             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
5613             compressed_length, uncompressed_length);
5614
5615         qtdemux->moov_node_compressed = qtdemux->moov_node;
5616         qtdemux->moov_node = g_node_new (buf);
5617
5618         qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
5619             uncompressed_length);
5620         break;
5621       }
5622 #endif /* HAVE_ZLIB */
5623       default:
5624         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
5625             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
5626         break;
5627     }
5628   }
5629   return TRUE;
5630
5631   /* ERRORS */
5632 invalid_compression:
5633   {
5634     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
5635     return FALSE;
5636   }
5637 }
5638
5639 static gboolean
5640 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
5641     const guint8 * end)
5642 {
5643   while (G_UNLIKELY (buf < end)) {
5644     GNode *child;
5645     guint32 len;
5646
5647     if (G_UNLIKELY (buf + 4 > end)) {
5648       GST_LOG_OBJECT (qtdemux, "buffer overrun");
5649       break;
5650     }
5651     len = QT_UINT32 (buf);
5652     if (G_UNLIKELY (len == 0)) {
5653       GST_LOG_OBJECT (qtdemux, "empty container");
5654       break;
5655     }
5656     if (G_UNLIKELY (len < 8)) {
5657       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
5658       break;
5659     }
5660     if (G_UNLIKELY (len > (end - buf))) {
5661       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len,
5662           (gint) (end - buf));
5663       break;
5664     }
5665
5666     child = g_node_new ((guint8 *) buf);
5667     g_node_append (node, child);
5668     GST_LOG_OBJECT (qtdemux, "adding new node of len %d", len);
5669     qtdemux_parse_node (qtdemux, child, buf, len);
5670
5671     buf += len;
5672   }
5673   return TRUE;
5674 }
5675
5676 static gboolean
5677 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
5678     GNode * xdxt)
5679 {
5680   int len = QT_UINT32 (xdxt->data);
5681   guint8 *buf = xdxt->data;
5682   guint8 *end = buf + len;
5683   GstBuffer *buffer;
5684
5685   /* skip size and type */
5686   buf += 8;
5687   end -= 8;
5688
5689   while (buf < end) {
5690     gint size;
5691     guint32 type;
5692
5693     size = QT_UINT32 (buf);
5694     type = QT_FOURCC (buf + 4);
5695
5696     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
5697
5698     if (buf + size > end || size <= 0)
5699       break;
5700
5701     buf += 8;
5702     size -= 8;
5703
5704     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
5705         GST_FOURCC_ARGS (type));
5706
5707     switch (type) {
5708       case FOURCC_tCtH:
5709         buffer = gst_buffer_new_and_alloc (size);
5710         gst_buffer_fill (buffer, 0, buf, size);
5711         stream->buffers = g_slist_append (stream->buffers, buffer);
5712         GST_LOG_OBJECT (qtdemux, "parsing theora header");
5713         break;
5714       case FOURCC_tCt_:
5715         buffer = gst_buffer_new_and_alloc (size);
5716         gst_buffer_fill (buffer, 0, buf, size);
5717         stream->buffers = g_slist_append (stream->buffers, buffer);
5718         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
5719         break;
5720       case FOURCC_tCtC:
5721         buffer = gst_buffer_new_and_alloc (size);
5722         gst_buffer_fill (buffer, 0, buf, size);
5723         stream->buffers = g_slist_append (stream->buffers, buffer);
5724         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
5725         break;
5726       default:
5727         GST_WARNING_OBJECT (qtdemux,
5728             "unknown theora cookie %" GST_FOURCC_FORMAT,
5729             GST_FOURCC_ARGS (type));
5730         break;
5731     }
5732     buf += size;
5733   }
5734   return TRUE;
5735 }
5736
5737 static gboolean
5738 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
5739     guint length)
5740 {
5741   guint32 fourcc = 0;
5742   guint32 node_length = 0;
5743   const QtNodeType *type;
5744   const guint8 *end;
5745
5746   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %u", buffer, length);
5747
5748   if (G_UNLIKELY (length < 8))
5749     goto not_enough_data;
5750
5751   node_length = QT_UINT32 (buffer);
5752   fourcc = QT_FOURCC (buffer + 4);
5753
5754   /* ignore empty nodes */
5755   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
5756     return TRUE;
5757
5758   type = qtdemux_type_get (fourcc);
5759
5760   end = buffer + length;
5761
5762   GST_LOG_OBJECT (qtdemux,
5763       "parsing '%" GST_FOURCC_FORMAT "', length=%u, name '%s'",
5764       GST_FOURCC_ARGS (fourcc), node_length, type->name);
5765
5766   if (node_length > length)
5767     goto broken_atom_size;
5768
5769   if (type->flags & QT_FLAG_CONTAINER) {
5770     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
5771   } else {
5772     switch (fourcc) {
5773       case FOURCC_stsd:
5774       {
5775         if (node_length < 20) {
5776           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
5777           break;
5778         }
5779         GST_DEBUG_OBJECT (qtdemux,
5780             "parsing stsd (sample table, sample description) atom");
5781         /* Skip over 8 byte atom hdr + 1 byte version, 3 bytes flags, 4 byte num_entries */
5782         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5783         break;
5784       }
5785       case FOURCC_mp4a:
5786       case FOURCC_alac:
5787       {
5788         guint32 version;
5789         guint32 offset;
5790         guint min_size;
5791
5792         /* also read alac (or whatever) in stead of mp4a in the following,
5793          * since a similar layout is used in other cases as well */
5794         if (fourcc == FOURCC_mp4a)
5795           min_size = 20;
5796         else
5797           min_size = 40;
5798
5799         /* There are two things we might encounter here: a true mp4a atom, and
5800            an mp4a entry in an stsd atom. The latter is what we're interested
5801            in, and it looks like an atom, but isn't really one. The true mp4a
5802            atom is short, so we detect it based on length here. */
5803         if (length < min_size) {
5804           GST_LOG_OBJECT (qtdemux, "skipping small %" GST_FOURCC_FORMAT " box",
5805               GST_FOURCC_ARGS (fourcc));
5806           break;
5807         }
5808
5809         /* 'version' here is the sound sample description version. Types 0 and
5810            1 are documented in the QTFF reference, but type 2 is not: it's
5811            described in Apple header files instead (struct SoundDescriptionV2
5812            in Movies.h) */
5813         version = QT_UINT16 (buffer + 16);
5814
5815         GST_DEBUG_OBJECT (qtdemux, "%" GST_FOURCC_FORMAT " version 0x%08x",
5816             GST_FOURCC_ARGS (fourcc), version);
5817
5818         /* parse any esds descriptors */
5819         switch (version) {
5820           case 0:
5821             offset = 0x24;
5822             break;
5823           case 1:
5824             offset = 0x34;
5825             break;
5826           case 2:
5827             offset = 0x48;
5828             break;
5829           default:
5830             GST_WARNING_OBJECT (qtdemux,
5831                 "unhandled %" GST_FOURCC_FORMAT " version 0x%08x",
5832                 GST_FOURCC_ARGS (fourcc), version);
5833             offset = 0;
5834             break;
5835         }
5836         if (offset)
5837           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5838         break;
5839       }
5840       case FOURCC_mp4v:
5841       case FOURCC_MP4V:
5842       case FOURCC_fmp4:
5843       case FOURCC_FMP4:
5844       case FOURCC_apcs:
5845       case FOURCC_apch:
5846       case FOURCC_apcn:
5847       case FOURCC_apco:
5848       case FOURCC_ap4h:
5849       {
5850         const guint8 *buf;
5851         guint32 version;
5852         int tlen;
5853
5854         /* codec_data is contained inside these atoms, which all have
5855          * the same format. */
5856
5857         GST_DEBUG_OBJECT (qtdemux, "parsing in %" GST_FOURCC_FORMAT,
5858             GST_FOURCC_ARGS (fourcc));
5859         version = QT_UINT32 (buffer + 16);
5860         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
5861         if (1 || version == 0x00000000) {
5862           buf = buffer + 0x32;
5863
5864           /* FIXME Quicktime uses PASCAL string while
5865            * the iso format uses C strings. Check the file
5866            * type before attempting to parse the string here. */
5867           tlen = QT_UINT8 (buf);
5868           GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
5869           buf++;
5870           GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
5871           /* the string has a reserved space of 32 bytes so skip
5872            * the remaining 31 */
5873           buf += 31;
5874           buf += 4;             /* and 4 bytes reserved */
5875
5876           GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
5877
5878           qtdemux_parse_container (qtdemux, node, buf, end);
5879         }
5880         break;
5881       }
5882       case FOURCC_H264:
5883       {
5884         GST_MEMDUMP_OBJECT (qtdemux, "H264", buffer, end - buffer);
5885         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5886         break;
5887       }
5888       case FOURCC_avc1:
5889       {
5890         GST_MEMDUMP_OBJECT (qtdemux, "avc1", buffer, end - buffer);
5891         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5892         break;
5893       }
5894       case FOURCC_avc3:
5895       {
5896         GST_MEMDUMP_OBJECT (qtdemux, "avc3", buffer, end - buffer);
5897         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5898         break;
5899       }
5900       case FOURCC_H265:
5901       {
5902         GST_MEMDUMP_OBJECT (qtdemux, "H265", buffer, end - buffer);
5903         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5904         break;
5905       }
5906       case FOURCC_hvc1:
5907       {
5908         GST_MEMDUMP_OBJECT (qtdemux, "hvc1", buffer, end - buffer);
5909         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5910         break;
5911       }
5912       case FOURCC_hev1:
5913       {
5914         GST_MEMDUMP_OBJECT (qtdemux, "hev1", buffer, end - buffer);
5915         qtdemux_parse_container (qtdemux, node, buffer + 0x56, end);
5916         break;
5917       }
5918       case FOURCC_mjp2:
5919       {
5920         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
5921         break;
5922       }
5923       case FOURCC_meta:
5924       {
5925         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
5926         qtdemux_parse_container (qtdemux, node, buffer + 12, end);
5927         break;
5928       }
5929       case FOURCC_mp4s:
5930       {
5931         GST_MEMDUMP_OBJECT (qtdemux, "mp4s", buffer, end - buffer);
5932         /* Skip 8 byte header, plus 8 byte version + flags + entry_count */
5933         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
5934         break;
5935       }
5936       case FOURCC_XiTh:
5937       {
5938         guint32 version;
5939         guint32 offset;
5940
5941         version = QT_UINT32 (buffer + 12);
5942         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
5943
5944         switch (version) {
5945           case 0x00000001:
5946             offset = 0x62;
5947             break;
5948           default:
5949             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
5950             offset = 0;
5951             break;
5952         }
5953         if (offset)
5954           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
5955         break;
5956       }
5957       case FOURCC_in24:
5958       {
5959         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
5960         break;
5961       }
5962       case FOURCC_uuid:
5963       {
5964         qtdemux_parse_uuid (qtdemux, buffer, end - buffer);
5965         break;
5966       }
5967       default:
5968         if (!strcmp (type->name, "unknown"))
5969           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
5970         break;
5971     }
5972   }
5973   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT "'",
5974       GST_FOURCC_ARGS (fourcc));
5975   return TRUE;
5976
5977 /* ERRORS */
5978 not_enough_data:
5979   {
5980     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5981         (_("This file is corrupt and cannot be played.")),
5982         ("Not enough data for an atom header, got only %u bytes", length));
5983     return FALSE;
5984   }
5985 broken_atom_size:
5986   {
5987     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
5988         (_("This file is corrupt and cannot be played.")),
5989         ("Atom '%" GST_FOURCC_FORMAT "' has size of %u bytes, but we have only "
5990             "%u bytes available.", GST_FOURCC_ARGS (fourcc), node_length,
5991             length));
5992     return FALSE;
5993   }
5994 }
5995
5996 static GNode *
5997 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
5998 {
5999   GNode *child;
6000   guint8 *buffer;
6001   guint32 child_fourcc;
6002
6003   for (child = g_node_first_child (node); child;
6004       child = g_node_next_sibling (child)) {
6005     buffer = (guint8 *) child->data;
6006
6007     child_fourcc = QT_FOURCC (buffer + 4);
6008
6009     if (G_UNLIKELY (child_fourcc == fourcc)) {
6010       return child;
6011     }
6012   }
6013   return NULL;
6014 }
6015
6016 static GNode *
6017 qtdemux_tree_get_child_by_type_full (GNode * node, guint32 fourcc,
6018     GstByteReader * parser)
6019 {
6020   GNode *child;
6021   guint8 *buffer;
6022   guint32 child_fourcc, child_len;
6023
6024   for (child = g_node_first_child (node); child;
6025       child = g_node_next_sibling (child)) {
6026     buffer = (guint8 *) child->data;
6027
6028     child_len = QT_UINT32 (buffer);
6029     child_fourcc = QT_FOURCC (buffer + 4);
6030
6031     if (G_UNLIKELY (child_fourcc == fourcc)) {
6032       if (G_UNLIKELY (child_len < (4 + 4)))
6033         return NULL;
6034       /* FIXME: must verify if atom length < parent atom length */
6035       gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6036       return child;
6037     }
6038   }
6039   return NULL;
6040 }
6041
6042 static GNode *
6043 qtdemux_tree_get_sibling_by_type_full (GNode * node, guint32 fourcc,
6044     GstByteReader * parser)
6045 {
6046   GNode *child;
6047   guint8 *buffer;
6048   guint32 child_fourcc, child_len;
6049
6050   for (child = g_node_next_sibling (node); child;
6051       child = g_node_next_sibling (child)) {
6052     buffer = (guint8 *) child->data;
6053
6054     child_fourcc = QT_FOURCC (buffer + 4);
6055
6056     if (child_fourcc == fourcc) {
6057       if (parser) {
6058         child_len = QT_UINT32 (buffer);
6059         if (G_UNLIKELY (child_len < (4 + 4)))
6060           return NULL;
6061         /* FIXME: must verify if atom length < parent atom length */
6062         gst_byte_reader_init (parser, buffer + (4 + 4), child_len - (4 + 4));
6063       }
6064       return child;
6065     }
6066   }
6067   return NULL;
6068 }
6069
6070 static GNode *
6071 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
6072 {
6073   return qtdemux_tree_get_sibling_by_type_full (node, fourcc, NULL);
6074 }
6075
6076 static void
6077 qtdemux_do_allocation (GstQTDemux * qtdemux, QtDemuxStream * stream)
6078 {
6079 /* FIXME: This can only reliably work if demuxers have a
6080  * separate streaming thread per srcpad. This should be
6081  * done in a demuxer base class, which integrates parts
6082  * of multiqueue
6083  *
6084  * https://bugzilla.gnome.org/show_bug.cgi?id=701856
6085  */
6086 #if 0
6087   GstQuery *query;
6088
6089   query = gst_query_new_allocation (stream->caps, FALSE);
6090
6091   if (!gst_pad_peer_query (stream->pad, query)) {
6092     /* not a problem, just debug a little */
6093     GST_DEBUG_OBJECT (qtdemux, "peer ALLOCATION query failed");
6094   }
6095
6096   if (stream->allocator)
6097     gst_object_unref (stream->allocator);
6098
6099   if (gst_query_get_n_allocation_params (query) > 0) {
6100     /* try the allocator */
6101     gst_query_parse_nth_allocation_param (query, 0, &stream->allocator,
6102         &stream->params);
6103     stream->use_allocator = TRUE;
6104   } else {
6105     stream->allocator = NULL;
6106     gst_allocation_params_init (&stream->params);
6107     stream->use_allocator = FALSE;
6108   }
6109   gst_query_unref (query);
6110 #endif
6111 }
6112
6113 static gboolean
6114 gst_qtdemux_configure_stream (GstQTDemux * qtdemux, QtDemuxStream * stream)
6115 {
6116   if (stream->subtype == FOURCC_vide) {
6117     /* fps is calculated base on the duration of the average framerate since
6118      * qt does not have a fixed framerate. */
6119     if ((stream->n_samples == 1) && (stream->first_duration == 0)) {
6120       /* still frame */
6121       stream->fps_n = 0;
6122       stream->fps_d = 1;
6123     } else {
6124       if (stream->duration == 0 || stream->n_samples < 2) {
6125         stream->fps_n = stream->timescale;
6126         stream->fps_d = 1;
6127       } else {
6128         /* Calculate a framerate, ignoring the first sample which is sometimes truncated */
6129         /* stream->duration is guint64, timescale, n_samples are guint32 */
6130         GstClockTime avg_duration =
6131             gst_util_uint64_scale_round (stream->duration -
6132             stream->first_duration, GST_SECOND,
6133             (guint64) (stream->timescale) * (stream->n_samples - 1));
6134
6135         GST_LOG_OBJECT (qtdemux,
6136             "Calculating avg sample duration based on stream duration %"
6137             G_GUINT64_FORMAT
6138             " minus first sample %u, leaving %d samples gives %"
6139             GST_TIME_FORMAT, stream->duration, stream->first_duration,
6140             stream->n_samples - 1, GST_TIME_ARGS (avg_duration));
6141
6142         gst_video_guess_framerate (avg_duration, &stream->fps_n,
6143             &stream->fps_d);
6144       }
6145       GST_DEBUG_OBJECT (qtdemux,
6146           "Calculating framerate, timescale %u gave fps_n %d fps_d %d",
6147           stream->timescale, stream->fps_n, stream->fps_d);
6148     }
6149
6150     if (stream->caps) {
6151       stream->caps = gst_caps_make_writable (stream->caps);
6152
6153       gst_caps_set_simple (stream->caps,
6154           "width", G_TYPE_INT, stream->width,
6155           "height", G_TYPE_INT, stream->height,
6156           "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
6157
6158       /* calculate pixel-aspect-ratio using display width and height */
6159       GST_DEBUG_OBJECT (qtdemux,
6160           "video size %dx%d, target display size %dx%d", stream->width,
6161           stream->height, stream->display_width, stream->display_height);
6162
6163       if (stream->display_width > 0 && stream->display_height > 0 &&
6164           stream->width > 0 && stream->height > 0) {
6165         gint n, d;
6166
6167         /* calculate the pixel aspect ratio using the display and pixel w/h */
6168         n = stream->display_width * stream->height;
6169         d = stream->display_height * stream->width;
6170         if (n == d)
6171           n = d = 1;
6172         GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
6173         gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6174             GST_TYPE_FRACTION, n, d, NULL);
6175       }
6176
6177       /* qt file might have pasp atom */
6178       if (stream->par_w > 0 && stream->par_h > 0) {
6179         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
6180         gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
6181             GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
6182       }
6183     }
6184   } else if (stream->subtype == FOURCC_soun) {
6185     if (stream->caps) {
6186       stream->caps = gst_caps_make_writable (stream->caps);
6187       if (stream->rate > 0)
6188         gst_caps_set_simple (stream->caps,
6189             "rate", G_TYPE_INT, (int) stream->rate, NULL);
6190       if (stream->n_channels > 0)
6191         gst_caps_set_simple (stream->caps,
6192             "channels", G_TYPE_INT, stream->n_channels, NULL);
6193       if (stream->n_channels > 2) {
6194         /* FIXME: Need to parse the 'chan' atom to get channel layouts
6195          * correctly; this is just the minimum we can do - assume
6196          * we don't actually have any channel positions. */
6197         gst_caps_set_simple (stream->caps,
6198             "channel-mask", GST_TYPE_BITMASK, G_GUINT64_CONSTANT (0), NULL);
6199       }
6200     }
6201   }
6202
6203   if (stream->pad) {
6204     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
6205     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
6206     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
6207     gst_pad_set_active (stream->pad, TRUE);
6208
6209     gst_pad_use_fixed_caps (stream->pad);
6210
6211     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
6212     if (stream->new_stream) {
6213       gchar *stream_id;
6214       GstEvent *event;
6215       GstStreamFlags stream_flags;
6216
6217       event =
6218           gst_pad_get_sticky_event (qtdemux->sinkpad, GST_EVENT_STREAM_START,
6219           0);
6220       if (event) {
6221         if (gst_event_parse_group_id (event, &qtdemux->group_id))
6222           qtdemux->have_group_id = TRUE;
6223         else
6224           qtdemux->have_group_id = FALSE;
6225         gst_event_unref (event);
6226       } else if (!qtdemux->have_group_id) {
6227         qtdemux->have_group_id = TRUE;
6228         qtdemux->group_id = gst_util_group_id_next ();
6229       }
6230
6231       stream->new_stream = FALSE;
6232       stream_id =
6233           gst_pad_create_stream_id_printf (stream->pad,
6234           GST_ELEMENT_CAST (qtdemux), "%03u", stream->track_id);
6235       event = gst_event_new_stream_start (stream_id);
6236       if (qtdemux->have_group_id)
6237         gst_event_set_group_id (event, qtdemux->group_id);
6238       stream_flags = GST_STREAM_FLAG_NONE;
6239       if (stream->disabled)
6240         stream_flags |= GST_STREAM_FLAG_UNSELECT;
6241       if (stream->sparse)
6242         stream_flags |= GST_STREAM_FLAG_SPARSE;
6243       gst_event_set_stream_flags (event, stream_flags);
6244       gst_pad_push_event (stream->pad, event);
6245       g_free (stream_id);
6246     }
6247     gst_pad_set_caps (stream->pad, stream->caps);
6248     stream->new_caps = FALSE;
6249   }
6250   return TRUE;
6251 }
6252
6253 static gboolean
6254 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
6255     QtDemuxStream * stream, GstTagList * list)
6256 {
6257   /* consistent default for push based mode */
6258   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
6259
6260   if (stream->subtype == FOURCC_vide) {
6261     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6262
6263     stream->pad =
6264         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6265     g_free (name);
6266
6267     gst_qtdemux_configure_stream (qtdemux, stream);
6268     qtdemux->n_video_streams++;
6269   } else if (stream->subtype == FOURCC_soun) {
6270     gchar *name = g_strdup_printf ("audio_%u", qtdemux->n_audio_streams);
6271
6272     stream->pad =
6273         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
6274     g_free (name);
6275     gst_qtdemux_configure_stream (qtdemux, stream);
6276     qtdemux->n_audio_streams++;
6277   } else if (stream->subtype == FOURCC_strm) {
6278     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
6279   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
6280       || stream->subtype == FOURCC_sbtl) {
6281     gchar *name = g_strdup_printf ("subtitle_%u", qtdemux->n_sub_streams);
6282
6283     stream->pad =
6284         gst_pad_new_from_static_template (&gst_qtdemux_subsrc_template, name);
6285     g_free (name);
6286     gst_qtdemux_configure_stream (qtdemux, stream);
6287     qtdemux->n_sub_streams++;
6288   } else if (stream->caps) {
6289     gchar *name = g_strdup_printf ("video_%u", qtdemux->n_video_streams);
6290
6291     stream->pad =
6292         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
6293     g_free (name);
6294     gst_qtdemux_configure_stream (qtdemux, stream);
6295     qtdemux->n_video_streams++;
6296   } else {
6297     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
6298     goto done;
6299   }
6300
6301   if (stream->pad) {
6302     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
6303         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
6304     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
6305     gst_flow_combiner_add_pad (qtdemux->flowcombiner, stream->pad);
6306
6307     if (stream->pending_tags)
6308       gst_tag_list_unref (stream->pending_tags);
6309     stream->pending_tags = list;
6310     /* global tags go on each pad anyway */
6311     stream->send_global_tags = TRUE;
6312   }
6313 done:
6314   return TRUE;
6315 }
6316
6317 /* find next atom with @fourcc starting at @offset */
6318 static GstFlowReturn
6319 qtdemux_find_atom (GstQTDemux * qtdemux, guint64 * offset,
6320     guint64 * length, guint32 fourcc)
6321 {
6322   GstFlowReturn ret;
6323   guint32 lfourcc;
6324   GstBuffer *buf;
6325
6326   GST_LOG_OBJECT (qtdemux, "finding fourcc %" GST_FOURCC_FORMAT " at offset %"
6327       G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), *offset);
6328
6329   while (TRUE) {
6330     GstMapInfo map;
6331
6332     buf = NULL;
6333     ret = gst_pad_pull_range (qtdemux->sinkpad, *offset, 16, &buf);
6334     if (G_UNLIKELY (ret != GST_FLOW_OK))
6335       goto locate_failed;
6336     if (G_UNLIKELY (gst_buffer_get_size (buf) != 16)) {
6337       /* likely EOF */
6338       ret = GST_FLOW_EOS;
6339       gst_buffer_unref (buf);
6340       goto locate_failed;
6341     }
6342     gst_buffer_map (buf, &map, GST_MAP_READ);
6343     extract_initial_length_and_fourcc (map.data, 16, length, &lfourcc);
6344     gst_buffer_unmap (buf, &map);
6345     gst_buffer_unref (buf);
6346
6347     if (G_UNLIKELY (*length == 0)) {
6348       GST_DEBUG_OBJECT (qtdemux, "invalid length 0");
6349       ret = GST_FLOW_ERROR;
6350       goto locate_failed;
6351     }
6352
6353     if (lfourcc == fourcc) {
6354       GST_DEBUG_OBJECT (qtdemux, "found fourcc at offset %" G_GUINT64_FORMAT,
6355           *offset);
6356       break;
6357     } else {
6358       GST_LOG_OBJECT (qtdemux,
6359           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
6360           GST_FOURCC_ARGS (fourcc), *offset);
6361       *offset += *length;
6362     }
6363   }
6364
6365   return GST_FLOW_OK;
6366
6367 locate_failed:
6368   {
6369     /* might simply have had last one */
6370     GST_DEBUG_OBJECT (qtdemux, "fourcc not found");
6371     return ret;
6372   }
6373 }
6374
6375 /* should only do something in pull mode */
6376 /* call with OBJECT lock */
6377 static GstFlowReturn
6378 qtdemux_add_fragmented_samples (GstQTDemux * qtdemux)
6379 {
6380   guint64 length, offset;
6381   GstBuffer *buf = NULL;
6382   GstFlowReturn ret = GST_FLOW_OK;
6383   GstFlowReturn res = GST_FLOW_OK;
6384   GstMapInfo map;
6385
6386   offset = qtdemux->moof_offset;
6387   GST_DEBUG_OBJECT (qtdemux, "next moof at offset %" G_GUINT64_FORMAT, offset);
6388
6389   if (!offset) {
6390     GST_DEBUG_OBJECT (qtdemux, "no next moof");
6391     return GST_FLOW_EOS;
6392   }
6393
6394   /* best not do pull etc with lock held */
6395   GST_OBJECT_UNLOCK (qtdemux);
6396
6397   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6398   if (ret != GST_FLOW_OK)
6399     goto flow_failed;
6400
6401   ret = gst_qtdemux_pull_atom (qtdemux, offset, length, &buf);
6402   if (G_UNLIKELY (ret != GST_FLOW_OK))
6403     goto flow_failed;
6404   gst_buffer_map (buf, &map, GST_MAP_READ);
6405   if (!qtdemux_parse_moof (qtdemux, map.data, map.size, offset, NULL)) {
6406     gst_buffer_unmap (buf, &map);
6407     gst_buffer_unref (buf);
6408     buf = NULL;
6409     goto parse_failed;
6410   }
6411
6412   gst_buffer_unmap (buf, &map);
6413   gst_buffer_unref (buf);
6414   buf = NULL;
6415
6416   offset += length;
6417   /* look for next moof */
6418   ret = qtdemux_find_atom (qtdemux, &offset, &length, FOURCC_moof);
6419   if (G_UNLIKELY (ret != GST_FLOW_OK))
6420     goto flow_failed;
6421
6422 exit:
6423   GST_OBJECT_LOCK (qtdemux);
6424
6425   qtdemux->moof_offset = offset;
6426
6427   return res;
6428
6429 parse_failed:
6430   {
6431     GST_DEBUG_OBJECT (qtdemux, "failed to parse moof");
6432     offset = 0;
6433     res = GST_FLOW_ERROR;
6434     goto exit;
6435   }
6436 flow_failed:
6437   {
6438     /* maybe upstream temporarily flushing */
6439     if (ret != GST_FLOW_FLUSHING) {
6440       GST_DEBUG_OBJECT (qtdemux, "no next moof");
6441       offset = 0;
6442     } else {
6443       GST_DEBUG_OBJECT (qtdemux, "upstream WRONG_STATE");
6444       /* resume at current position next time */
6445     }
6446     res = ret;
6447     goto exit;
6448   }
6449 }
6450
6451 /* initialise bytereaders for stbl sub-atoms */
6452 static gboolean
6453 qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
6454 {
6455   stream->stbl_index = -1;      /* no samples have yet been parsed */
6456   stream->sample_index = -1;
6457
6458   /* time-to-sample atom */
6459   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stts, &stream->stts))
6460     goto corrupt_file;
6461
6462   /* copy atom data into a new buffer for later use */
6463   stream->stts.data = g_memdup (stream->stts.data, stream->stts.size);
6464
6465   /* skip version + flags */
6466   if (!gst_byte_reader_skip (&stream->stts, 1 + 3) ||
6467       !gst_byte_reader_get_uint32_be (&stream->stts, &stream->n_sample_times))
6468     goto corrupt_file;
6469   GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", stream->n_sample_times);
6470
6471   /* make sure there's enough data */
6472   if (!qt_atom_parser_has_chunks (&stream->stts, stream->n_sample_times, 8)) {
6473     stream->n_sample_times = gst_byte_reader_get_remaining (&stream->stts) / 8;
6474     GST_LOG_OBJECT (qtdemux, "overriding to %u timestamp blocks",
6475         stream->n_sample_times);
6476     if (!stream->n_sample_times)
6477       goto corrupt_file;
6478   }
6479
6480   /* sync sample atom */
6481   stream->stps_present = FALSE;
6482   if ((stream->stss_present =
6483           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stss,
6484               &stream->stss) ? TRUE : FALSE) == TRUE) {
6485     /* copy atom data into a new buffer for later use */
6486     stream->stss.data = g_memdup (stream->stss.data, stream->stss.size);
6487
6488     /* skip version + flags */
6489     if (!gst_byte_reader_skip (&stream->stss, 1 + 3) ||
6490         !gst_byte_reader_get_uint32_be (&stream->stss, &stream->n_sample_syncs))
6491       goto corrupt_file;
6492
6493     if (stream->n_sample_syncs) {
6494       /* make sure there's enough data */
6495       if (!qt_atom_parser_has_chunks (&stream->stss, stream->n_sample_syncs, 4))
6496         goto corrupt_file;
6497     }
6498
6499     /* partial sync sample atom */
6500     if ((stream->stps_present =
6501             ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stps,
6502                 &stream->stps) ? TRUE : FALSE) == TRUE) {
6503       /* copy atom data into a new buffer for later use */
6504       stream->stps.data = g_memdup (stream->stps.data, stream->stps.size);
6505
6506       /* skip version + flags */
6507       if (!gst_byte_reader_skip (&stream->stps, 1 + 3) ||
6508           !gst_byte_reader_get_uint32_be (&stream->stps,
6509               &stream->n_sample_partial_syncs))
6510         goto corrupt_file;
6511
6512       /* if there are no entries, the stss table contains the real
6513        * sync samples */
6514       if (stream->n_sample_partial_syncs) {
6515         /* make sure there's enough data */
6516         if (!qt_atom_parser_has_chunks (&stream->stps,
6517                 stream->n_sample_partial_syncs, 4))
6518           goto corrupt_file;
6519       }
6520     }
6521   }
6522
6523   /* sample size */
6524   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsz, &stream->stsz))
6525     goto no_samples;
6526
6527   /* copy atom data into a new buffer for later use */
6528   stream->stsz.data = g_memdup (stream->stsz.data, stream->stsz.size);
6529
6530   /* skip version + flags */
6531   if (!gst_byte_reader_skip (&stream->stsz, 1 + 3) ||
6532       !gst_byte_reader_get_uint32_be (&stream->stsz, &stream->sample_size))
6533     goto corrupt_file;
6534
6535   if (!gst_byte_reader_get_uint32_be (&stream->stsz, &stream->n_samples))
6536     goto corrupt_file;
6537
6538   if (!stream->n_samples)
6539     goto no_samples;
6540
6541   /* sample-to-chunk atom */
6542   if (!qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stsc, &stream->stsc))
6543     goto corrupt_file;
6544
6545   /* copy atom data into a new buffer for later use */
6546   stream->stsc.data = g_memdup (stream->stsc.data, stream->stsc.size);
6547
6548   /* skip version + flags */
6549   if (!gst_byte_reader_skip (&stream->stsc, 1 + 3) ||
6550       !gst_byte_reader_get_uint32_be (&stream->stsc,
6551           &stream->n_samples_per_chunk))
6552     goto corrupt_file;
6553
6554   GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %u",
6555       stream->n_samples_per_chunk);
6556
6557   /* make sure there's enough data */
6558   if (!qt_atom_parser_has_chunks (&stream->stsc, stream->n_samples_per_chunk,
6559           12))
6560     goto corrupt_file;
6561
6562
6563   /* chunk offset */
6564   if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_stco, &stream->stco))
6565     stream->co_size = sizeof (guint32);
6566   else if (qtdemux_tree_get_child_by_type_full (stbl, FOURCC_co64,
6567           &stream->stco))
6568     stream->co_size = sizeof (guint64);
6569   else
6570     goto corrupt_file;
6571
6572   /* copy atom data into a new buffer for later use */
6573   stream->stco.data = g_memdup (stream->stco.data, stream->stco.size);
6574
6575   /* skip version + flags */
6576   if (!gst_byte_reader_skip (&stream->stco, 1 + 3))
6577     goto corrupt_file;
6578
6579   /* chunks_are_samples == TRUE means treat chunks as samples */
6580   stream->chunks_are_samples = stream->sample_size && !stream->sampled;
6581   if (stream->chunks_are_samples) {
6582     /* treat chunks as samples */
6583     if (!gst_byte_reader_get_uint32_be (&stream->stco, &stream->n_samples))
6584       goto corrupt_file;
6585   } else {
6586     /* skip number of entries */
6587     if (!gst_byte_reader_skip (&stream->stco, 4))
6588       goto corrupt_file;
6589
6590     /* make sure there are enough data in the stsz atom */
6591     if (!stream->sample_size) {
6592       /* different sizes for each sample */
6593       if (!qt_atom_parser_has_chunks (&stream->stsz, stream->n_samples, 4))
6594         goto corrupt_file;
6595     }
6596   }
6597
6598   GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %u * %u (%.2f MB)",
6599       stream->n_samples, (guint) sizeof (QtDemuxSample),
6600       stream->n_samples * sizeof (QtDemuxSample) / (1024.0 * 1024.0));
6601
6602   if (stream->n_samples >=
6603       QTDEMUX_MAX_SAMPLE_INDEX_SIZE / sizeof (QtDemuxSample)) {
6604     GST_WARNING_OBJECT (qtdemux, "not allocating index of %d samples, would "
6605         "be larger than %uMB (broken file?)", stream->n_samples,
6606         QTDEMUX_MAX_SAMPLE_INDEX_SIZE >> 20);
6607     return FALSE;
6608   }
6609
6610   stream->samples = g_try_new0 (QtDemuxSample, stream->n_samples);
6611   if (!stream->samples) {
6612     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples",
6613         stream->n_samples);
6614     return FALSE;
6615   }
6616
6617
6618   /* composition time-to-sample */
6619   if ((stream->ctts_present =
6620           ! !qtdemux_tree_get_child_by_type_full (stbl, FOURCC_ctts,
6621               &stream->ctts) ? TRUE : FALSE) == TRUE) {
6622     /* copy atom data into a new buffer for later use */
6623     stream->ctts.data = g_memdup (stream->ctts.data, stream->ctts.size);
6624
6625     /* skip version + flags */
6626     if (!gst_byte_reader_skip (&stream->ctts, 1 + 3)
6627         || !gst_byte_reader_get_uint32_be (&stream->ctts,
6628             &stream->n_composition_times))
6629       goto corrupt_file;
6630
6631     /* make sure there's enough data */
6632     if (!qt_atom_parser_has_chunks (&stream->ctts, stream->n_composition_times,
6633             4 + 4))
6634       goto corrupt_file;
6635   }
6636
6637   return TRUE;
6638
6639 corrupt_file:
6640   {
6641     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
6642         (_("This file is corrupt and cannot be played.")), (NULL));
6643     return FALSE;
6644   }
6645 no_samples:
6646   {
6647     gst_qtdemux_stbl_free (stream);
6648     if (!qtdemux->fragmented) {
6649       /* not quite good */
6650       GST_WARNING_OBJECT (qtdemux, "stream has no samples");
6651       return FALSE;
6652     } else {
6653       /* may pick up samples elsewhere */
6654       return TRUE;
6655     }
6656   }
6657 }
6658
6659 /* collect samples from the next sample to be parsed up to sample @n for @stream
6660  * by reading the info from @stbl
6661  *
6662  * This code can be executed from both the streaming thread and the seeking
6663  * thread so it takes the object lock to protect itself
6664  */
6665 static gboolean
6666 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream, guint32 n)
6667 {
6668   gint i, j, k;
6669   QtDemuxSample *samples, *first, *cur, *last;
6670   guint32 n_samples_per_chunk;
6671   guint32 n_samples;
6672
6673   GST_LOG_OBJECT (qtdemux, "parsing samples for stream fourcc %"
6674       GST_FOURCC_FORMAT ", pad %s", GST_FOURCC_ARGS (stream->fourcc),
6675       stream->pad ? GST_PAD_NAME (stream->pad) : "(NULL)");
6676
6677   n_samples = stream->n_samples;
6678
6679   if (n >= n_samples)
6680     goto out_of_samples;
6681
6682   GST_OBJECT_LOCK (qtdemux);
6683   if (n <= stream->stbl_index)
6684     goto already_parsed;
6685
6686   GST_DEBUG_OBJECT (qtdemux, "parsing up to sample %u", n);
6687
6688   if (!stream->stsz.data) {
6689     /* so we already parsed and passed all the moov samples;
6690      * onto fragmented ones */
6691     g_assert (qtdemux->fragmented);
6692     goto done;
6693   }
6694
6695   /* pointer to the sample table */
6696   samples = stream->samples;
6697
6698   /* starts from -1, moves to the next sample index to parse */
6699   stream->stbl_index++;
6700
6701   /* keep track of the first and last sample to fill */
6702   first = &samples[stream->stbl_index];
6703   last = &samples[n];
6704
6705   if (!stream->chunks_are_samples) {
6706     /* set the sample sizes */
6707     if (stream->sample_size == 0) {
6708       /* different sizes for each sample */
6709       for (cur = first; cur <= last; cur++) {
6710         cur->size = gst_byte_reader_get_uint32_be_unchecked (&stream->stsz);
6711         GST_LOG_OBJECT (qtdemux, "sample %d has size %u",
6712             (guint) (cur - samples), cur->size);
6713       }
6714     } else {
6715       /* samples have the same size */
6716       GST_LOG_OBJECT (qtdemux, "all samples have size %u", stream->sample_size);
6717       for (cur = first; cur <= last; cur++)
6718         cur->size = stream->sample_size;
6719     }
6720   }
6721
6722   n_samples_per_chunk = stream->n_samples_per_chunk;
6723   cur = first;
6724
6725   for (i = stream->stsc_index; i < n_samples_per_chunk; i++) {
6726     guint32 last_chunk;
6727
6728     if (stream->stsc_chunk_index >= stream->last_chunk
6729         || stream->stsc_chunk_index < stream->first_chunk) {
6730       stream->first_chunk =
6731           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6732       stream->samples_per_chunk =
6733           gst_byte_reader_get_uint32_be_unchecked (&stream->stsc);
6734       gst_byte_reader_skip_unchecked (&stream->stsc, 4);
6735
6736       /* chunk numbers are counted from 1 it seems */
6737       if (G_UNLIKELY (stream->first_chunk == 0))
6738         goto corrupt_file;
6739
6740       --stream->first_chunk;
6741
6742       /* the last chunk of each entry is calculated by taking the first chunk
6743        * of the next entry; except if there is no next, where we fake it with
6744        * INT_MAX */
6745       if (G_UNLIKELY (i == (stream->n_samples_per_chunk - 1))) {
6746         stream->last_chunk = G_MAXUINT32;
6747       } else {
6748         stream->last_chunk =
6749             gst_byte_reader_peek_uint32_be_unchecked (&stream->stsc);
6750         if (G_UNLIKELY (stream->last_chunk == 0))
6751           goto corrupt_file;
6752
6753         --stream->last_chunk;
6754       }
6755
6756       GST_LOG_OBJECT (qtdemux,
6757           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
6758           stream->first_chunk, stream->last_chunk, stream->samples_per_chunk);
6759
6760       if (G_UNLIKELY (stream->last_chunk < stream->first_chunk))
6761         goto corrupt_file;
6762
6763       if (stream->last_chunk != G_MAXUINT32) {
6764         if (!qt_atom_parser_peek_sub (&stream->stco,
6765                 stream->first_chunk * stream->co_size,
6766                 (stream->last_chunk - stream->first_chunk) * stream->co_size,
6767                 &stream->co_chunk))
6768           goto corrupt_file;
6769
6770       } else {
6771         stream->co_chunk = stream->stco;
6772         if (!gst_byte_reader_skip (&stream->co_chunk,
6773                 stream->first_chunk * stream->co_size))
6774           goto corrupt_file;
6775       }
6776
6777       stream->stsc_chunk_index = stream->first_chunk;
6778     }
6779
6780     last_chunk = stream->last_chunk;
6781
6782     if (stream->chunks_are_samples) {
6783       cur = &samples[stream->stsc_chunk_index];
6784
6785       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6786         if (j > n) {
6787           /* save state */
6788           stream->stsc_chunk_index = j;
6789           goto done;
6790         }
6791
6792         cur->offset =
6793             qt_atom_parser_get_offset_unchecked (&stream->co_chunk,
6794             stream->co_size);
6795
6796         GST_LOG_OBJECT (qtdemux, "Created entry %d with offset "
6797             "%" G_GUINT64_FORMAT, j, cur->offset);
6798
6799         if (stream->samples_per_frame * stream->bytes_per_frame) {
6800           cur->size =
6801               (stream->samples_per_chunk * stream->n_channels) /
6802               stream->samples_per_frame * stream->bytes_per_frame;
6803         } else {
6804           cur->size = stream->samples_per_chunk;
6805         }
6806
6807         GST_DEBUG_OBJECT (qtdemux,
6808             "keyframe sample %d: timestamp %" GST_TIME_FORMAT ", size %u",
6809             j, GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream,
6810                     stream->stco_sample_index)), cur->size);
6811
6812         cur->timestamp = stream->stco_sample_index;
6813         cur->duration = stream->samples_per_chunk;
6814         cur->keyframe = TRUE;
6815         cur++;
6816
6817         stream->stco_sample_index += stream->samples_per_chunk;
6818       }
6819       stream->stsc_chunk_index = j;
6820     } else {
6821       for (j = stream->stsc_chunk_index; j < last_chunk; j++) {
6822         guint32 samples_per_chunk;
6823         guint64 chunk_offset;
6824
6825         if (!stream->stsc_sample_index
6826             && !qt_atom_parser_get_offset (&stream->co_chunk, stream->co_size,
6827                 &stream->chunk_offset))
6828           goto corrupt_file;
6829
6830         samples_per_chunk = stream->samples_per_chunk;
6831         chunk_offset = stream->chunk_offset;
6832
6833         for (k = stream->stsc_sample_index; k < samples_per_chunk; k++) {
6834           GST_LOG_OBJECT (qtdemux, "creating entry %d with offset %"
6835               G_GUINT64_FORMAT " and size %d",
6836               (guint) (cur - samples), chunk_offset, cur->size);
6837
6838           cur->offset = chunk_offset;
6839           chunk_offset += cur->size;
6840           cur++;
6841
6842           if (G_UNLIKELY (cur > last)) {
6843             /* save state */
6844             stream->stsc_sample_index = k + 1;
6845             stream->chunk_offset = chunk_offset;
6846             stream->stsc_chunk_index = j;
6847             goto done2;
6848           }
6849         }
6850         stream->stsc_sample_index = 0;
6851       }
6852       stream->stsc_chunk_index = j;
6853     }
6854     stream->stsc_index++;
6855   }
6856
6857   if (stream->chunks_are_samples)
6858     goto ctts;
6859 done2:
6860   {
6861     guint32 n_sample_times;
6862
6863     n_sample_times = stream->n_sample_times;
6864     cur = first;
6865
6866     for (i = stream->stts_index; i < n_sample_times; i++) {
6867       guint32 stts_samples;
6868       gint32 stts_duration;
6869       gint64 stts_time;
6870
6871       if (stream->stts_sample_index >= stream->stts_samples
6872           || !stream->stts_sample_index) {
6873
6874         stream->stts_samples =
6875             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6876         stream->stts_duration =
6877             gst_byte_reader_get_uint32_be_unchecked (&stream->stts);
6878
6879         GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u",
6880             i, stream->stts_samples, stream->stts_duration);
6881
6882         stream->stts_sample_index = 0;
6883       }
6884
6885       stts_samples = stream->stts_samples;
6886       stts_duration = stream->stts_duration;
6887       stts_time = stream->stts_time;
6888
6889       for (j = stream->stts_sample_index; j < stts_samples; j++) {
6890         GST_DEBUG_OBJECT (qtdemux,
6891             "sample %d: index %d, timestamp %" GST_TIME_FORMAT,
6892             (guint) (cur - samples), j,
6893             GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stts_time)));
6894
6895         cur->timestamp = stts_time;
6896         cur->duration = stts_duration;
6897
6898         /* avoid 32-bit wrap-around,
6899          * but still mind possible 'negative' duration */
6900         stts_time += (gint64) stts_duration;
6901         cur++;
6902
6903         if (G_UNLIKELY (cur > last)) {
6904           /* save values */
6905           stream->stts_time = stts_time;
6906           stream->stts_sample_index = j + 1;
6907           goto done3;
6908         }
6909       }
6910       stream->stts_sample_index = 0;
6911       stream->stts_time = stts_time;
6912       stream->stts_index++;
6913     }
6914     /* fill up empty timestamps with the last timestamp, this can happen when
6915      * the last samples do not decode and so we don't have timestamps for them.
6916      * We however look at the last timestamp to estimate the track length so we
6917      * need something in here. */
6918     for (; cur < last; cur++) {
6919       GST_DEBUG_OBJECT (qtdemux,
6920           "fill sample %d: timestamp %" GST_TIME_FORMAT,
6921           (guint) (cur - samples),
6922           GST_TIME_ARGS (QTSTREAMTIME_TO_GSTTIME (stream, stream->stts_time)));
6923       cur->timestamp = stream->stts_time;
6924       cur->duration = -1;
6925     }
6926   }
6927 done3:
6928   {
6929     /* sample sync, can be NULL */
6930     if (stream->stss_present == TRUE) {
6931       guint32 n_sample_syncs;
6932
6933       n_sample_syncs = stream->n_sample_syncs;
6934
6935       if (!n_sample_syncs) {
6936         GST_DEBUG_OBJECT (qtdemux, "all samples are keyframes");
6937         stream->all_keyframe = TRUE;
6938       } else {
6939         for (i = stream->stss_index; i < n_sample_syncs; i++) {
6940           /* note that the first sample is index 1, not 0 */
6941           guint32 index;
6942
6943           index = gst_byte_reader_get_uint32_be_unchecked (&stream->stss);
6944
6945           if (G_LIKELY (index > 0 && index <= n_samples)) {
6946             index -= 1;
6947             samples[index].keyframe = TRUE;
6948             GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6949             /* and exit if we have enough samples */
6950             if (G_UNLIKELY (index >= n)) {
6951               i++;
6952               break;
6953             }
6954           }
6955         }
6956         /* save state */
6957         stream->stss_index = i;
6958       }
6959
6960       /* stps marks partial sync frames like open GOP I-Frames */
6961       if (stream->stps_present == TRUE) {
6962         guint32 n_sample_partial_syncs;
6963
6964         n_sample_partial_syncs = stream->n_sample_partial_syncs;
6965
6966         /* if there are no entries, the stss table contains the real
6967          * sync samples */
6968         if (n_sample_partial_syncs) {
6969           for (i = stream->stps_index; i < n_sample_partial_syncs; i++) {
6970             /* note that the first sample is index 1, not 0 */
6971             guint32 index;
6972
6973             index = gst_byte_reader_get_uint32_be_unchecked (&stream->stps);
6974
6975             if (G_LIKELY (index > 0 && index <= n_samples)) {
6976               index -= 1;
6977               samples[index].keyframe = TRUE;
6978               GST_DEBUG_OBJECT (qtdemux, "samples at %u is keyframe", index);
6979               /* and exit if we have enough samples */
6980               if (G_UNLIKELY (index >= n)) {
6981                 i++;
6982                 break;
6983               }
6984             }
6985           }
6986           /* save state */
6987           stream->stps_index = i;
6988         }
6989       }
6990     } else {
6991       /* no stss, all samples are keyframes */
6992       stream->all_keyframe = TRUE;
6993       GST_DEBUG_OBJECT (qtdemux, "setting all keyframes");
6994     }
6995   }
6996
6997 ctts:
6998   /* composition time to sample */
6999   if (stream->ctts_present == TRUE) {
7000     guint32 n_composition_times;
7001     guint32 ctts_count;
7002     gint32 ctts_soffset;
7003
7004     /* Fill in the pts_offsets */
7005     cur = first;
7006     n_composition_times = stream->n_composition_times;
7007
7008     for (i = stream->ctts_index; i < n_composition_times; i++) {
7009       if (stream->ctts_sample_index >= stream->ctts_count
7010           || !stream->ctts_sample_index) {
7011         stream->ctts_count =
7012             gst_byte_reader_get_uint32_be_unchecked (&stream->ctts);
7013         stream->ctts_soffset =
7014             gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
7015         stream->ctts_sample_index = 0;
7016       }
7017
7018       ctts_count = stream->ctts_count;
7019       ctts_soffset = stream->ctts_soffset;
7020
7021       for (j = stream->ctts_sample_index; j < ctts_count; j++) {
7022         cur->pts_offset = ctts_soffset;
7023         cur++;
7024
7025         if (G_UNLIKELY (cur > last)) {
7026           /* save state */
7027           stream->ctts_sample_index = j + 1;
7028           goto done;
7029         }
7030       }
7031       stream->ctts_sample_index = 0;
7032       stream->ctts_index++;
7033     }
7034   }
7035 done:
7036   stream->stbl_index = n;
7037   /* if index has been completely parsed, free data that is no-longer needed */
7038   if (n + 1 == stream->n_samples) {
7039     gst_qtdemux_stbl_free (stream);
7040     GST_DEBUG_OBJECT (qtdemux,
7041         "parsed all available samples; checking for more");
7042     while (n + 1 == stream->n_samples)
7043       if (qtdemux_add_fragmented_samples (qtdemux) != GST_FLOW_OK)
7044         break;
7045   }
7046   GST_OBJECT_UNLOCK (qtdemux);
7047
7048   return TRUE;
7049
7050   /* SUCCESS */
7051 already_parsed:
7052   {
7053     GST_LOG_OBJECT (qtdemux,
7054         "Tried to parse up to sample %u but this sample has already been parsed",
7055         n);
7056     /* if fragmented, there may be more */
7057     if (qtdemux->fragmented && n == stream->stbl_index)
7058       goto done;
7059     GST_OBJECT_UNLOCK (qtdemux);
7060     return TRUE;
7061   }
7062   /* ERRORS */
7063 out_of_samples:
7064   {
7065     GST_LOG_OBJECT (qtdemux,
7066         "Tried to parse up to sample %u but there are only %u samples", n + 1,
7067         stream->n_samples);
7068     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7069         (_("This file is corrupt and cannot be played.")), (NULL));
7070     return FALSE;
7071   }
7072 corrupt_file:
7073   {
7074     GST_OBJECT_UNLOCK (qtdemux);
7075     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
7076         (_("This file is corrupt and cannot be played.")), (NULL));
7077     return FALSE;
7078   }
7079 }
7080
7081 /* collect all segment info for @stream.
7082  */
7083 static gboolean
7084 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
7085     GNode * trak)
7086 {
7087   GNode *edts;
7088
7089   /* parse and prepare segment info from the edit list */
7090   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
7091   stream->n_segments = 0;
7092   stream->segments = NULL;
7093   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
7094     GNode *elst;
7095     gint n_segments;
7096     gint i, count;
7097     guint64 time;
7098     GstClockTime stime;
7099     guint8 *buffer;
7100
7101     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
7102     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
7103       goto done;
7104
7105     buffer = elst->data;
7106
7107     n_segments = QT_UINT32 (buffer + 12);
7108
7109     /* we might allocate a bit too much, at least allocate 1 segment */
7110     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
7111
7112     /* segments always start from 0 */
7113     time = 0;
7114     stime = 0;
7115     count = 0;
7116     for (i = 0; i < n_segments; i++) {
7117       guint64 duration;
7118       guint64 media_time;
7119       QtDemuxSegment *segment;
7120       guint32 rate_int;
7121
7122       media_time = QT_UINT32 (buffer + 20 + i * 12);
7123       duration = QT_UINT32 (buffer + 16 + i * 12);
7124
7125       segment = &stream->segments[count++];
7126
7127       /* time and duration expressed in global timescale */
7128       segment->time = stime;
7129       /* add non scaled values so we don't cause roundoff errors */
7130       time += duration;
7131       stime = QTTIME_TO_GSTTIME (qtdemux, time);
7132       segment->stop_time = stime;
7133       segment->duration = stime - segment->time;
7134
7135       segment->trak_media_start = media_time;
7136       /* media_time expressed in stream timescale */
7137       if (media_time != G_MAXUINT32) {
7138         segment->media_start = QTSTREAMTIME_TO_GSTTIME (stream, media_time);
7139         segment->media_stop = segment->media_start + segment->duration;
7140       } else {
7141         segment->media_start = GST_CLOCK_TIME_NONE;
7142         segment->media_stop = GST_CLOCK_TIME_NONE;
7143       }
7144       rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
7145
7146       if (rate_int <= 1) {
7147         /* 0 is not allowed, some programs write 1 instead of the floating point
7148          * value */
7149         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
7150             rate_int);
7151         segment->rate = 1;
7152       } else {
7153         segment->rate = rate_int / 65536.0;
7154       }
7155
7156       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
7157           ", duration %" GST_TIME_FORMAT ", media_start %" GST_TIME_FORMAT
7158           " (%" G_GUINT64_FORMAT ") , media_stop %" GST_TIME_FORMAT
7159           " stop_time %" GST_TIME_FORMAT " rate %g, (%d) timescale %u",
7160           i, GST_TIME_ARGS (segment->time),
7161           GST_TIME_ARGS (segment->duration),
7162           GST_TIME_ARGS (segment->media_start), media_time,
7163           GST_TIME_ARGS (segment->media_stop),
7164           GST_TIME_ARGS (segment->stop_time), segment->rate, rate_int,
7165           stream->timescale);
7166       if (segment->stop_time > qtdemux->segment.stop) {
7167         GST_WARNING_OBJECT (qtdemux, "Segment %d "
7168             " extends to %" GST_TIME_FORMAT
7169             " past the end of the file duration %" GST_TIME_FORMAT
7170             " it will be truncated", i, GST_TIME_ARGS (segment->stop_time),
7171             GST_TIME_ARGS (qtdemux->segment.stop));
7172         qtdemux->segment.stop = segment->stop_time;
7173       }
7174     }
7175     GST_DEBUG_OBJECT (qtdemux, "found %d segments", count);
7176     stream->n_segments = count;
7177   }
7178 done:
7179
7180   /* push based does not handle segments, so act accordingly here,
7181    * and warn if applicable */
7182   if (!qtdemux->pullbased) {
7183     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
7184     /* remove and use default one below, we stream like it anyway */
7185     g_free (stream->segments);
7186     stream->segments = NULL;
7187     stream->n_segments = 0;
7188   }
7189
7190   /* no segments, create one to play the complete trak */
7191   if (stream->n_segments == 0) {
7192     GstClockTime stream_duration =
7193         QTSTREAMTIME_TO_GSTTIME (stream, stream->duration);
7194
7195     if (stream->segments == NULL)
7196       stream->segments = g_new (QtDemuxSegment, 1);
7197
7198     /* represent unknown our way */
7199     if (stream_duration == 0)
7200       stream_duration = GST_CLOCK_TIME_NONE;
7201
7202     stream->segments[0].time = 0;
7203     stream->segments[0].stop_time = stream_duration;
7204     stream->segments[0].duration = stream_duration;
7205     stream->segments[0].media_start = 0;
7206     stream->segments[0].media_stop = stream_duration;
7207     stream->segments[0].rate = 1.0;
7208     stream->segments[0].trak_media_start = 0;
7209
7210     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
7211         GST_TIME_ARGS (stream_duration));
7212     stream->n_segments = 1;
7213     stream->dummy_segment = TRUE;
7214   }
7215   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
7216
7217   return TRUE;
7218 }
7219
7220 /*
7221  * Parses the stsd atom of a svq3 trak looking for
7222  * the SMI and gama atoms.
7223  */
7224 static void
7225 qtdemux_parse_svq3_stsd_data (GstQTDemux * qtdemux, GNode * stsd,
7226     guint8 ** gamma, GstBuffer ** seqh)
7227 {
7228   guint8 *_gamma = NULL;
7229   GstBuffer *_seqh = NULL;
7230   guint8 *stsd_data = stsd->data;
7231   guint32 length = QT_UINT32 (stsd_data);
7232   guint16 version;
7233
7234   if (length < 32) {
7235     GST_WARNING_OBJECT (qtdemux, "stsd too short");
7236     goto end;
7237   }
7238
7239   stsd_data += 32;
7240   length -= 32;
7241   version = QT_UINT16 (stsd_data);
7242   if (version == 3) {
7243     if (length >= 70) {
7244       length -= 70;
7245       stsd_data += 70;
7246       while (length > 8) {
7247         guint32 fourcc, size;
7248         guint8 *data;
7249         size = QT_UINT32 (stsd_data);
7250         fourcc = QT_FOURCC (stsd_data + 4);
7251         data = stsd_data + 8;
7252
7253         if (size == 0) {
7254           GST_WARNING_OBJECT (qtdemux, "Atom of size 0 found, aborting "
7255               "svq3 atom parsing");
7256           goto end;
7257         }
7258
7259         switch (fourcc) {
7260           case FOURCC_gama:{
7261             if (size == 12) {
7262               _gamma = data;
7263             } else {
7264               GST_WARNING_OBJECT (qtdemux, "Unexpected size %" G_GUINT32_FORMAT
7265                   " for gama atom, expected 12", size);
7266             }
7267             break;
7268           }
7269           case FOURCC_SMI_:{
7270             if (size > 16 && QT_FOURCC (data) == FOURCC_SEQH) {
7271               guint32 seqh_size;
7272               if (_seqh != NULL) {
7273                 GST_WARNING_OBJECT (qtdemux, "Unexpected second SEQH SMI atom "
7274                     " found, ignoring");
7275               } else {
7276                 seqh_size = QT_UINT32 (data + 4);
7277                 if (seqh_size > 0) {
7278                   _seqh = gst_buffer_new_and_alloc (seqh_size);
7279                   gst_buffer_fill (_seqh, 0, data + 8, seqh_size);
7280                 }
7281               }
7282             }
7283             break;
7284           }
7285           default:{
7286             GST_WARNING_OBJECT (qtdemux, "Unhandled atom %" GST_FOURCC_FORMAT
7287                 " in SVQ3 entry in stsd atom", GST_FOURCC_ARGS (fourcc));
7288           }
7289         }
7290
7291         if (size <= length) {
7292           length -= size;
7293           stsd_data += size;
7294         }
7295       }
7296     } else {
7297       GST_WARNING_OBJECT (qtdemux, "SVQ3 entry too short in stsd atom");
7298     }
7299   } else {
7300     GST_WARNING_OBJECT (qtdemux, "Unexpected version for SVQ3 entry %"
7301         G_GUINT16_FORMAT, version);
7302     goto end;
7303   }
7304
7305 end:
7306   if (gamma) {
7307     *gamma = _gamma;
7308   }
7309   if (seqh) {
7310     *seqh = _seqh;
7311   } else if (_seqh) {
7312     gst_buffer_unref (_seqh);
7313   }
7314 }
7315
7316 static gchar *
7317 qtdemux_get_rtsp_uri_from_hndl (GstQTDemux * qtdemux, GNode * minf)
7318 {
7319   GNode *dinf;
7320   GstByteReader dref;
7321   gchar *uri = NULL;
7322
7323   /*
7324    * Get 'dinf', to get its child 'dref', that might contain a 'hndl'
7325    * atom that might contain a 'data' atom with the rtsp uri.
7326    * This case was reported in bug #597497, some info about
7327    * the hndl atom can be found in TN1195
7328    */
7329   dinf = qtdemux_tree_get_child_by_type (minf, FOURCC_dinf);
7330   GST_DEBUG_OBJECT (qtdemux, "Trying to obtain rtsp URI for stream trak");
7331
7332   if (dinf) {
7333     guint32 dref_num_entries = 0;
7334     if (qtdemux_tree_get_child_by_type_full (dinf, FOURCC_dref, &dref) &&
7335         gst_byte_reader_skip (&dref, 4) &&
7336         gst_byte_reader_get_uint32_be (&dref, &dref_num_entries)) {
7337       gint i;
7338
7339       /* search dref entries for hndl atom */
7340       for (i = 0; i < dref_num_entries; i++) {
7341         guint32 size = 0, type;
7342         guint8 string_len = 0;
7343         if (gst_byte_reader_get_uint32_be (&dref, &size) &&
7344             qt_atom_parser_get_fourcc (&dref, &type)) {
7345           if (type == FOURCC_hndl) {
7346             GST_DEBUG_OBJECT (qtdemux, "Found hndl atom");
7347
7348             /* skip data reference handle bytes and the
7349              * following pascal string and some extra 4
7350              * bytes I have no idea what are */
7351             if (!gst_byte_reader_skip (&dref, 4) ||
7352                 !gst_byte_reader_get_uint8 (&dref, &string_len) ||
7353                 !gst_byte_reader_skip (&dref, string_len + 4)) {
7354               GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl atom");
7355               break;
7356             }
7357
7358             /* iterate over the atoms to find the data atom */
7359             while (gst_byte_reader_get_remaining (&dref) >= 8) {
7360               guint32 atom_size;
7361               guint32 atom_type;
7362
7363               if (gst_byte_reader_get_uint32_be (&dref, &atom_size) &&
7364                   qt_atom_parser_get_fourcc (&dref, &atom_type)) {
7365                 if (atom_type == FOURCC_data) {
7366                   const guint8 *uri_aux = NULL;
7367
7368                   /* found the data atom that might contain the rtsp uri */
7369                   GST_DEBUG_OBJECT (qtdemux, "Found data atom inside "
7370                       "hndl atom, interpreting it as an URI");
7371                   if (gst_byte_reader_peek_data (&dref, atom_size - 8,
7372                           &uri_aux)) {
7373                     if (g_strstr_len ((gchar *) uri_aux, 7, "rtsp://") != NULL)
7374                       uri = g_strndup ((gchar *) uri_aux, atom_size - 8);
7375                     else
7376                       GST_WARNING_OBJECT (qtdemux, "Data atom in hndl atom "
7377                           "didn't contain a rtsp address");
7378                   } else {
7379                     GST_WARNING_OBJECT (qtdemux, "Failed to get the data "
7380                         "atom contents");
7381                   }
7382                   break;
7383                 }
7384                 /* skipping to the next entry */
7385                 if (!gst_byte_reader_skip (&dref, atom_size - 8))
7386                   break;
7387               } else {
7388                 GST_WARNING_OBJECT (qtdemux, "Failed to parse hndl child "
7389                     "atom header");
7390                 break;
7391               }
7392             }
7393             break;
7394           }
7395           /* skip to the next entry */
7396           if (!gst_byte_reader_skip (&dref, size - 8))
7397             break;
7398         } else {
7399           GST_WARNING_OBJECT (qtdemux, "Error parsing dref atom");
7400         }
7401       }
7402       GST_DEBUG_OBJECT (qtdemux, "Finished parsing dref atom");
7403     }
7404   }
7405   return uri;
7406 }
7407
7408 #define AMR_NB_ALL_MODES        0x81ff
7409 #define AMR_WB_ALL_MODES        0x83ff
7410 static guint
7411 qtdemux_parse_amr_bitrate (GstBuffer * buf, gboolean wb)
7412 {
7413   /* The 'damr' atom is of the form:
7414    *
7415    * | vendor | decoder_ver | mode_set | mode_change_period | frames/sample |
7416    *    32 b       8 b          16 b           8 b                 8 b
7417    *
7418    * The highest set bit of the first 7 (AMR-NB) or 8 (AMR-WB) bits of mode_set
7419    * represents the highest mode used in the stream (and thus the maximum
7420    * bitrate), with a couple of special cases as seen below.
7421    */
7422
7423   /* Map of frame type ID -> bitrate */
7424   static const guint nb_bitrates[] = {
7425     4750, 5150, 5900, 6700, 7400, 7950, 10200, 12200
7426   };
7427   static const guint wb_bitrates[] = {
7428     6600, 8850, 12650, 14250, 15850, 18250, 19850, 23050, 23850
7429   };
7430   GstMapInfo map;
7431   gsize max_mode;
7432   guint16 mode_set;
7433
7434   gst_buffer_map (buf, &map, GST_MAP_READ);
7435
7436   if (map.size != 0x11) {
7437     GST_DEBUG ("Atom should have size 0x11, not %" G_GSIZE_FORMAT, map.size);
7438     goto bad_data;
7439   }
7440
7441   if (QT_FOURCC (map.data + 4) != GST_MAKE_FOURCC ('d', 'a', 'm', 'r')) {
7442     GST_DEBUG ("Unknown atom in %" GST_FOURCC_FORMAT,
7443         GST_FOURCC_ARGS (QT_UINT32 (map.data + 4)));
7444     goto bad_data;
7445   }
7446
7447   mode_set = QT_UINT16 (map.data + 13);
7448
7449   if (mode_set == (wb ? AMR_WB_ALL_MODES : AMR_NB_ALL_MODES))
7450     max_mode = 7 + (wb ? 1 : 0);
7451   else
7452     /* AMR-NB modes fo from 0-7, and AMR-WB modes go from 0-8 */
7453     max_mode = g_bit_nth_msf ((gulong) mode_set & (wb ? 0x1ff : 0xff), -1);
7454
7455   if (max_mode == -1) {
7456     GST_DEBUG ("No mode indication was found (mode set) = %x",
7457         (guint) mode_set);
7458     goto bad_data;
7459   }
7460
7461   gst_buffer_unmap (buf, &map);
7462   return wb ? wb_bitrates[max_mode] : nb_bitrates[max_mode];
7463
7464 bad_data:
7465   gst_buffer_unmap (buf, &map);
7466   return 0;
7467 }
7468
7469 static gboolean
7470 qtdemux_parse_transformation_matrix (GstQTDemux * qtdemux,
7471     GstByteReader * reader, guint32 * matrix, const gchar * atom)
7472 {
7473   /*
7474    * 9 values of 32 bits (fixed point 16.16, except 2 5 and 8 that are 2.30)
7475    * [0 1 2]
7476    * [3 4 5]
7477    * [6 7 8]
7478    */
7479
7480   if (gst_byte_reader_get_remaining (reader) < 36)
7481     return FALSE;
7482
7483   matrix[0] = gst_byte_reader_get_uint32_be_unchecked (reader);
7484   matrix[1] = gst_byte_reader_get_uint32_be_unchecked (reader);
7485   matrix[2] = gst_byte_reader_get_uint32_be_unchecked (reader);
7486   matrix[3] = gst_byte_reader_get_uint32_be_unchecked (reader);
7487   matrix[4] = gst_byte_reader_get_uint32_be_unchecked (reader);
7488   matrix[5] = gst_byte_reader_get_uint32_be_unchecked (reader);
7489   matrix[6] = gst_byte_reader_get_uint32_be_unchecked (reader);
7490   matrix[7] = gst_byte_reader_get_uint32_be_unchecked (reader);
7491   matrix[8] = gst_byte_reader_get_uint32_be_unchecked (reader);
7492
7493   GST_DEBUG_OBJECT (qtdemux, "Transformation matrix from atom %s", atom);
7494   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[0] >> 16,
7495       matrix[0] & 0xFFFF, matrix[1] >> 16, matrix[1] & 0xFF, matrix[2] >> 16,
7496       matrix[2] & 0xFF);
7497   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[3] >> 16,
7498       matrix[3] & 0xFFFF, matrix[4] >> 16, matrix[4] & 0xFF, matrix[5] >> 16,
7499       matrix[5] & 0xFF);
7500   GST_DEBUG_OBJECT (qtdemux, "%u.%u %u.%u %u.%u", matrix[6] >> 16,
7501       matrix[6] & 0xFFFF, matrix[7] >> 16, matrix[7] & 0xFF, matrix[8] >> 16,
7502       matrix[8] & 0xFF);
7503
7504   return TRUE;
7505 }
7506
7507 static void
7508 qtdemux_inspect_transformation_matrix (GstQTDemux * qtdemux,
7509     QtDemuxStream * stream, guint32 * matrix, GstTagList ** taglist)
7510 {
7511
7512 /* [a b c]
7513  * [d e f]
7514  * [g h i]
7515  *
7516  * This macro will only compare value abdegh, it expects cfi to have already
7517  * been checked
7518  */
7519 #define QTCHECK_MATRIX(m,a,b,d,e,g,h) ((m)[0] == (a << 16) && (m)[1] == (b << 16) && \
7520                                        (m)[3] == (d << 16) && (m)[4] == (e << 16) && \
7521                                        (m)[6] == (g << 16) && (m)[7] == (h << 16))
7522
7523   /* only handle the cases where the last column has standard values */
7524   if (matrix[2] == 0 && matrix[5] == 0 && matrix[8] == 1 << 30) {
7525     const gchar *rotation_tag = NULL;
7526
7527     /* no rotation needed */
7528     if (QTCHECK_MATRIX (matrix, 1, 0, 0, 1, 0, 0)) {
7529       /* NOP */
7530     } else if (QTCHECK_MATRIX (matrix, 0, 1, G_MAXUINT16, 0,
7531             stream->display_height, 0)) {
7532       rotation_tag = "rotate-90";
7533     } else if (QTCHECK_MATRIX (matrix, G_MAXUINT16, 0, 0, G_MAXUINT16,
7534             stream->display_width, stream->display_height)) {
7535       rotation_tag = "rotate-180";
7536     } else if (QTCHECK_MATRIX (matrix, 0, G_MAXUINT16, 1, 0, 0,
7537             stream->display_width)) {
7538       rotation_tag = "rotate-270";
7539     } else {
7540       GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7541     }
7542
7543     GST_DEBUG_OBJECT (qtdemux, "Transformation matrix rotation %s",
7544         rotation_tag);
7545     if (rotation_tag != NULL) {
7546       if (*taglist == NULL)
7547         *taglist = gst_tag_list_new_empty ();
7548       gst_tag_list_add (*taglist, GST_TAG_MERGE_REPLACE,
7549           GST_TAG_IMAGE_ORIENTATION, rotation_tag, NULL);
7550     }
7551   } else {
7552     GST_FIXME_OBJECT (qtdemux, "Unhandled transformation matrix values");
7553   }
7554 }
7555
7556 /* parse the traks.
7557  * With each track we associate a new QtDemuxStream that contains all the info
7558  * about the trak.
7559  * traks that do not decode to something (like strm traks) will not have a pad.
7560  */
7561 static gboolean
7562 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
7563 {
7564   GstByteReader tkhd;
7565   int offset;
7566   GNode *mdia;
7567   GNode *mdhd;
7568   GNode *hdlr;
7569   GNode *minf;
7570   GNode *stbl;
7571   GNode *stsd;
7572   GNode *mp4a;
7573   GNode *mp4v;
7574   GNode *wave;
7575   GNode *esds;
7576   GNode *pasp;
7577   GNode *tref;
7578
7579   QtDemuxStream *stream = NULL;
7580   gboolean new_stream = FALSE;
7581   GstTagList *list = NULL;
7582   gchar *codec = NULL;
7583   const guint8 *stsd_data;
7584   guint16 lang_code;            /* quicktime lang code or packed iso code */
7585   guint32 version;
7586   guint32 tkhd_flags = 0;
7587   guint8 tkhd_version = 0;
7588   guint32 fourcc;
7589   guint value_size, stsd_len, len;
7590   guint32 track_id;
7591
7592   GST_DEBUG_OBJECT (qtdemux, "parse_trak");
7593
7594   if (!qtdemux_tree_get_child_by_type_full (trak, FOURCC_tkhd, &tkhd)
7595       || !gst_byte_reader_get_uint8 (&tkhd, &tkhd_version)
7596       || !gst_byte_reader_get_uint24_be (&tkhd, &tkhd_flags))
7597     goto corrupt_file;
7598
7599   /* pick between 64 or 32 bits */
7600   value_size = tkhd_version == 1 ? 8 : 4;
7601   if (!gst_byte_reader_skip (&tkhd, value_size * 2) ||
7602       !gst_byte_reader_get_uint32_be (&tkhd, &track_id))
7603     goto corrupt_file;
7604
7605   if (!qtdemux->got_moov) {
7606     if (qtdemux_find_stream (qtdemux, track_id))
7607       goto existing_stream;
7608     stream = _create_stream ();
7609     stream->track_id = track_id;
7610     new_stream = TRUE;
7611   } else {
7612     stream = qtdemux_find_stream (qtdemux, track_id);
7613     if (!stream) {
7614       GST_WARNING_OBJECT (qtdemux, "Stream not found, going to ignore it");
7615       goto skip_track;
7616     }
7617   }
7618
7619   if ((tkhd_flags & 1) == 0)
7620     stream->disabled = TRUE;
7621
7622   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags/id: 0x%02x/%06x/%u",
7623       tkhd_version, tkhd_flags, stream->track_id);
7624
7625   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
7626     goto corrupt_file;
7627
7628   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
7629     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
7630     if (qtdemux->major_brand != FOURCC_mjp2 ||
7631         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
7632       goto corrupt_file;
7633   }
7634
7635   len = QT_UINT32 ((guint8 *) mdhd->data);
7636   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
7637   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
7638   if (version == 0x01000000) {
7639     if (len < 38)
7640       goto corrupt_file;
7641     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
7642     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
7643     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 36);
7644   } else {
7645     if (len < 30)
7646       goto corrupt_file;
7647     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
7648     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
7649     lang_code = QT_UINT16 ((guint8 *) mdhd->data + 28);
7650   }
7651
7652   if (lang_code < 0x400) {
7653     qtdemux_lang_map_qt_code_to_iso (stream->lang_id, lang_code);
7654   } else if (lang_code == 0x7fff) {
7655     stream->lang_id[0] = 0;     /* unspecified */
7656   } else {
7657     stream->lang_id[0] = 0x60 + ((lang_code >> 10) & 0x1F);
7658     stream->lang_id[1] = 0x60 + ((lang_code >> 5) & 0x1F);
7659     stream->lang_id[2] = 0x60 + (lang_code & 0x1F);
7660     stream->lang_id[3] = 0;
7661   }
7662
7663   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
7664       stream->timescale);
7665   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
7666       stream->duration);
7667   GST_LOG_OBJECT (qtdemux, "track language code/id: 0x%04x/%s",
7668       lang_code, stream->lang_id);
7669
7670   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
7671     goto corrupt_file;
7672
7673   if ((tref = qtdemux_tree_get_child_by_type (trak, FOURCC_tref))) {
7674     /* chapters track reference */
7675     GNode *chap = qtdemux_tree_get_child_by_type (tref, FOURCC_chap);
7676     if (chap) {
7677       gsize length = GST_READ_UINT32_BE (chap->data);
7678       if (qtdemux->chapters_track_id)
7679         GST_FIXME_OBJECT (qtdemux, "Multiple CHAP tracks");
7680
7681       if (length >= 12) {
7682         qtdemux->chapters_track_id =
7683             GST_READ_UINT32_BE ((gint8 *) chap->data + 8);
7684       }
7685     }
7686   }
7687
7688   /* fragmented files may have bogus duration in moov */
7689   if (!qtdemux->fragmented &&
7690       qtdemux->duration != G_MAXINT64 && stream->duration != G_MAXINT32) {
7691     guint64 tdur1, tdur2;
7692
7693     /* don't overflow */
7694     tdur1 = stream->timescale * (guint64) qtdemux->duration;
7695     tdur2 = qtdemux->timescale * (guint64) stream->duration;
7696
7697     /* HACK:
7698      * some of those trailers, nowadays, have prologue images that are
7699      * themselves vide tracks as well. I haven't really found a way to
7700      * identify those yet, except for just looking at their duration. */
7701     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
7702       GST_WARNING_OBJECT (qtdemux,
7703           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
7704           " vs. %" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
7705           "found, assuming preview image or something; skipping track",
7706           stream->duration, stream->timescale, qtdemux->duration,
7707           qtdemux->timescale);
7708       g_free (stream);
7709       return TRUE;
7710     }
7711   }
7712
7713   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
7714     goto corrupt_file;
7715
7716   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
7717       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
7718
7719   len = QT_UINT32 ((guint8 *) hdlr->data);
7720   if (len >= 20)
7721     stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
7722   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
7723       GST_FOURCC_ARGS (stream->subtype));
7724
7725   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
7726     goto corrupt_file;
7727
7728   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
7729     goto corrupt_file;
7730
7731   /* parse stsd */
7732   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
7733     goto corrupt_file;
7734   stsd_data = (const guint8 *) stsd->data;
7735
7736   /* stsd should at least have one entry */
7737   stsd_len = QT_UINT32 (stsd_data);
7738   if (stsd_len < 24) {
7739     /* .. but skip stream with empty stsd produced by some Vivotek cameras */
7740     if (stream->subtype == FOURCC_vivo) {
7741       g_free (stream);
7742       return TRUE;
7743     } else {
7744       goto corrupt_file;
7745     }
7746   }
7747
7748   GST_LOG_OBJECT (qtdemux, "stsd len:           %d", stsd_len);
7749
7750   /* and that entry should fit within stsd */
7751   len = QT_UINT32 (stsd_data + 16);
7752   if (len > stsd_len + 16)
7753     goto corrupt_file;
7754
7755   stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
7756   GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
7757       GST_FOURCC_ARGS (stream->fourcc));
7758   GST_LOG_OBJECT (qtdemux, "stsd type len:      %d", len);
7759
7760   if ((fourcc == FOURCC_drms) || (fourcc == FOURCC_drmi) ||
7761       ((fourcc & 0x00FFFFFF) == GST_MAKE_FOURCC ('e', 'n', 'c', 0)))
7762     goto error_encrypted;
7763
7764   if (stream->subtype == FOURCC_vide) {
7765     guint32 w = 0, h = 0;
7766     gboolean gray;
7767     gint depth, palette_size, palette_count;
7768     guint32 matrix[9];
7769     guint32 *palette_data = NULL;
7770
7771     stream->sampled = TRUE;
7772
7773     /* version 1 uses some 64-bit ints */
7774     if (!gst_byte_reader_skip (&tkhd, 20 + value_size))
7775       goto corrupt_file;
7776
7777     if (!qtdemux_parse_transformation_matrix (qtdemux, &tkhd, matrix, "tkhd"))
7778       goto corrupt_file;
7779
7780     if (!gst_byte_reader_get_uint32_be (&tkhd, &w)
7781         || !gst_byte_reader_get_uint32_be (&tkhd, &h))
7782       goto corrupt_file;
7783
7784     stream->display_width = w >> 16;
7785     stream->display_height = h >> 16;
7786
7787     qtdemux_inspect_transformation_matrix (qtdemux, stream, matrix, &list);
7788
7789     offset = 16;
7790     if (len < 86)
7791       goto corrupt_file;
7792
7793     stream->width = QT_UINT16 (stsd_data + offset + 32);
7794     stream->height = QT_UINT16 (stsd_data + offset + 34);
7795     stream->fps_n = 0;          /* this is filled in later */
7796     stream->fps_d = 0;          /* this is filled in later */
7797     stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
7798     stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
7799
7800     GST_LOG_OBJECT (qtdemux, "width %d, height %d, bps %d, color table id %d",
7801         stream->width, stream->height, stream->bits_per_sample,
7802         stream->color_table_id);
7803
7804     depth = stream->bits_per_sample;
7805
7806     /* more than 32 bits means grayscale */
7807     gray = (depth > 32);
7808     /* low 32 bits specify the depth  */
7809     depth &= 0x1F;
7810
7811     /* different number of palette entries is determined by depth. */
7812     palette_count = 0;
7813     if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
7814       palette_count = (1 << depth);
7815     palette_size = palette_count * 4;
7816
7817     if (stream->color_table_id) {
7818       switch (palette_count) {
7819         case 0:
7820           break;
7821         case 2:
7822           palette_data = g_memdup (ff_qt_default_palette_2, palette_size);
7823           break;
7824         case 4:
7825           palette_data = g_memdup (ff_qt_default_palette_4, palette_size);
7826           break;
7827         case 16:
7828           if (gray)
7829             palette_data = g_memdup (ff_qt_grayscale_palette_16, palette_size);
7830           else
7831             palette_data = g_memdup (ff_qt_default_palette_16, palette_size);
7832           break;
7833         case 256:
7834           if (gray)
7835             palette_data = g_memdup (ff_qt_grayscale_palette_256, palette_size);
7836           else
7837             palette_data = g_memdup (ff_qt_default_palette_256, palette_size);
7838           break;
7839         default:
7840           GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
7841               (_("The video in this file might not play correctly.")),
7842               ("unsupported palette depth %d", depth));
7843           break;
7844       }
7845     } else {
7846       gint i, j, start, end;
7847
7848       if (len < 94)
7849         goto corrupt_file;
7850
7851       /* read table */
7852       start = QT_UINT32 (stsd_data + offset + 86);
7853       palette_count = QT_UINT16 (stsd_data + offset + 90);
7854       end = QT_UINT16 (stsd_data + offset + 92);
7855
7856       GST_LOG_OBJECT (qtdemux, "start %d, end %d, palette_count %d",
7857           start, end, palette_count);
7858
7859       if (end > 255)
7860         end = 255;
7861       if (start > end)
7862         start = end;
7863
7864       if (len < 94 + (end - start) * 8)
7865         goto corrupt_file;
7866
7867       /* palette is always the same size */
7868       palette_data = g_malloc0 (256 * 4);
7869       palette_size = 256 * 4;
7870
7871       for (j = 0, i = start; i <= end; j++, i++) {
7872         guint32 a, r, g, b;
7873
7874         a = QT_UINT16 (stsd_data + offset + 94 + (j * 8));
7875         r = QT_UINT16 (stsd_data + offset + 96 + (j * 8));
7876         g = QT_UINT16 (stsd_data + offset + 98 + (j * 8));
7877         b = QT_UINT16 (stsd_data + offset + 100 + (j * 8));
7878
7879         palette_data[i] = ((a & 0xff00) << 16) | ((r & 0xff00) << 8) |
7880             (g & 0xff00) | (b >> 8);
7881       }
7882     }
7883
7884     stream->caps =
7885         qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
7886     if (G_UNLIKELY (!stream->caps)) {
7887       g_free (palette_data);
7888       goto unknown_stream;
7889     }
7890
7891     if (codec) {
7892       if (list == NULL)
7893         list = gst_tag_list_new_empty ();
7894       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
7895           GST_TAG_VIDEO_CODEC, codec, NULL);
7896       g_free (codec);
7897       codec = NULL;
7898     }
7899
7900
7901     if (palette_data) {
7902       GstStructure *s;
7903
7904       if (stream->rgb8_palette)
7905         gst_memory_unref (stream->rgb8_palette);
7906       stream->rgb8_palette = gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY,
7907           palette_data, palette_size, 0, palette_size, palette_data, g_free);
7908
7909       s = gst_caps_get_structure (stream->caps, 0);
7910
7911       /* non-raw video has a palette_data property. raw video has the palette as
7912        * an extra plane that we append to the output buffers before we push
7913        * them*/
7914       if (!gst_structure_has_name (s, "video/x-raw")) {
7915         GstBuffer *palette;
7916
7917         palette = gst_buffer_new ();
7918         gst_buffer_append_memory (palette, stream->rgb8_palette);
7919         stream->rgb8_palette = NULL;
7920
7921         gst_caps_set_simple (stream->caps, "palette_data",
7922             GST_TYPE_BUFFER, palette, NULL);
7923         gst_buffer_unref (palette);
7924       }
7925     } else if (palette_count != 0) {
7926       GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
7927           (NULL), ("Unsupported palette depth %d", depth));
7928     }
7929
7930     GST_LOG_OBJECT (qtdemux, "frame count:   %u",
7931         QT_UINT16 (stsd_data + offset + 48));
7932
7933     esds = NULL;
7934     pasp = NULL;
7935     /* pick 'the' stsd child */
7936     mp4v = qtdemux_tree_get_child_by_type (stsd, fourcc);
7937     if (mp4v) {
7938       esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
7939       pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
7940     }
7941
7942     if (pasp) {
7943       const guint8 *pasp_data = (const guint8 *) pasp->data;
7944
7945       stream->par_w = QT_UINT32 (pasp_data + 8);
7946       stream->par_h = QT_UINT32 (pasp_data + 12);
7947     } else {
7948       stream->par_w = 0;
7949       stream->par_h = 0;
7950     }
7951
7952     if (esds) {
7953       gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
7954     } else {
7955       switch (fourcc) {
7956         case FOURCC_H264:
7957         case FOURCC_avc1:
7958         case FOURCC_avc3:
7959         {
7960           gint len = QT_UINT32 (stsd_data) - 0x66;
7961           const guint8 *avc_data = stsd_data + 0x66;
7962
7963           /* find avcC */
7964           while (len >= 0x8) {
7965             gint size;
7966
7967             if (QT_UINT32 (avc_data) <= len)
7968               size = QT_UINT32 (avc_data) - 0x8;
7969             else
7970               size = len - 0x8;
7971
7972             if (size < 1)
7973               /* No real data, so break out */
7974               break;
7975
7976             switch (QT_FOURCC (avc_data + 0x4)) {
7977               case FOURCC_avcC:
7978               {
7979                 /* parse, if found */
7980                 GstBuffer *buf;
7981
7982                 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
7983
7984                 /* First 4 bytes are the length of the atom, the next 4 bytes
7985                  * are the fourcc, the next 1 byte is the version, and the
7986                  * subsequent bytes are profile_tier_level structure like data. */
7987                 gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
7988                     avc_data + 8 + 1, size - 1);
7989                 buf = gst_buffer_new_and_alloc (size);
7990                 gst_buffer_fill (buf, 0, avc_data + 0x8, size);
7991                 gst_caps_set_simple (stream->caps,
7992                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
7993                 gst_buffer_unref (buf);
7994
7995                 break;
7996               }
7997               case FOURCC_strf:
7998               {
7999                 GstBuffer *buf;
8000
8001                 GST_DEBUG_OBJECT (qtdemux, "found strf codec_data in stsd");
8002
8003                 /* First 4 bytes are the length of the atom, the next 4 bytes
8004                  * are the fourcc, next 40 bytes are BITMAPINFOHEADER,
8005                  * next 1 byte is the version, and the
8006                  * subsequent bytes are sequence parameter set like data. */
8007
8008                 size -= 40;     /* we'll be skipping BITMAPINFOHEADER */
8009                 if (size > 1) {
8010                   gst_codec_utils_h264_caps_set_level_and_profile (stream->caps,
8011                       avc_data + 8 + 40 + 1, size - 1);
8012
8013                   buf = gst_buffer_new_and_alloc (size);
8014                   gst_buffer_fill (buf, 0, avc_data + 8 + 40, size);
8015                   gst_caps_set_simple (stream->caps,
8016                       "codec_data", GST_TYPE_BUFFER, buf, NULL);
8017                   gst_buffer_unref (buf);
8018                 }
8019                 break;
8020               }
8021               case FOURCC_btrt:
8022               {
8023                 guint avg_bitrate, max_bitrate;
8024
8025                 /* bufferSizeDB, maxBitrate and avgBitrate - 4 bytes each */
8026                 if (size < 12)
8027                   break;
8028
8029                 max_bitrate = QT_UINT32 (avc_data + 0xc);
8030                 avg_bitrate = QT_UINT32 (avc_data + 0x10);
8031
8032                 if (!max_bitrate && !avg_bitrate)
8033                   break;
8034
8035                 /* Some muxers seem to swap the average and maximum bitrates
8036                  * (I'm looking at you, YouTube), so we swap for sanity. */
8037                 if (max_bitrate > 0 && max_bitrate < avg_bitrate) {
8038                   guint temp = avg_bitrate;
8039
8040                   avg_bitrate = max_bitrate;
8041                   max_bitrate = temp;
8042                 }
8043
8044                 if (!list)
8045                   list = gst_tag_list_new_empty ();
8046
8047                 if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
8048                   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8049                       GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
8050                 }
8051                 if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
8052                   gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8053                       GST_TAG_BITRATE, avg_bitrate, NULL);
8054                 }
8055
8056                 break;
8057               }
8058
8059               default:
8060                 break;
8061             }
8062
8063             len -= size + 8;
8064             avc_data += size + 8;
8065           }
8066
8067           break;
8068         }
8069         case FOURCC_H265:
8070         case FOURCC_hvc1:
8071         case FOURCC_hev1:
8072         {
8073           gint len = QT_UINT32 (stsd_data) - 0x66;
8074           const guint8 *hevc_data = stsd_data + 0x66;
8075
8076           /* find hevc */
8077           while (len >= 0x8) {
8078             gint size;
8079
8080             if (QT_UINT32 (hevc_data) <= len)
8081               size = QT_UINT32 (hevc_data) - 0x8;
8082             else
8083               size = len - 0x8;
8084
8085             if (size < 1)
8086               /* No real data, so break out */
8087               break;
8088
8089             switch (QT_FOURCC (hevc_data + 0x4)) {
8090               case FOURCC_hvcC:
8091               {
8092                 /* parse, if found */
8093                 GstBuffer *buf;
8094
8095                 GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
8096
8097                 /* First 4 bytes are the length of the atom, the next 4 bytes
8098                  * are the fourcc, the next 1 byte is the version, and the
8099                  * subsequent bytes are sequence parameter set like data. */
8100                 gst_codec_utils_h265_caps_set_level_tier_and_profile
8101                     (stream->caps, hevc_data + 8 + 1, size - 1);
8102
8103                 buf = gst_buffer_new_and_alloc (size);
8104                 gst_buffer_fill (buf, 0, hevc_data + 0x8, size);
8105                 gst_caps_set_simple (stream->caps,
8106                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
8107                 gst_buffer_unref (buf);
8108                 break;
8109               }
8110               default:
8111                 break;
8112             }
8113             len -= size + 8;
8114             hevc_data += size + 8;
8115           }
8116           break;
8117         }
8118         case FOURCC_mp4v:
8119         case FOURCC_MP4V:
8120         case FOURCC_fmp4:
8121         case FOURCC_FMP4:
8122         {
8123           GNode *glbl;
8124
8125           GST_DEBUG_OBJECT (qtdemux, "found %" GST_FOURCC_FORMAT,
8126               GST_FOURCC_ARGS (fourcc));
8127
8128           /* codec data might be in glbl extension atom */
8129           glbl = mp4v ?
8130               qtdemux_tree_get_child_by_type (mp4v, FOURCC_glbl) : NULL;
8131           if (glbl) {
8132             guint8 *data;
8133             GstBuffer *buf;
8134             gint len;
8135
8136             GST_DEBUG_OBJECT (qtdemux, "found glbl data in stsd");
8137             data = glbl->data;
8138             len = QT_UINT32 (data);
8139             if (len > 0x8) {
8140               len -= 0x8;
8141               buf = gst_buffer_new_and_alloc (len);
8142               gst_buffer_fill (buf, 0, data + 8, len);
8143               gst_caps_set_simple (stream->caps,
8144                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
8145               gst_buffer_unref (buf);
8146             }
8147           }
8148           break;
8149         }
8150         case FOURCC_mjp2:
8151         {
8152           /* see annex I of the jpeg2000 spec */
8153           GNode *jp2h, *ihdr, *colr, *mjp2, *field, *prefix, *cmap, *cdef;
8154           const guint8 *data;
8155           const gchar *colorspace = NULL;
8156           gint ncomp = 0;
8157           guint32 ncomp_map = 0;
8158           gint32 *comp_map = NULL;
8159           guint32 nchan_def = 0;
8160           gint32 *chan_def = NULL;
8161
8162           GST_DEBUG_OBJECT (qtdemux, "found mjp2");
8163           /* some required atoms */
8164           mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
8165           if (!mjp2)
8166             break;
8167           jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
8168           if (!jp2h)
8169             break;
8170
8171           /* number of components; redundant with info in codestream, but useful
8172              to a muxer */
8173           ihdr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_ihdr);
8174           if (!ihdr || QT_UINT32 (ihdr->data) != 22)
8175             break;
8176           ncomp = QT_UINT16 (((guint8 *) ihdr->data) + 16);
8177
8178           colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
8179           if (!colr)
8180             break;
8181           GST_DEBUG_OBJECT (qtdemux, "found colr");
8182           /* extract colour space info */
8183           if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
8184             switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
8185               case 16:
8186                 colorspace = "sRGB";
8187                 break;
8188               case 17:
8189                 colorspace = "GRAY";
8190                 break;
8191               case 18:
8192                 colorspace = "sYUV";
8193                 break;
8194               default:
8195                 colorspace = NULL;
8196                 break;
8197             }
8198           }
8199           if (!colorspace)
8200             /* colr is required, and only values 16, 17, and 18 are specified,
8201                so error if we have no colorspace */
8202             break;
8203
8204           /* extract component mapping */
8205           cmap = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cmap);
8206           if (cmap) {
8207             guint32 cmap_len = 0;
8208             int i;
8209             cmap_len = QT_UINT32 (cmap->data);
8210             if (cmap_len >= 8) {
8211               /* normal box, subtract off header */
8212               cmap_len -= 8;
8213               /* cmap: { u16 cmp; u8 mtyp; u8 pcol; }* */
8214               if (cmap_len % 4 == 0) {
8215                 ncomp_map = (cmap_len / 4);
8216                 comp_map = g_new0 (gint32, ncomp_map);
8217                 for (i = 0; i < ncomp_map; i++) {
8218                   guint16 cmp;
8219                   guint8 mtyp, pcol;
8220                   cmp = QT_UINT16 (((guint8 *) cmap->data) + 8 + i * 4);
8221                   mtyp = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 2);
8222                   pcol = QT_UINT8 (((guint8 *) cmap->data) + 8 + i * 4 + 3);
8223                   comp_map[i] = (mtyp << 24) | (pcol << 16) | cmp;
8224                 }
8225               }
8226             }
8227           }
8228           /* extract channel definitions */
8229           cdef = qtdemux_tree_get_child_by_type (jp2h, FOURCC_cdef);
8230           if (cdef) {
8231             guint32 cdef_len = 0;
8232             int i;
8233             cdef_len = QT_UINT32 (cdef->data);
8234             if (cdef_len >= 10) {
8235               /* normal box, subtract off header and len */
8236               cdef_len -= 10;
8237               /* cdef: u16 n; { u16 cn; u16 typ; u16 asoc; }* */
8238               if (cdef_len % 6 == 0) {
8239                 nchan_def = (cdef_len / 6);
8240                 chan_def = g_new0 (gint32, nchan_def);
8241                 for (i = 0; i < nchan_def; i++)
8242                   chan_def[i] = -1;
8243                 for (i = 0; i < nchan_def; i++) {
8244                   guint16 cn, typ, asoc;
8245                   cn = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6);
8246                   typ = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 2);
8247                   asoc = QT_UINT16 (((guint8 *) cdef->data) + 10 + i * 6 + 4);
8248                   if (cn < nchan_def) {
8249                     switch (typ) {
8250                       case 0:
8251                         chan_def[cn] = asoc;
8252                         break;
8253                       case 1:
8254                         chan_def[cn] = 0;       /* alpha */
8255                         break;
8256                       default:
8257                         chan_def[cn] = -typ;
8258                     }
8259                   }
8260                 }
8261               }
8262             }
8263           }
8264
8265           gst_caps_set_simple (stream->caps,
8266               "num-components", G_TYPE_INT, ncomp, NULL);
8267           gst_caps_set_simple (stream->caps,
8268               "colorspace", G_TYPE_STRING, colorspace, NULL);
8269
8270           if (comp_map) {
8271             GValue arr = { 0, };
8272             GValue elt = { 0, };
8273             int i;
8274             g_value_init (&arr, GST_TYPE_ARRAY);
8275             g_value_init (&elt, G_TYPE_INT);
8276             for (i = 0; i < ncomp_map; i++) {
8277               g_value_set_int (&elt, comp_map[i]);
8278               gst_value_array_append_value (&arr, &elt);
8279             }
8280             gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8281                 "component-map", &arr);
8282             g_value_unset (&elt);
8283             g_value_unset (&arr);
8284             g_free (comp_map);
8285           }
8286
8287           if (chan_def) {
8288             GValue arr = { 0, };
8289             GValue elt = { 0, };
8290             int i;
8291             g_value_init (&arr, GST_TYPE_ARRAY);
8292             g_value_init (&elt, G_TYPE_INT);
8293             for (i = 0; i < nchan_def; i++) {
8294               g_value_set_int (&elt, chan_def[i]);
8295               gst_value_array_append_value (&arr, &elt);
8296             }
8297             gst_structure_set_value (gst_caps_get_structure (stream->caps, 0),
8298                 "channel-definitions", &arr);
8299             g_value_unset (&elt);
8300             g_value_unset (&arr);
8301             g_free (chan_def);
8302           }
8303
8304           /* some optional atoms */
8305           field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
8306           prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
8307
8308           /* indicate possible fields in caps */
8309           if (field) {
8310             data = (guint8 *) field->data + 8;
8311             if (*data != 1)
8312               gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
8313                   (gint) * data, NULL);
8314           }
8315           /* add codec_data if provided */
8316           if (prefix) {
8317             GstBuffer *buf;
8318             gint len;
8319
8320             GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
8321             data = prefix->data;
8322             len = QT_UINT32 (data);
8323             if (len > 0x8) {
8324               len -= 0x8;
8325               buf = gst_buffer_new_and_alloc (len);
8326               gst_buffer_fill (buf, 0, data + 8, len);
8327               gst_caps_set_simple (stream->caps,
8328                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
8329               gst_buffer_unref (buf);
8330             }
8331           }
8332           break;
8333         }
8334         case FOURCC_SVQ3:
8335         case FOURCC_VP31:
8336         {
8337           GstBuffer *buf;
8338           GstBuffer *seqh = NULL;
8339           guint8 *gamma_data = NULL;
8340           gint len = QT_UINT32 (stsd_data);
8341
8342           qtdemux_parse_svq3_stsd_data (qtdemux, stsd, &gamma_data, &seqh);
8343           if (gamma_data) {
8344             gst_caps_set_simple (stream->caps, "applied-gamma", G_TYPE_DOUBLE,
8345                 QT_FP32 (gamma_data), NULL);
8346           }
8347           if (seqh) {
8348             /* sorry for the bad name, but we don't know what this is, other
8349              * than its own fourcc */
8350             gst_caps_set_simple (stream->caps, "seqh", GST_TYPE_BUFFER, seqh,
8351                 NULL);
8352           }
8353
8354           GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
8355           buf = gst_buffer_new_and_alloc (len);
8356           gst_buffer_fill (buf, 0, stsd_data, len);
8357           gst_caps_set_simple (stream->caps,
8358               "codec_data", GST_TYPE_BUFFER, buf, NULL);
8359           gst_buffer_unref (buf);
8360           break;
8361         }
8362         case FOURCC_rle_:
8363         case FOURCC_WRLE:
8364         {
8365           gst_caps_set_simple (stream->caps,
8366               "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
8367           break;
8368         }
8369         case FOURCC_XiTh:
8370         {
8371           GNode *xith, *xdxt;
8372
8373           GST_DEBUG_OBJECT (qtdemux, "found XiTh");
8374           xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
8375           if (!xith)
8376             break;
8377
8378           xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
8379           if (!xdxt)
8380             break;
8381
8382           GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
8383           /* collect the headers and store them in a stream list so that we can
8384            * send them out first */
8385           qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
8386           break;
8387         }
8388         case FOURCC_ovc1:
8389         {
8390           GNode *ovc1;
8391           guint8 *ovc1_data;
8392           guint ovc1_len;
8393           GstBuffer *buf;
8394
8395           GST_DEBUG_OBJECT (qtdemux, "parse ovc1 header");
8396           ovc1 = qtdemux_tree_get_child_by_type (stsd, FOURCC_ovc1);
8397           if (!ovc1)
8398             break;
8399           ovc1_data = ovc1->data;
8400           ovc1_len = QT_UINT32 (ovc1_data);
8401           if (ovc1_len <= 198) {
8402             GST_WARNING_OBJECT (qtdemux, "Too small ovc1 header, skipping");
8403             break;
8404           }
8405           buf = gst_buffer_new_and_alloc (ovc1_len - 198);
8406           gst_buffer_fill (buf, 0, ovc1_data + 198, ovc1_len - 198);
8407           gst_caps_set_simple (stream->caps,
8408               "codec_data", GST_TYPE_BUFFER, buf, NULL);
8409           gst_buffer_unref (buf);
8410           break;
8411         }
8412         case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
8413         {
8414           gint len = QT_UINT32 (stsd_data) - 0x66;
8415           const guint8 *vc1_data = stsd_data + 0x66;
8416
8417           /* find dvc1 */
8418           while (len >= 8) {
8419             gint size;
8420
8421             if (QT_UINT32 (vc1_data) <= len)
8422               size = QT_UINT32 (vc1_data) - 8;
8423             else
8424               size = len - 8;
8425
8426             if (size < 1)
8427               /* No real data, so break out */
8428               break;
8429
8430             switch (QT_FOURCC (vc1_data + 0x4)) {
8431               case GST_MAKE_FOURCC ('d', 'v', 'c', '1'):
8432               {
8433                 GstBuffer *buf;
8434
8435                 GST_DEBUG_OBJECT (qtdemux, "found dvc1 codec_data in stsd");
8436                 buf = gst_buffer_new_and_alloc (size);
8437                 gst_buffer_fill (buf, 0, vc1_data + 8, size);
8438                 gst_caps_set_simple (stream->caps,
8439                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
8440                 gst_buffer_unref (buf);
8441                 break;
8442               }
8443               default:
8444                 break;
8445             }
8446             len -= size + 8;
8447             vc1_data += size + 8;
8448           }
8449           break;
8450         }
8451         default:
8452           break;
8453       }
8454     }
8455
8456     GST_INFO_OBJECT (qtdemux,
8457         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
8458         GST_FOURCC_ARGS (fourcc), stream->caps);
8459
8460   } else if (stream->subtype == FOURCC_soun) {
8461     int version, samplesize;
8462     guint16 compression_id;
8463     gboolean amrwb = FALSE;
8464
8465     offset = 32;
8466     /* sample description entry (16) + sound sample description v0 (20) */
8467     if (len < 36)
8468       goto corrupt_file;
8469
8470     version = QT_UINT32 (stsd_data + offset);
8471     stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
8472     samplesize = QT_UINT16 (stsd_data + offset + 10);
8473     compression_id = QT_UINT16 (stsd_data + offset + 12);
8474     stream->rate = QT_FP32 (stsd_data + offset + 16);
8475
8476     GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
8477     GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
8478         QT_UINT32 (stsd_data + offset + 4));
8479     GST_LOG_OBJECT (qtdemux, "n_channels:       %d", stream->n_channels);
8480     GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
8481     GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
8482     GST_LOG_OBJECT (qtdemux, "packet size:      %d",
8483         QT_UINT16 (stsd_data + offset + 14));
8484     GST_LOG_OBJECT (qtdemux, "sample rate:      %g", stream->rate);
8485
8486     if (compression_id == 0xfffe)
8487       stream->sampled = TRUE;
8488
8489     /* first assume uncompressed audio */
8490     stream->bytes_per_sample = samplesize / 8;
8491     stream->samples_per_frame = stream->n_channels;
8492     stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
8493     stream->samples_per_packet = stream->samples_per_frame;
8494     stream->bytes_per_packet = stream->bytes_per_sample;
8495
8496     offset = 52;
8497     switch (fourcc) {
8498         /* Yes, these have to be hard-coded */
8499       case FOURCC_MAC6:
8500       {
8501         stream->samples_per_packet = 6;
8502         stream->bytes_per_packet = 1;
8503         stream->bytes_per_frame = 1 * stream->n_channels;
8504         stream->bytes_per_sample = 1;
8505         stream->samples_per_frame = 6 * stream->n_channels;
8506         break;
8507       }
8508       case FOURCC_MAC3:
8509       {
8510         stream->samples_per_packet = 3;
8511         stream->bytes_per_packet = 1;
8512         stream->bytes_per_frame = 1 * stream->n_channels;
8513         stream->bytes_per_sample = 1;
8514         stream->samples_per_frame = 3 * stream->n_channels;
8515         break;
8516       }
8517       case FOURCC_ima4:
8518       {
8519         stream->samples_per_packet = 64;
8520         stream->bytes_per_packet = 34;
8521         stream->bytes_per_frame = 34 * stream->n_channels;
8522         stream->bytes_per_sample = 2;
8523         stream->samples_per_frame = 64 * stream->n_channels;
8524         break;
8525       }
8526       case FOURCC_ulaw:
8527       case FOURCC_alaw:
8528       {
8529         stream->samples_per_packet = 1;
8530         stream->bytes_per_packet = 1;
8531         stream->bytes_per_frame = 1 * stream->n_channels;
8532         stream->bytes_per_sample = 1;
8533         stream->samples_per_frame = 1 * stream->n_channels;
8534         break;
8535       }
8536       case FOURCC_agsm:
8537       {
8538         stream->samples_per_packet = 160;
8539         stream->bytes_per_packet = 33;
8540         stream->bytes_per_frame = 33 * stream->n_channels;
8541         stream->bytes_per_sample = 2;
8542         stream->samples_per_frame = 160 * stream->n_channels;
8543         break;
8544       }
8545       default:
8546         break;
8547     }
8548
8549     if (version == 0x00010000) {
8550       /* sample description entry (16) + sound sample description v1 (20+16) */
8551       if (len < 52)
8552         goto corrupt_file;
8553
8554       switch (fourcc) {
8555         case FOURCC_twos:
8556         case FOURCC_sowt:
8557         case FOURCC_raw_:
8558           break;
8559         default:
8560         {
8561           /* only parse extra decoding config for non-pcm audio */
8562           stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
8563           stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
8564           stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
8565           stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
8566
8567           GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
8568               stream->samples_per_packet);
8569           GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
8570               stream->bytes_per_packet);
8571           GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
8572               stream->bytes_per_frame);
8573           GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
8574               stream->bytes_per_sample);
8575
8576           if (!stream->sampled && stream->bytes_per_packet) {
8577             stream->samples_per_frame = (stream->bytes_per_frame /
8578                 stream->bytes_per_packet) * stream->samples_per_packet;
8579             GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
8580                 stream->samples_per_frame);
8581           }
8582           break;
8583         }
8584       }
8585     } else if (version == 0x00020000) {
8586       union
8587       {
8588         gdouble fp;
8589         guint64 val;
8590       } qtfp;
8591
8592       /* sample description entry (16) + sound sample description v2 (56) */
8593       if (len < 72)
8594         goto corrupt_file;
8595
8596       qtfp.val = QT_UINT64 (stsd_data + offset + 4);
8597       stream->rate = qtfp.fp;
8598       stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
8599
8600       GST_LOG_OBJECT (qtdemux, "Sound sample description Version 2");
8601       GST_LOG_OBJECT (qtdemux, "sample rate:        %g", stream->rate);
8602       GST_LOG_OBJECT (qtdemux, "n_channels:         %d", stream->n_channels);
8603       GST_LOG_OBJECT (qtdemux, "bits/channel:       %d",
8604           QT_UINT32 (stsd_data + offset + 20));
8605       GST_LOG_OBJECT (qtdemux, "format flags:       %X",
8606           QT_UINT32 (stsd_data + offset + 24));
8607       GST_LOG_OBJECT (qtdemux, "bytes/packet:       %d",
8608           QT_UINT32 (stsd_data + offset + 28));
8609       GST_LOG_OBJECT (qtdemux, "LPCM frames/packet: %d",
8610           QT_UINT32 (stsd_data + offset + 32));
8611     } else if (version != 0x00000) {
8612       GST_WARNING_OBJECT (qtdemux, "unknown audio STSD version %08x", version);
8613     }
8614
8615     stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc,
8616         stsd_data + 32, len - 16, &codec);
8617
8618     switch (fourcc) {
8619       case FOURCC_in24:
8620       {
8621         GNode *enda;
8622         GNode *in24;
8623
8624         in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
8625
8626         enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
8627         if (!enda) {
8628           wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
8629           if (wave)
8630             enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
8631         }
8632         if (enda) {
8633           int enda_value = QT_UINT16 ((guint8 *) enda->data + 8);
8634           gst_caps_set_simple (stream->caps,
8635               "format", G_TYPE_STRING, (enda_value) ? "S24LE" : "S24BE", NULL);
8636         }
8637         break;
8638       }
8639       case FOURCC_owma:
8640       {
8641         GNode *owma;
8642         const guint8 *owma_data;
8643         const gchar *codec_name = NULL;
8644         guint owma_len;
8645         GstBuffer *buf;
8646         gint version = 1;
8647         /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8648         /* FIXME this should also be gst_riff_strf_auds,
8649          * but the latter one is actually missing bits-per-sample :( */
8650         typedef struct
8651         {
8652           gint16 wFormatTag;
8653           gint16 nChannels;
8654           gint32 nSamplesPerSec;
8655           gint32 nAvgBytesPerSec;
8656           gint16 nBlockAlign;
8657           gint16 wBitsPerSample;
8658           gint16 cbSize;
8659         } WAVEFORMATEX;
8660         WAVEFORMATEX *wfex;
8661
8662         GST_DEBUG_OBJECT (qtdemux, "parse owma");
8663         owma = qtdemux_tree_get_child_by_type (stsd, FOURCC_owma);
8664         if (!owma)
8665           break;
8666         owma_data = owma->data;
8667         owma_len = QT_UINT32 (owma_data);
8668         if (owma_len <= 54) {
8669           GST_WARNING_OBJECT (qtdemux, "Too small owma header, skipping");
8670           break;
8671         }
8672         wfex = (WAVEFORMATEX *) (owma_data + 36);
8673         buf = gst_buffer_new_and_alloc (owma_len - 54);
8674         gst_buffer_fill (buf, 0, owma_data + 54, owma_len - 54);
8675         if (wfex->wFormatTag == 0x0161) {
8676           codec_name = "Windows Media Audio";
8677           version = 2;
8678         } else if (wfex->wFormatTag == 0x0162) {
8679           codec_name = "Windows Media Audio 9 Pro";
8680           version = 3;
8681         } else if (wfex->wFormatTag == 0x0163) {
8682           codec_name = "Windows Media Audio 9 Lossless";
8683           /* is that correct? gstffmpegcodecmap.c is missing it, but
8684            * fluendo codec seems to support it */
8685           version = 4;
8686         }
8687
8688         gst_caps_set_simple (stream->caps,
8689             "codec_data", GST_TYPE_BUFFER, buf,
8690             "wmaversion", G_TYPE_INT, version,
8691             "block_align", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->nBlockAlign),
8692             "bitrate", G_TYPE_INT, GST_READ_UINT32_LE (&wfex->nAvgBytesPerSec),
8693             "width", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8694             "depth", G_TYPE_INT, GST_READ_UINT16_LE (&wfex->wBitsPerSample),
8695             NULL);
8696         gst_buffer_unref (buf);
8697
8698         if (codec_name) {
8699           g_free (codec);
8700           codec = g_strdup (codec_name);
8701         }
8702         break;
8703       }
8704       case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
8705       {
8706         gint len = QT_UINT32 (stsd_data) - offset;
8707         const guint8 *wfex_data = stsd_data + offset;
8708         const gchar *codec_name = NULL;
8709         gint version = 1;
8710         /* from http://msdn.microsoft.com/en-us/library/dd757720(VS.85).aspx */
8711         /* FIXME this should also be gst_riff_strf_auds,
8712          * but the latter one is actually missing bits-per-sample :( */
8713         typedef struct
8714         {
8715           gint16 wFormatTag;
8716           gint16 nChannels;
8717           gint32 nSamplesPerSec;
8718           gint32 nAvgBytesPerSec;
8719           gint16 nBlockAlign;
8720           gint16 wBitsPerSample;
8721           gint16 cbSize;
8722         } WAVEFORMATEX;
8723         WAVEFORMATEX wfex;
8724
8725         /* FIXME: unify with similar wavformatex parsing code above */
8726         GST_DEBUG_OBJECT (qtdemux, "parse wma, looking for wfex");
8727
8728         /* find wfex */
8729         while (len >= 8) {
8730           gint size;
8731
8732           if (QT_UINT32 (wfex_data) <= len)
8733             size = QT_UINT32 (wfex_data) - 8;
8734           else
8735             size = len - 8;
8736
8737           if (size < 1)
8738             /* No real data, so break out */
8739             break;
8740
8741           switch (QT_FOURCC (wfex_data + 4)) {
8742             case GST_MAKE_FOURCC ('w', 'f', 'e', 'x'):
8743             {
8744               GST_DEBUG_OBJECT (qtdemux, "found wfex in stsd");
8745
8746               if (size < 8 + 18)
8747                 break;
8748
8749               wfex.wFormatTag = GST_READ_UINT16_LE (wfex_data + 8 + 0);
8750               wfex.nChannels = GST_READ_UINT16_LE (wfex_data + 8 + 2);
8751               wfex.nSamplesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 4);
8752               wfex.nAvgBytesPerSec = GST_READ_UINT32_LE (wfex_data + 8 + 8);
8753               wfex.nBlockAlign = GST_READ_UINT16_LE (wfex_data + 8 + 12);
8754               wfex.wBitsPerSample = GST_READ_UINT16_LE (wfex_data + 8 + 14);
8755               wfex.cbSize = GST_READ_UINT16_LE (wfex_data + 8 + 16);
8756
8757               GST_LOG_OBJECT (qtdemux, "Found wfex box in stsd:");
8758               GST_LOG_OBJECT (qtdemux, "FormatTag = 0x%04x, Channels = %u, "
8759                   "SamplesPerSec = %u, AvgBytesPerSec = %u, BlockAlign = %u, "
8760                   "BitsPerSample = %u, Size = %u", wfex.wFormatTag,
8761                   wfex.nChannels, wfex.nSamplesPerSec, wfex.nAvgBytesPerSec,
8762                   wfex.nBlockAlign, wfex.wBitsPerSample, wfex.cbSize);
8763
8764               if (wfex.wFormatTag == 0x0161) {
8765                 codec_name = "Windows Media Audio";
8766                 version = 2;
8767               } else if (wfex.wFormatTag == 0x0162) {
8768                 codec_name = "Windows Media Audio 9 Pro";
8769                 version = 3;
8770               } else if (wfex.wFormatTag == 0x0163) {
8771                 codec_name = "Windows Media Audio 9 Lossless";
8772                 /* is that correct? gstffmpegcodecmap.c is missing it, but
8773                  * fluendo codec seems to support it */
8774                 version = 4;
8775               }
8776
8777               gst_caps_set_simple (stream->caps,
8778                   "wmaversion", G_TYPE_INT, version,
8779                   "block_align", G_TYPE_INT, wfex.nBlockAlign,
8780                   "bitrate", G_TYPE_INT, wfex.nAvgBytesPerSec,
8781                   "width", G_TYPE_INT, wfex.wBitsPerSample,
8782                   "depth", G_TYPE_INT, wfex.wBitsPerSample, NULL);
8783
8784               if (size > wfex.cbSize) {
8785                 GstBuffer *buf;
8786
8787                 buf = gst_buffer_new_and_alloc (size - wfex.cbSize);
8788                 gst_buffer_fill (buf, 0, wfex_data + 8 + wfex.cbSize,
8789                     size - wfex.cbSize);
8790                 gst_caps_set_simple (stream->caps,
8791                     "codec_data", GST_TYPE_BUFFER, buf, NULL);
8792                 gst_buffer_unref (buf);
8793               } else {
8794                 GST_WARNING_OBJECT (qtdemux, "no codec data");
8795               }
8796
8797               if (codec_name) {
8798                 g_free (codec);
8799                 codec = g_strdup (codec_name);
8800               }
8801               break;
8802             }
8803             default:
8804               break;
8805           }
8806           len -= size + 8;
8807           wfex_data += size + 8;
8808         }
8809         break;
8810       }
8811       default:
8812         break;
8813     }
8814
8815     if (codec) {
8816       GstStructure *s;
8817       gint bitrate = 0;
8818
8819       if (list == NULL)
8820         list = gst_tag_list_new_empty ();
8821       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8822           GST_TAG_AUDIO_CODEC, codec, NULL);
8823       g_free (codec);
8824       codec = NULL;
8825
8826       /* some bitrate info may have ended up in caps */
8827       s = gst_caps_get_structure (stream->caps, 0);
8828       gst_structure_get_int (s, "bitrate", &bitrate);
8829       if (bitrate > 0)
8830         gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
8831             bitrate, NULL);
8832     }
8833
8834     mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
8835     wave = NULL;
8836     esds = NULL;
8837     if (mp4a) {
8838       wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
8839       if (wave)
8840         esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
8841       if (!esds)
8842         esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
8843     }
8844
8845
8846     /* If the fourcc's bottom 16 bits gives 'sm', then the top
8847        16 bits is a byte-swapped wave-style codec identifier,
8848        and we can find a WAVE header internally to a 'wave' atom here.
8849        This can more clearly be thought of as 'ms' as the top 16 bits, and a
8850        codec id as the bottom 16 bits - but byte-swapped to store in QT (which
8851        is big-endian).
8852      */
8853     if ((fourcc & 0xffff) == (('s' << 8) | 'm')) {
8854       if (len < offset + 20) {
8855         GST_WARNING_OBJECT (qtdemux, "No wave atom in MS-style audio");
8856       } else {
8857         guint32 datalen = QT_UINT32 (stsd_data + offset + 16);
8858         const guint8 *data = stsd_data + offset + 16;
8859         GNode *wavenode;
8860         GNode *waveheadernode;
8861
8862         wavenode = g_node_new ((guint8 *) data);
8863         if (qtdemux_parse_node (qtdemux, wavenode, data, datalen)) {
8864           const guint8 *waveheader;
8865           guint32 headerlen;
8866
8867           waveheadernode = qtdemux_tree_get_child_by_type (wavenode, fourcc);
8868           if (waveheadernode) {
8869             waveheader = (const guint8 *) waveheadernode->data;
8870             headerlen = QT_UINT32 (waveheader);
8871
8872             if (headerlen > 8) {
8873               gst_riff_strf_auds *header = NULL;
8874               GstBuffer *headerbuf;
8875               GstBuffer *extra;
8876
8877               waveheader += 8;
8878               headerlen -= 8;
8879
8880               headerbuf = gst_buffer_new_and_alloc (headerlen);
8881               gst_buffer_fill (headerbuf, 0, waveheader, headerlen);
8882
8883               if (gst_riff_parse_strf_auds (GST_ELEMENT_CAST (qtdemux),
8884                       headerbuf, &header, &extra)) {
8885                 gst_caps_unref (stream->caps);
8886                 /* FIXME: Need to do something with the channel reorder map */
8887                 stream->caps = gst_riff_create_audio_caps (header->format, NULL,
8888                     header, extra, NULL, NULL, NULL);
8889
8890                 if (extra)
8891                   gst_buffer_unref (extra);
8892                 g_free (header);
8893               }
8894             }
8895           } else
8896             GST_DEBUG ("Didn't find waveheadernode for this codec");
8897         }
8898         g_node_destroy (wavenode);
8899       }
8900     } else if (esds) {
8901       gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
8902     } else {
8903       switch (fourcc) {
8904 #if 0
8905           /* FIXME: what is in the chunk? */
8906         case FOURCC_QDMC:
8907         {
8908           gint len = QT_UINT32 (stsd_data);
8909
8910           /* seems to be always = 116 = 0x74 */
8911           break;
8912         }
8913 #endif
8914         case FOURCC_QDM2:
8915         {
8916           gint len = QT_UINT32 (stsd_data);
8917
8918           if (len > 0x4C) {
8919             GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
8920
8921             gst_buffer_fill (buf, 0, stsd_data + 0x4C, len - 0x4C);
8922             gst_caps_set_simple (stream->caps,
8923                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8924             gst_buffer_unref (buf);
8925           }
8926           gst_caps_set_simple (stream->caps,
8927               "samplesize", G_TYPE_INT, samplesize, NULL);
8928           break;
8929         }
8930         case FOURCC_alac:
8931         {
8932           GNode *alac, *wave = NULL;
8933
8934           /* apparently, m4a has this atom appended directly in the stsd entry,
8935            * while mov has it in a wave atom */
8936           alac = qtdemux_tree_get_child_by_type (stsd, FOURCC_alac);
8937           if (alac) {
8938             /* alac now refers to stsd entry atom */
8939             wave = qtdemux_tree_get_child_by_type (alac, FOURCC_wave);
8940             if (wave)
8941               alac = qtdemux_tree_get_child_by_type (wave, FOURCC_alac);
8942             else
8943               alac = qtdemux_tree_get_child_by_type (alac, FOURCC_alac);
8944           }
8945           if (alac) {
8946             const guint8 *alac_data = alac->data;
8947             gint len = QT_UINT32 (alac->data);
8948             GstBuffer *buf;
8949
8950             if (len < 36) {
8951               GST_DEBUG_OBJECT (qtdemux,
8952                   "discarding alac atom with unexpected len %d", len);
8953             } else {
8954               /* codec-data contains alac atom size and prefix,
8955                * ffmpeg likes it that way, not quite gst-ish though ...*/
8956               buf = gst_buffer_new_and_alloc (len);
8957               gst_buffer_fill (buf, 0, alac->data, len);
8958               gst_caps_set_simple (stream->caps,
8959                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
8960               gst_buffer_unref (buf);
8961
8962               stream->bytes_per_frame = QT_UINT32 (alac_data + 12);
8963               stream->n_channels = QT_UINT8 (alac_data + 21);
8964               stream->rate = QT_UINT32 (alac_data + 32);
8965             }
8966           }
8967           gst_caps_set_simple (stream->caps,
8968               "samplesize", G_TYPE_INT, samplesize, NULL);
8969           break;
8970         }
8971         case FOURCC_sawb:
8972           /* Fallthrough! */
8973           amrwb = TRUE;
8974         case FOURCC_samr:
8975         {
8976           gint len = QT_UINT32 (stsd_data);
8977
8978           if (len > 0x34) {
8979             GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
8980             guint bitrate;
8981
8982             gst_buffer_fill (buf, 0, stsd_data + 0x34, len - 0x34);
8983
8984             /* If we have enough data, let's try to get the 'damr' atom. See
8985              * the 3GPP container spec (26.244) for more details. */
8986             if ((len - 0x34) > 8 &&
8987                 (bitrate = qtdemux_parse_amr_bitrate (buf, amrwb))) {
8988               if (!list)
8989                 list = gst_tag_list_new_empty ();
8990               gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
8991                   GST_TAG_MAXIMUM_BITRATE, bitrate, NULL);
8992             }
8993
8994             gst_caps_set_simple (stream->caps,
8995                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
8996             gst_buffer_unref (buf);
8997           }
8998           break;
8999         }
9000         case FOURCC_mp4a:
9001         {
9002           /* mp4a atom withtout ESDS; Attempt to build codec data from atom */
9003           gint len = QT_UINT32 (stsd_data);
9004
9005           if (len >= 50) {
9006             guint16 sound_version = QT_UINT16 (stsd_data + 32);
9007
9008             if (sound_version == 1) {
9009               guint16 channels = QT_UINT16 (stsd_data + 40);
9010               guint32 time_scale = QT_UINT32 (stsd_data + 46);
9011               guint8 codec_data[2];
9012               GstBuffer *buf;
9013               gint profile = 2; /* FIXME: Can this be determined somehow? There doesn't seem to be anything in mp4a atom that specifis compression */
9014
9015               gint sample_rate_index =
9016                   gst_codec_utils_aac_get_index_from_sample_rate (time_scale);
9017
9018               /* build AAC codec data */
9019               codec_data[0] = profile << 3;
9020               codec_data[0] |= ((sample_rate_index >> 1) & 0x7);
9021               codec_data[1] = (sample_rate_index & 0x01) << 7;
9022               codec_data[1] |= (channels & 0xF) << 3;
9023
9024               buf = gst_buffer_new_and_alloc (2);
9025               gst_buffer_fill (buf, 0, codec_data, 2);
9026               gst_caps_set_simple (stream->caps,
9027                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
9028               gst_buffer_unref (buf);
9029             }
9030           }
9031           break;
9032         }
9033         default:
9034           GST_INFO_OBJECT (qtdemux,
9035               "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9036           break;
9037       }
9038     }
9039     GST_INFO_OBJECT (qtdemux,
9040         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9041         GST_FOURCC_ARGS (fourcc), stream->caps);
9042
9043   } else if (stream->subtype == FOURCC_strm) {
9044     if (fourcc == FOURCC_rtsp) {
9045       stream->redirect_uri = qtdemux_get_rtsp_uri_from_hndl (qtdemux, minf);
9046     } else {
9047       GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
9048           GST_FOURCC_ARGS (fourcc));
9049       goto unknown_stream;
9050     }
9051     stream->sampled = TRUE;
9052   } else if (stream->subtype == FOURCC_subp || stream->subtype == FOURCC_text
9053       || stream->subtype == FOURCC_sbtl) {
9054
9055     stream->sampled = TRUE;
9056     stream->sparse = TRUE;
9057
9058     stream->caps =
9059         qtdemux_sub_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9060     if (codec) {
9061       list = gst_tag_list_new_empty ();
9062       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9063           GST_TAG_SUBTITLE_CODEC, codec, NULL);
9064       g_free (codec);
9065       codec = NULL;
9066     }
9067
9068     /* hunt for sort-of codec data */
9069     switch (fourcc) {
9070       case FOURCC_mp4s:
9071       {
9072         GNode *mp4s = NULL;
9073         GNode *esds = NULL;
9074
9075         /* look for palette in a stsd->mp4s->esds sub-atom */
9076         mp4s = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4s);
9077         if (mp4s)
9078           esds = qtdemux_tree_get_child_by_type (mp4s, FOURCC_esds);
9079         if (esds == NULL) {
9080           /* Invalid STSD */
9081           GST_LOG_OBJECT (qtdemux, "Skipping invalid stsd: no esds child");
9082           break;
9083         }
9084
9085         gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
9086         break;
9087       }
9088       default:
9089         GST_INFO_OBJECT (qtdemux,
9090             "unhandled type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
9091         break;
9092     }
9093     GST_INFO_OBJECT (qtdemux,
9094         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
9095         GST_FOURCC_ARGS (fourcc), stream->caps);
9096   } else {
9097     /* everything in 1 sample */
9098     stream->sampled = TRUE;
9099
9100     stream->caps =
9101         qtdemux_generic_caps (qtdemux, stream, fourcc, stsd_data, &codec);
9102
9103     if (stream->caps == NULL)
9104       goto unknown_stream;
9105
9106     if (codec) {
9107       list = gst_tag_list_new_empty ();
9108       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9109           GST_TAG_SUBTITLE_CODEC, codec, NULL);
9110       g_free (codec);
9111       codec = NULL;
9112     }
9113   }
9114
9115   /* promote to sampled format */
9116   if (stream->fourcc == FOURCC_samr) {
9117     /* force mono 8000 Hz for AMR */
9118     stream->sampled = TRUE;
9119     stream->n_channels = 1;
9120     stream->rate = 8000;
9121   } else if (stream->fourcc == FOURCC_sawb) {
9122     /* force mono 16000 Hz for AMR-WB */
9123     stream->sampled = TRUE;
9124     stream->n_channels = 1;
9125     stream->rate = 16000;
9126   } else if (stream->fourcc == FOURCC_mp4a) {
9127     stream->sampled = TRUE;
9128   }
9129
9130   /* collect sample information */
9131   if (!qtdemux_stbl_init (qtdemux, stream, stbl))
9132     goto samples_failed;
9133
9134   if (qtdemux->fragmented) {
9135     guint32 dummy;
9136     guint64 offset;
9137
9138     /* need all moov samples as basis; probably not many if any at all */
9139     /* prevent moof parsing taking of at this time */
9140     offset = qtdemux->moof_offset;
9141     qtdemux->moof_offset = 0;
9142     if (stream->n_samples &&
9143         !qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) {
9144       qtdemux->moof_offset = offset;
9145       goto samples_failed;
9146     }
9147     qtdemux->moof_offset = 0;
9148     /* movie duration more reliable in this case (e.g. mehd) */
9149     if (qtdemux->segment.duration &&
9150         GST_CLOCK_TIME_IS_VALID (qtdemux->segment.duration))
9151       stream->duration =
9152           GSTTIME_TO_QTSTREAMTIME (stream, qtdemux->segment.duration);
9153     /* need defaults for fragments */
9154     qtdemux_parse_trex (qtdemux, stream, &dummy, &dummy, &dummy);
9155   }
9156
9157   /* configure segments */
9158   if (!qtdemux_parse_segments (qtdemux, stream, trak))
9159     goto segments_failed;
9160
9161   /* add some language tag, if useful */
9162   if (stream->lang_id[0] != '\0' && strcmp (stream->lang_id, "unk") &&
9163       strcmp (stream->lang_id, "und")) {
9164     const gchar *lang_code;
9165
9166     if (!list)
9167       list = gst_tag_list_new_empty ();
9168
9169     /* convert ISO 639-2 code to ISO 639-1 */
9170     lang_code = gst_tag_get_language_code (stream->lang_id);
9171     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
9172         GST_TAG_LANGUAGE_CODE, (lang_code) ? lang_code : stream->lang_id, NULL);
9173   }
9174
9175   /* now we are ready to add the stream */
9176   if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
9177     goto too_many_streams;
9178
9179   if (!qtdemux->got_moov) {
9180     stream->pending_tags = list;
9181     qtdemux->streams[qtdemux->n_streams] = stream;
9182     qtdemux->n_streams++;
9183     GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
9184   }
9185
9186   return TRUE;
9187
9188 /* ERRORS */
9189 skip_track:
9190   {
9191     GST_INFO_OBJECT (qtdemux, "skip disabled track");
9192     if (new_stream)
9193       g_free (stream);
9194     return TRUE;
9195   }
9196 corrupt_file:
9197   {
9198     GST_ELEMENT_ERROR (qtdemux, STREAM, DEMUX,
9199         (_("This file is corrupt and cannot be played.")), (NULL));
9200     if (new_stream)
9201       g_free (stream);
9202     return FALSE;
9203   }
9204 error_encrypted:
9205   {
9206     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
9207     if (new_stream)
9208       g_free (stream);
9209     return FALSE;
9210   }
9211 samples_failed:
9212 segments_failed:
9213   {
9214     /* we posted an error already */
9215     /* free stbl sub-atoms */
9216     gst_qtdemux_stbl_free (stream);
9217     if (new_stream)
9218       g_free (stream);
9219     return FALSE;
9220   }
9221 existing_stream:
9222   {
9223     GST_INFO_OBJECT (qtdemux, "stream with track id %i already exists",
9224         track_id);
9225     if (new_stream)
9226       g_free (stream);
9227     return TRUE;
9228   }
9229 unknown_stream:
9230   {
9231     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
9232         GST_FOURCC_ARGS (stream->subtype));
9233     if (new_stream)
9234       g_free (stream);
9235     return TRUE;
9236   }
9237 too_many_streams:
9238   {
9239     GST_ELEMENT_WARNING (qtdemux, STREAM, DEMUX,
9240         (_("This file contains too many streams. Only playing first %d"),
9241             GST_QTDEMUX_MAX_STREAMS), (NULL));
9242     return TRUE;
9243   }
9244 }
9245
9246 /* If we can estimate the overall bitrate, and don't have information about the
9247  * stream bitrate for exactly one stream, this guesses the stream bitrate as
9248  * the overall bitrate minus the sum of the bitrates of all other streams. This
9249  * should be useful for the common case where we have one audio and one video
9250  * stream and can estimate the bitrate of one, but not the other. */
9251 static void
9252 gst_qtdemux_guess_bitrate (GstQTDemux * qtdemux)
9253 {
9254   QtDemuxStream *stream = NULL;
9255   gint64 size, sys_bitrate, sum_bitrate = 0;
9256   GstClockTime duration;
9257   gint i;
9258   guint bitrate;
9259
9260   if (qtdemux->fragmented)
9261     return;
9262
9263   GST_DEBUG_OBJECT (qtdemux, "Looking for streams with unknown bitrate");
9264
9265   if (!gst_pad_peer_query_duration (qtdemux->sinkpad, GST_FORMAT_BYTES, &size)
9266       || size <= 0) {
9267     GST_DEBUG_OBJECT (qtdemux,
9268         "Size in bytes of the stream not known - bailing");
9269     return;
9270   }
9271
9272   /* Subtract the header size */
9273   GST_DEBUG_OBJECT (qtdemux, "Total size %" G_GINT64_FORMAT ", header size %u",
9274       size, qtdemux->header_size);
9275
9276   if (size < qtdemux->header_size)
9277     return;
9278
9279   size = size - qtdemux->header_size;
9280
9281   if (!gst_qtdemux_get_duration (qtdemux, &duration) ||
9282       duration == GST_CLOCK_TIME_NONE) {
9283     GST_DEBUG_OBJECT (qtdemux, "Stream duration not known - bailing");
9284     return;
9285   }
9286
9287   for (i = 0; i < qtdemux->n_streams; i++) {
9288     switch (qtdemux->streams[i]->subtype) {
9289       case FOURCC_soun:
9290       case FOURCC_vide:
9291         GST_DEBUG_OBJECT (qtdemux, "checking bitrate for %" GST_PTR_FORMAT,
9292             qtdemux->streams[i]->caps);
9293         /* retrieve bitrate, prefer avg then max */
9294         bitrate = 0;
9295         if (qtdemux->streams[i]->pending_tags) {
9296           gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9297               GST_TAG_MAXIMUM_BITRATE, &bitrate);
9298           GST_DEBUG_OBJECT (qtdemux, "max-bitrate: %u", bitrate);
9299           gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9300               GST_TAG_NOMINAL_BITRATE, &bitrate);
9301           GST_DEBUG_OBJECT (qtdemux, "nominal-bitrate: %u", bitrate);
9302           gst_tag_list_get_uint (qtdemux->streams[i]->pending_tags,
9303               GST_TAG_BITRATE, &bitrate);
9304           GST_DEBUG_OBJECT (qtdemux, "bitrate: %u", bitrate);
9305         }
9306         if (bitrate)
9307           sum_bitrate += bitrate;
9308         else {
9309           if (stream) {
9310             GST_DEBUG_OBJECT (qtdemux,
9311                 ">1 stream with unknown bitrate - bailing");
9312             return;
9313           } else
9314             stream = qtdemux->streams[i];
9315         }
9316
9317       default:
9318         /* For other subtypes, we assume no significant impact on bitrate */
9319         break;
9320     }
9321   }
9322
9323   if (!stream) {
9324     GST_DEBUG_OBJECT (qtdemux, "All stream bitrates are known");
9325     return;
9326   }
9327
9328   sys_bitrate = gst_util_uint64_scale (size, GST_SECOND * 8, duration);
9329
9330   if (sys_bitrate < sum_bitrate) {
9331     /* This can happen, since sum_bitrate might be derived from maximum
9332      * bitrates and not average bitrates */
9333     GST_DEBUG_OBJECT (qtdemux,
9334         "System bitrate less than sum bitrate - bailing");
9335     return;
9336   }
9337
9338   bitrate = sys_bitrate - sum_bitrate;
9339   GST_DEBUG_OBJECT (qtdemux, "System bitrate = %" G_GINT64_FORMAT
9340       ", Stream bitrate = %u", sys_bitrate, bitrate);
9341
9342   if (!stream->pending_tags)
9343     stream->pending_tags = gst_tag_list_new_empty ();
9344
9345   gst_tag_list_add (stream->pending_tags, GST_TAG_MERGE_REPLACE,
9346       GST_TAG_BITRATE, bitrate, NULL);
9347 }
9348
9349 static GstFlowReturn
9350 qtdemux_prepare_streams (GstQTDemux * qtdemux)
9351 {
9352   gint i;
9353   GstFlowReturn ret = GST_FLOW_OK;
9354
9355   GST_DEBUG_OBJECT (qtdemux, "prepare streams");
9356
9357   for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9358     QtDemuxStream *stream = qtdemux->streams[i];
9359     guint32 sample_num = 0;
9360
9361     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9362         i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9363
9364     if (qtdemux->fragmented) {
9365       /* need all moov samples first */
9366       GST_OBJECT_LOCK (qtdemux);
9367       while (stream->n_samples == 0)
9368         if ((ret = qtdemux_add_fragmented_samples (qtdemux)) != GST_FLOW_OK)
9369           break;
9370       GST_OBJECT_UNLOCK (qtdemux);
9371     } else {
9372       /* discard any stray moof */
9373       qtdemux->moof_offset = 0;
9374     }
9375
9376     /* prepare braking */
9377     if (ret != GST_FLOW_ERROR)
9378       ret = GST_FLOW_OK;
9379
9380     /* in pull mode, we should have parsed some sample info by now;
9381      * and quite some code will not handle no samples.
9382      * in push mode, we'll just have to deal with it */
9383     if (G_UNLIKELY (qtdemux->pullbased && !stream->n_samples)) {
9384       GST_DEBUG_OBJECT (qtdemux, "no samples for stream; discarding");
9385       gst_qtdemux_remove_stream (qtdemux, i);
9386       i--;
9387       continue;
9388     }
9389
9390     /* parse the initial sample for use in setting the frame rate cap */
9391     while (sample_num == 0 && sample_num < stream->n_samples) {
9392       if (!qtdemux_parse_samples (qtdemux, stream, sample_num))
9393         break;
9394       ++sample_num;
9395     }
9396     if (stream->n_samples > 0 && stream->stbl_index > 0) {
9397       stream->first_duration = stream->samples[0].duration;
9398       GST_LOG_OBJECT (qtdemux, "stream %d first duration %u",
9399           stream->track_id, stream->first_duration);
9400     }
9401   }
9402
9403   return ret;
9404 }
9405
9406 static GstFlowReturn
9407 qtdemux_expose_streams (GstQTDemux * qtdemux)
9408 {
9409   gint i;
9410   GstFlowReturn ret = GST_FLOW_OK;
9411   GSList *oldpads = NULL;
9412   GSList *iter;
9413
9414   GST_DEBUG_OBJECT (qtdemux, "exposing streams");
9415
9416   for (i = 0; ret == GST_FLOW_OK && i < qtdemux->n_streams; i++) {
9417     QtDemuxStream *stream = qtdemux->streams[i];
9418     GstPad *oldpad = stream->pad;
9419     GstTagList *list;
9420
9421     GST_DEBUG_OBJECT (qtdemux, "stream %d, id %d, fourcc %" GST_FOURCC_FORMAT,
9422         i, stream->track_id, GST_FOURCC_ARGS (stream->fourcc));
9423
9424     if ((stream->subtype == FOURCC_text || stream->subtype == FOURCC_sbtl) &&
9425         stream->track_id == qtdemux->chapters_track_id) {
9426       /* TODO - parse chapters track and expose it as GstToc; For now just ignore it
9427          so that it doesn't look like a subtitle track */
9428       gst_qtdemux_remove_stream (qtdemux, i);
9429       i--;
9430       continue;
9431     }
9432
9433     /* now we have all info and can expose */
9434     list = stream->pending_tags;
9435     stream->pending_tags = NULL;
9436     if (oldpad)
9437       oldpads = g_slist_prepend (oldpads, oldpad);
9438     gst_qtdemux_add_stream (qtdemux, stream, list);
9439   }
9440
9441   gst_qtdemux_guess_bitrate (qtdemux);
9442
9443   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
9444
9445   for (iter = oldpads; iter; iter = g_slist_next (iter)) {
9446     GstPad *oldpad = iter->data;
9447
9448     gst_pad_push_event (oldpad, gst_event_new_eos ());
9449     gst_pad_set_active (oldpad, FALSE);
9450     gst_element_remove_pad (GST_ELEMENT (qtdemux), oldpad);
9451     gst_flow_combiner_remove_pad (qtdemux->flowcombiner, oldpad);
9452     gst_object_unref (oldpad);
9453   }
9454
9455   /* check if we should post a redirect in case there is a single trak
9456    * and it is a redirecting trak */
9457   if (qtdemux->n_streams == 1 && qtdemux->streams[0]->redirect_uri != NULL) {
9458     GstMessage *m;
9459
9460     GST_INFO_OBJECT (qtdemux, "Issuing a redirect due to a single track with "
9461         "an external content");
9462     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
9463         gst_structure_new ("redirect",
9464             "new-location", G_TYPE_STRING, qtdemux->streams[0]->redirect_uri,
9465             NULL));
9466     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
9467     qtdemux->posted_redirect = TRUE;
9468   }
9469
9470   for (i = 0; i < qtdemux->n_streams; i++) {
9471     QtDemuxStream *stream = qtdemux->streams[i];
9472
9473     qtdemux_do_allocation (qtdemux, stream);
9474   }
9475
9476   qtdemux->exposed = TRUE;
9477   return ret;
9478 }
9479
9480 /* check if major or compatible brand is 3GP */
9481 static inline gboolean
9482 qtdemux_is_brand_3gp (GstQTDemux * qtdemux, gboolean major)
9483 {
9484   if (major) {
9485     return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9486         GST_MAKE_FOURCC ('3', 'g', 0, 0));
9487   } else if (qtdemux->comp_brands != NULL) {
9488     GstMapInfo map;
9489     guint8 *data;
9490     gsize size;
9491     gboolean res = FALSE;
9492
9493     gst_buffer_map (qtdemux->comp_brands, &map, GST_MAP_READ);
9494     data = map.data;
9495     size = map.size;
9496     while (size >= 4) {
9497       res = res || ((QT_FOURCC (data) & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
9498           GST_MAKE_FOURCC ('3', 'g', 0, 0));
9499       data += 4;
9500       size -= 4;
9501     }
9502     gst_buffer_unmap (qtdemux->comp_brands, &map);
9503     return res;
9504   } else {
9505     return FALSE;
9506   }
9507 }
9508
9509 /* check if tag is a spec'ed 3GP tag keyword storing a string */
9510 static inline gboolean
9511 qtdemux_is_string_tag_3gp (GstQTDemux * qtdemux, guint32 fourcc)
9512 {
9513   return fourcc == FOURCC_cprt || fourcc == FOURCC_gnre || fourcc == FOURCC_titl
9514       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
9515       || fourcc == FOURCC_albm;
9516 }
9517
9518 static void
9519 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
9520     const char *dummy, GNode * node)
9521 {
9522   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9523   int offset;
9524   char *name;
9525   gchar *data;
9526   gdouble longitude, latitude, altitude;
9527   gint len;
9528
9529   len = QT_UINT32 (node->data);
9530   if (len <= 14)
9531     goto short_read;
9532
9533   data = node->data;
9534   offset = 14;
9535
9536   /* TODO: language code skipped */
9537
9538   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
9539
9540   if (!name) {
9541     /* do not alarm in trivial case, but bail out otherwise */
9542     if (*(data + offset) != 0) {
9543       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
9544           "giving up", tag);
9545     }
9546   } else {
9547     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9548         GST_TAG_GEO_LOCATION_NAME, name, NULL);
9549     offset += strlen (name);
9550     g_free (name);
9551   }
9552
9553   if (len < offset + 2 + 4 + 4 + 4)
9554     goto short_read;
9555
9556   /* +1 +1 = skip null-terminator and location role byte */
9557   offset += 1 + 1;
9558   /* table in spec says unsigned, semantics say negative has meaning ... */
9559   longitude = QT_SFP32 (data + offset);
9560
9561   offset += 4;
9562   latitude = QT_SFP32 (data + offset);
9563
9564   offset += 4;
9565   altitude = QT_SFP32 (data + offset);
9566
9567   /* one invalid means all are invalid */
9568   if (longitude >= -180.0 && longitude <= 180.0 &&
9569       latitude >= -90.0 && latitude <= 90.0) {
9570     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9571         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
9572         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
9573         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
9574   }
9575
9576   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
9577
9578   return;
9579
9580   /* ERRORS */
9581 short_read:
9582   {
9583     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP location");
9584     return;
9585   }
9586 }
9587
9588
9589 static void
9590 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9591     GNode * node)
9592 {
9593   guint16 y;
9594   GDate *date;
9595   gint len;
9596
9597   len = QT_UINT32 (node->data);
9598   if (len < 14)
9599     return;
9600
9601   y = QT_UINT16 ((guint8 *) node->data + 12);
9602   if (y == 0) {
9603     GST_DEBUG_OBJECT (qtdemux, "year: %u is not a valid year", y);
9604     return;
9605   }
9606   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
9607
9608   date = g_date_new_dmy (1, 1, y);
9609   gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
9610   g_date_free (date);
9611 }
9612
9613 static void
9614 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
9615     const char *dummy, GNode * node)
9616 {
9617   int offset;
9618   char *tag_str = NULL;
9619   guint8 *entity;
9620   guint16 table;
9621   gint len;
9622
9623   len = QT_UINT32 (node->data);
9624   if (len <= 20)
9625     goto short_read;
9626
9627   offset = 12;
9628   entity = (guint8 *) node->data + offset;
9629   if (entity[0] == 0 || entity[1] == 0 || entity[2] == 0 || entity[3] == 0) {
9630     GST_DEBUG_OBJECT (qtdemux,
9631         "classification info: %c%c%c%c invalid classification entity",
9632         entity[0], entity[1], entity[2], entity[3]);
9633     return;
9634   }
9635
9636   offset += 4;
9637   table = QT_UINT16 ((guint8 *) node->data + offset);
9638
9639   /* Language code skipped */
9640
9641   offset += 4;
9642
9643   /* Tag format: "XXXX://Y[YYYY]/classification info string"
9644    * XXXX: classification entity, fixed length 4 chars.
9645    * Y[YYYY]: classification table, max 5 chars.
9646    */
9647   tag_str = g_strdup_printf ("----://%u/%s",
9648       table, (char *) node->data + offset);
9649
9650   /* memcpy To be sure we're preserving byte order */
9651   memcpy (tag_str, entity, 4);
9652   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
9653
9654   gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
9655       tag_str, NULL);
9656
9657   g_free (tag_str);
9658
9659   return;
9660
9661   /* ERRORS */
9662 short_read:
9663   {
9664     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP classification");
9665     return;
9666   }
9667 }
9668
9669 static gboolean
9670 qtdemux_tag_add_str_full (GstQTDemux * qtdemux, const char *tag,
9671     const char *dummy, GNode * node)
9672 {
9673   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9674   GNode *data;
9675   char *s;
9676   int len;
9677   guint32 type;
9678   int offset;
9679   gboolean ret = TRUE;
9680   const gchar *charset = NULL;
9681
9682   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9683   if (data) {
9684     len = QT_UINT32 (data->data);
9685     type = QT_UINT32 ((guint8 *) data->data + 8);
9686     if (type == 0x00000001 && len > 16) {
9687       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
9688           env_vars);
9689       if (s) {
9690         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9691         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
9692             NULL);
9693         g_free (s);
9694       } else {
9695         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9696       }
9697     }
9698   } else {
9699     len = QT_UINT32 (node->data);
9700     type = QT_UINT32 ((guint8 *) node->data + 4);
9701     if ((type >> 24) == 0xa9) {
9702       gint str_len;
9703       gint lang_code;
9704
9705       /* Type starts with the (C) symbol, so the next data is a list
9706        * of (string size(16), language code(16), string) */
9707
9708       str_len = QT_UINT16 ((guint8 *) node->data + 8);
9709       lang_code = QT_UINT16 ((guint8 *) node->data + 10);
9710
9711       /* the string + fourcc + size + 2 16bit fields,
9712        * means that there are more tags in this atom */
9713       if (len > str_len + 8 + 4) {
9714         /* TODO how to represent the same tag in different languages? */
9715         GST_WARNING_OBJECT (qtdemux, "Ignoring metadata entry with multiple "
9716             "text alternatives, reading only first one");
9717       }
9718
9719       offset = 12;
9720       len = str_len + 8 + 4;    /* remove trailing strings that we don't use */
9721       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
9722
9723       if (lang_code < 0x800) {  /* MAC encoded string */
9724         charset = "mac";
9725       }
9726     } else if (len > 14 && qtdemux_is_string_tag_3gp (qtdemux,
9727             QT_FOURCC ((guint8 *) node->data + 4))) {
9728       guint32 type = QT_UINT32 ((guint8 *) node->data + 8);
9729
9730       /* we go for 3GP style encoding if major brands claims so,
9731        * or if no hope for data be ok UTF-8, and compatible 3GP brand present */
9732       if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
9733           (qtdemux_is_brand_3gp (qtdemux, FALSE) &&
9734               ((type & 0x00FFFFFF) == 0x0) && (type >> 24 <= 0xF))) {
9735         offset = 14;
9736         /* 16-bit Language code is ignored here as well */
9737         GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
9738       } else {
9739         goto normal;
9740       }
9741     } else {
9742     normal:
9743       offset = 8;
9744       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
9745       ret = FALSE;              /* may have to fallback */
9746     }
9747     if (charset) {
9748       GError *err = NULL;
9749
9750       s = g_convert ((gchar *) node->data + offset, len - offset, "utf8",
9751           charset, NULL, NULL, &err);
9752       if (err) {
9753         GST_DEBUG_OBJECT (qtdemux, "Failed to convert string from charset %s:"
9754             " %s(%d): %s", charset, g_quark_to_string (err->domain), err->code,
9755             err->message);
9756         g_error_free (err);
9757       }
9758     } else {
9759       s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9760           len - offset, env_vars);
9761     }
9762     if (s) {
9763       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
9764       gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
9765       g_free (s);
9766       ret = TRUE;
9767     } else {
9768       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
9769     }
9770   }
9771   return ret;
9772 }
9773
9774 static void
9775 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag,
9776     const char *dummy, GNode * node)
9777 {
9778   qtdemux_tag_add_str_full (qtdemux, tag, dummy, node);
9779 }
9780
9781 static void
9782 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
9783     const char *dummy, GNode * node)
9784 {
9785   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
9786   guint8 *data;
9787   char *s, *t, *k = NULL;
9788   int len;
9789   int offset;
9790   int count;
9791
9792   /* first try normal string tag if major brand not 3GP */
9793   if (!qtdemux_is_brand_3gp (qtdemux, TRUE)) {
9794     if (!qtdemux_tag_add_str_full (qtdemux, tag, dummy, node)) {
9795       /* hm, that did not work, maybe 3gpp storage in non-3gpp major brand;
9796        * let's try it 3gpp way after minor safety check */
9797       data = node->data;
9798       if (QT_UINT32 (data) < 15 || !qtdemux_is_brand_3gp (qtdemux, FALSE))
9799         return;
9800     } else
9801       return;
9802   }
9803
9804   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
9805
9806   data = node->data;
9807
9808   len = QT_UINT32 (data);
9809   if (len < 15)
9810     goto short_read;
9811
9812   count = QT_UINT8 (data + 14);
9813   offset = 15;
9814   for (; count; count--) {
9815     gint slen;
9816
9817     if (offset + 1 > len)
9818       goto short_read;
9819     slen = QT_UINT8 (data + offset);
9820     offset += 1;
9821     if (offset + slen > len)
9822       goto short_read;
9823     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
9824         slen, env_vars);
9825     if (s) {
9826       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
9827       if (k) {
9828         t = g_strjoin (",", k, s, NULL);
9829         g_free (s);
9830         g_free (k);
9831         k = t;
9832       } else {
9833         k = s;
9834       }
9835     } else {
9836       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
9837     }
9838     offset += slen;
9839   }
9840
9841 done:
9842   if (k) {
9843     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
9844     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
9845   }
9846   g_free (k);
9847
9848   return;
9849
9850   /* ERRORS */
9851 short_read:
9852   {
9853     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
9854     goto done;
9855   }
9856 }
9857
9858 static void
9859 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
9860     const char *tag2, GNode * node)
9861 {
9862   GNode *data;
9863   int len;
9864   int type;
9865   int n1, n2;
9866
9867   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9868   if (data) {
9869     len = QT_UINT32 (data->data);
9870     type = QT_UINT32 ((guint8 *) data->data + 8);
9871     if (type == 0x00000000 && len >= 22) {
9872       n1 = QT_UINT16 ((guint8 *) data->data + 18);
9873       n2 = QT_UINT16 ((guint8 *) data->data + 20);
9874       if (n1 > 0) {
9875         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
9876         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9877             tag1, n1, NULL);
9878       }
9879       if (n2 > 0) {
9880         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
9881         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9882             tag2, n2, NULL);
9883       }
9884     }
9885   }
9886 }
9887
9888 static void
9889 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9890     GNode * node)
9891 {
9892   GNode *data;
9893   int len;
9894   int type;
9895   int n1;
9896
9897   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9898   if (data) {
9899     len = QT_UINT32 (data->data);
9900     type = QT_UINT32 ((guint8 *) data->data + 8);
9901     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
9902     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9903     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
9904       n1 = QT_UINT16 ((guint8 *) data->data + 16);
9905       if (n1) {
9906         /* do not add bpm=0 */
9907         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
9908         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9909             tag1, (gdouble) n1, NULL);
9910       }
9911     }
9912   }
9913 }
9914
9915 static void
9916 qtdemux_tag_add_uint32 (GstQTDemux * qtdemux, const char *tag1,
9917     const char *dummy, GNode * node)
9918 {
9919   GNode *data;
9920   int len;
9921   int type;
9922   guint32 num;
9923
9924   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9925   if (data) {
9926     len = QT_UINT32 (data->data);
9927     type = QT_UINT32 ((guint8 *) data->data + 8);
9928     GST_DEBUG_OBJECT (qtdemux, "have %s tag, type=%d,len=%d", tag1, type, len);
9929     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
9930     if ((type == 0x00000015 || type == 0x0000000f) && len >= 20) {
9931       num = QT_UINT32 ((guint8 *) data->data + 16);
9932       if (num) {
9933         /* do not add num=0 */
9934         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", num);
9935         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9936             tag1, num, NULL);
9937       }
9938     }
9939   }
9940 }
9941
9942 static void
9943 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
9944     GNode * node)
9945 {
9946   GNode *data;
9947   int len;
9948   int type;
9949   GstSample *sample;
9950
9951   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9952   if (data) {
9953     len = QT_UINT32 (data->data);
9954     type = QT_UINT32 ((guint8 *) data->data + 8);
9955     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
9956     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
9957       if ((sample =
9958               gst_tag_image_data_to_image_sample ((guint8 *) data->data + 16,
9959                   len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
9960         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
9961         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
9962             tag1, sample, NULL);
9963         gst_sample_unref (sample);
9964       }
9965     }
9966   }
9967 }
9968
9969 static void
9970 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
9971     GNode * node)
9972 {
9973   GNode *data;
9974   char *s;
9975   int len;
9976   int type;
9977
9978   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
9979   if (data) {
9980     len = QT_UINT32 (data->data);
9981     type = QT_UINT32 ((guint8 *) data->data + 8);
9982     if (type == 0x00000001 && len > 16) {
9983       guint y, m = 1, d = 1;
9984       gint ret;
9985
9986       s = g_strndup ((char *) data->data + 16, len - 16);
9987       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
9988       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
9989       if (ret >= 1 && y > 1500 && y < 3000) {
9990         GDate *date;
9991
9992         date = g_date_new_dmy (d, m, y);
9993         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
9994             date, NULL);
9995         g_date_free (date);
9996       } else {
9997         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
9998       }
9999       g_free (s);
10000     }
10001   }
10002 }
10003
10004 static void
10005 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
10006     GNode * node)
10007 {
10008   GNode *data;
10009
10010   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10011
10012   /* re-route to normal string tag if major brand says so
10013    * or no data atom and compatible brand suggests so */
10014   if (qtdemux_is_brand_3gp (qtdemux, TRUE) ||
10015       (qtdemux_is_brand_3gp (qtdemux, FALSE) && !data)) {
10016     qtdemux_tag_add_str (qtdemux, tag, dummy, node);
10017     return;
10018   }
10019
10020   if (data) {
10021     guint len, type, n;
10022
10023     len = QT_UINT32 (data->data);
10024     type = QT_UINT32 ((guint8 *) data->data + 8);
10025     if (type == 0x00000000 && len >= 18) {
10026       n = QT_UINT16 ((guint8 *) data->data + 16);
10027       if (n > 0) {
10028         const gchar *genre;
10029
10030         genre = gst_tag_id3_genre_get (n - 1);
10031         if (genre != NULL) {
10032           GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genre);
10033           gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
10034               tag, genre, NULL);
10035         }
10036       }
10037     }
10038   }
10039 }
10040
10041 static void
10042 qtdemux_add_double_tag_from_str (GstQTDemux * demux, const gchar * tag,
10043     guint8 * data, guint32 datasize)
10044 {
10045   gdouble value;
10046   gchar *datacopy;
10047
10048   /* make a copy to have \0 at the end */
10049   datacopy = g_strndup ((gchar *) data, datasize);
10050
10051   /* convert the str to double */
10052   if (sscanf (datacopy, "%lf", &value) == 1) {
10053     GST_DEBUG_OBJECT (demux, "adding tag: %s [%s]", tag, datacopy);
10054     gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_REPLACE, tag, value, NULL);
10055   } else {
10056     GST_WARNING_OBJECT (demux, "Failed to parse double from string: %s",
10057         datacopy);
10058   }
10059   g_free (datacopy);
10060 }
10061
10062
10063 static void
10064 qtdemux_tag_add_revdns (GstQTDemux * demux, const char *tag,
10065     const char *tag_bis, GNode * node)
10066 {
10067   GNode *mean;
10068   GNode *name;
10069   GNode *data;
10070   guint32 meansize;
10071   guint32 namesize;
10072   guint32 datatype;
10073   guint32 datasize;
10074   const gchar *meanstr;
10075   const gchar *namestr;
10076
10077   /* checking the whole ---- atom size for consistency */
10078   if (QT_UINT32 (node->data) <= 4 + 12 + 12 + 16) {
10079     GST_WARNING_OBJECT (demux, "Tag ---- atom is too small, ignoring");
10080     return;
10081   }
10082
10083   mean = qtdemux_tree_get_child_by_type (node, FOURCC_mean);
10084   if (!mean) {
10085     GST_WARNING_OBJECT (demux, "No 'mean' atom found");
10086     return;
10087   }
10088
10089   meansize = QT_UINT32 (mean->data);
10090   if (meansize <= 12) {
10091     GST_WARNING_OBJECT (demux, "Small mean atom, ignoring the whole tag");
10092     return;
10093   }
10094   meanstr = ((gchar *) mean->data) + 12;
10095   meansize -= 12;
10096
10097   name = qtdemux_tree_get_child_by_type (node, FOURCC_name);
10098   if (!name) {
10099     GST_WARNING_OBJECT (demux, "'name' atom not found, ignoring tag");
10100     return;
10101   }
10102
10103   namesize = QT_UINT32 (name->data);
10104   if (namesize <= 12) {
10105     GST_WARNING_OBJECT (demux, "'name' atom is too small, ignoring tag");
10106     return;
10107   }
10108   namestr = ((gchar *) name->data) + 12;
10109   namesize -= 12;
10110
10111   /*
10112    * Data atom is:
10113    * uint32 - size
10114    * uint32 - name
10115    * uint8  - version
10116    * uint24 - data type
10117    * uint32 - all 0
10118    * rest   - the data
10119    */
10120   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
10121   if (!data) {
10122     GST_WARNING_OBJECT (demux, "No data atom in this tag");
10123     return;
10124   }
10125   datasize = QT_UINT32 (data->data);
10126   if (datasize <= 16) {
10127     GST_WARNING_OBJECT (demux, "Data atom too small");
10128     return;
10129   }
10130   datatype = QT_UINT32 (((gchar *) data->data) + 8) & 0xFFFFFF;
10131
10132   if ((strncmp (meanstr, "com.apple.iTunes", meansize) == 0) ||
10133       (strncmp (meanstr, "org.hydrogenaudio.replaygain", meansize) == 0)) {
10134     static const struct
10135     {
10136       const gchar name[28];
10137       const gchar tag[28];
10138     } tags[] = {
10139       {
10140       "replaygain_track_gain", GST_TAG_TRACK_GAIN}, {
10141       "replaygain_track_peak", GST_TAG_TRACK_PEAK}, {
10142       "replaygain_album_gain", GST_TAG_ALBUM_GAIN}, {
10143       "replaygain_album_peak", GST_TAG_ALBUM_PEAK}, {
10144       "MusicBrainz Track Id", GST_TAG_MUSICBRAINZ_TRACKID}, {
10145       "MusicBrainz Artist Id", GST_TAG_MUSICBRAINZ_ARTISTID}, {
10146       "MusicBrainz Album Id", GST_TAG_MUSICBRAINZ_ALBUMID}, {
10147       "MusicBrainz Album Artist Id", GST_TAG_MUSICBRAINZ_ALBUMARTISTID}
10148     };
10149     int i;
10150
10151     for (i = 0; i < G_N_ELEMENTS (tags); ++i) {
10152       if (!g_ascii_strncasecmp (tags[i].name, namestr, namesize)) {
10153         switch (gst_tag_get_type (tags[i].tag)) {
10154           case G_TYPE_DOUBLE:
10155             qtdemux_add_double_tag_from_str (demux, tags[i].tag,
10156                 ((guint8 *) data->data) + 16, datasize - 16);
10157             break;
10158           case G_TYPE_STRING:
10159             qtdemux_tag_add_str (demux, tags[i].tag, NULL, node);
10160             break;
10161           default:
10162             /* not reached */
10163             break;
10164         }
10165         break;
10166       }
10167     }
10168     if (i == G_N_ELEMENTS (tags))
10169       goto unknown_tag;
10170   } else {
10171     goto unknown_tag;
10172   }
10173
10174   return;
10175
10176 /* errors */
10177 unknown_tag:
10178 #ifndef GST_DISABLE_GST_DEBUG
10179   {
10180     gchar *namestr_dbg;
10181     gchar *meanstr_dbg;
10182
10183     meanstr_dbg = g_strndup (meanstr, meansize);
10184     namestr_dbg = g_strndup (namestr, namesize);
10185
10186     GST_WARNING_OBJECT (demux, "This tag %s:%s type:%u is not mapped, "
10187         "file a bug at bugzilla.gnome.org", meanstr_dbg, namestr_dbg, datatype);
10188
10189     g_free (namestr_dbg);
10190     g_free (meanstr_dbg);
10191   }
10192 #endif
10193   return;
10194 }
10195
10196 static void
10197 qtdemux_tag_add_id32 (GstQTDemux * demux, const char *tag,
10198     const char *tag_bis, GNode * node)
10199 {
10200   guint8 *data;
10201   GstBuffer *buf;
10202   guint len;
10203   GstTagList *taglist = NULL;
10204
10205   GST_LOG_OBJECT (demux, "parsing ID32");
10206
10207   data = node->data;
10208   len = GST_READ_UINT32_BE (data);
10209
10210   /* need at least full box and language tag */
10211   if (len < 12 + 2)
10212     return;
10213
10214   buf = gst_buffer_new_allocate (NULL, len - 14, NULL);
10215   gst_buffer_fill (buf, 0, data + 14, len - 14);
10216
10217   taglist = gst_tag_list_from_id3v2_tag (buf);
10218   if (taglist) {
10219     GST_LOG_OBJECT (demux, "parsing ok");
10220     gst_tag_list_insert (demux->tag_list, taglist, GST_TAG_MERGE_KEEP);
10221   } else {
10222     GST_LOG_OBJECT (demux, "parsing failed");
10223   }
10224
10225   if (taglist)
10226     gst_tag_list_unref (taglist);
10227
10228   gst_buffer_unref (buf);
10229 }
10230
10231 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
10232     const char *tag, const char *tag_bis, GNode * node);
10233
10234 /* unmapped tags
10235 FOURCC_pcst -> if media is a podcast -> bool
10236 FOURCC_cpil -> if media is part of a compilation -> bool
10237 FOURCC_pgap -> if media is part of a gapless context -> bool
10238 FOURCC_tven -> the tv episode id e.g. S01E23 -> str
10239 */
10240
10241 static const struct
10242 {
10243   guint32 fourcc;
10244   const gchar *gst_tag;
10245   const gchar *gst_tag_bis;
10246   const GstQTDemuxAddTagFunc func;
10247 } add_funcs[] = {
10248   {
10249   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10250   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
10251   FOURCC__grp, GST_TAG_GROUPING, NULL, qtdemux_tag_add_str}, {
10252   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10253   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10254   FOURCC_aART, GST_TAG_ALBUM_ARTIST, NULL, qtdemux_tag_add_str}, {
10255   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
10256   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
10257   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10258   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
10259   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10260   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
10261   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10262   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10263   FOURCC_desc, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10264   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
10265   FOURCC__lyr, GST_TAG_LYRICS, NULL, qtdemux_tag_add_str}, {
10266   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
10267   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
10268   FOURCC__too, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10269   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
10270   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
10271   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10272         qtdemux_tag_add_num}, {
10273   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
10274         qtdemux_tag_add_num}, {
10275   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
10276   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
10277   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
10278   FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
10279   FOURCC_sonm, GST_TAG_TITLE_SORTNAME, NULL, qtdemux_tag_add_str}, {
10280   FOURCC_soal, GST_TAG_ALBUM_SORTNAME, NULL, qtdemux_tag_add_str}, {
10281   FOURCC_soar, GST_TAG_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10282   FOURCC_soaa, GST_TAG_ALBUM_ARTIST_SORTNAME, NULL, qtdemux_tag_add_str}, {
10283   FOURCC_soco, GST_TAG_COMPOSER_SORTNAME, NULL, qtdemux_tag_add_str}, {
10284   FOURCC_sosn, GST_TAG_SHOW_SORTNAME, NULL, qtdemux_tag_add_str}, {
10285   FOURCC_tvsh, GST_TAG_SHOW_NAME, NULL, qtdemux_tag_add_str}, {
10286   FOURCC_tvsn, GST_TAG_SHOW_SEASON_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10287   FOURCC_tves, GST_TAG_SHOW_EPISODE_NUMBER, NULL, qtdemux_tag_add_uint32}, {
10288   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
10289   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
10290   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
10291   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
10292   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
10293         qtdemux_tag_add_classification}, {
10294   FOURCC__mak, GST_TAG_DEVICE_MANUFACTURER, NULL, qtdemux_tag_add_str}, {
10295   FOURCC__mod, GST_TAG_DEVICE_MODEL, NULL, qtdemux_tag_add_str}, {
10296   FOURCC__swr, GST_TAG_APPLICATION_NAME, NULL, qtdemux_tag_add_str}, {
10297
10298     /* This is a special case, some tags are stored in this
10299      * 'reverse dns naming', according to:
10300      * http://atomicparsley.sourceforge.net/mpeg-4files.html and
10301      * bug #614471
10302      */
10303   FOURCC_____, "", NULL, qtdemux_tag_add_revdns}, {
10304     /* see http://www.mp4ra.org/specs.html for ID32 in meta box */
10305   FOURCC_ID32, "", NULL, qtdemux_tag_add_id32}
10306 };
10307
10308 static void
10309 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
10310 {
10311   gint len;
10312   guint8 *data;
10313   GstBuffer *buf;
10314   gchar *media_type;
10315   const gchar *style;
10316   GstSample *sample;
10317   GstStructure *s;
10318   guint i;
10319   guint8 ndata[4];
10320
10321   data = node->data;
10322   len = QT_UINT32 (data);
10323   buf = gst_buffer_new_and_alloc (len);
10324   gst_buffer_fill (buf, 0, data, len);
10325
10326   /* heuristic to determine style of tag */
10327   if (QT_FOURCC (data + 4) == FOURCC_____ ||
10328       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
10329     style = "itunes";
10330   else if (demux->major_brand == FOURCC_qt__)
10331     style = "quicktime";
10332   /* fall back to assuming iso/3gp tag style */
10333   else
10334     style = "iso";
10335
10336   /* santize the name for the caps. */
10337   for (i = 0; i < 4; i++) {
10338     guint8 d = data[4 + i];
10339     if (g_ascii_isalnum (d))
10340       ndata[i] = g_ascii_tolower (d);
10341     else
10342       ndata[i] = '_';
10343   }
10344
10345   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
10346       ndata[0], ndata[1], ndata[2], ndata[3]);
10347   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
10348
10349   s = gst_structure_new (media_type, "style", G_TYPE_STRING, style, NULL);
10350   sample = gst_sample_new (buf, NULL, NULL, s);
10351   gst_buffer_unref (buf);
10352   g_free (media_type);
10353
10354   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, info %" GST_PTR_FORMAT,
10355       len, s);
10356
10357   gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
10358       GST_QT_DEMUX_PRIVATE_TAG, sample, NULL);
10359
10360   gst_sample_unref (sample);
10361 }
10362
10363 static void
10364 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
10365 {
10366   GNode *meta;
10367   GNode *ilst;
10368   GNode *xmp_;
10369   GNode *node;
10370   gint i;
10371
10372   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
10373   if (meta != NULL) {
10374     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
10375     if (ilst == NULL) {
10376       GST_LOG_OBJECT (qtdemux, "no ilst");
10377       return;
10378     }
10379   } else {
10380     ilst = udta;
10381     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
10382   }
10383
10384   GST_DEBUG_OBJECT (qtdemux, "new tag list");
10385   if (!qtdemux->tag_list) {
10386     qtdemux->tag_list = gst_tag_list_new_empty ();
10387     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10388   } else {
10389     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10390   }
10391
10392   i = 0;
10393   while (i < G_N_ELEMENTS (add_funcs)) {
10394     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
10395     if (node) {
10396       gint len;
10397
10398       len = QT_UINT32 (node->data);
10399       if (len < 12) {
10400         GST_DEBUG_OBJECT (qtdemux, "too small tag atom %" GST_FOURCC_FORMAT,
10401             GST_FOURCC_ARGS (add_funcs[i].fourcc));
10402       } else {
10403         add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
10404             add_funcs[i].gst_tag_bis, node);
10405       }
10406       g_node_destroy (node);
10407     } else {
10408       i++;
10409     }
10410   }
10411
10412   /* parsed nodes have been removed, pass along remainder as blob */
10413   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
10414       (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
10415
10416   /* parse up XMP_ node if existing */
10417   xmp_ = qtdemux_tree_get_child_by_type (udta, FOURCC_XMP_);
10418   if (xmp_ != NULL) {
10419     GstBuffer *buf;
10420     GstTagList *taglist;
10421
10422     buf = _gst_buffer_new_wrapped (((guint8 *) xmp_->data) + 8,
10423         QT_UINT32 ((guint8 *) xmp_->data) - 8, NULL);
10424     taglist = gst_tag_list_from_xmp_buffer (buf);
10425     gst_buffer_unref (buf);
10426
10427     qtdemux_handle_xmp_taglist (qtdemux, taglist);
10428   } else {
10429     GST_DEBUG_OBJECT (qtdemux, "No XMP_ node found");
10430   }
10431
10432 }
10433
10434 typedef struct
10435 {
10436   GstStructure *structure;      /* helper for sort function */
10437   gchar *location;
10438   guint min_req_bitrate;
10439   guint min_req_qt_version;
10440 } GstQtReference;
10441
10442 static gint
10443 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
10444 {
10445   GstQtReference *ref_a = (GstQtReference *) a;
10446   GstQtReference *ref_b = (GstQtReference *) b;
10447
10448   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
10449     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
10450
10451   /* known bitrates go before unknown; higher bitrates go first */
10452   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
10453 }
10454
10455 /* sort the redirects and post a message for the application.
10456  */
10457 static void
10458 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
10459 {
10460   GstQtReference *best;
10461   GstStructure *s;
10462   GstMessage *msg;
10463   GValue list_val = { 0, };
10464   GList *l;
10465
10466   g_assert (references != NULL);
10467
10468   references = g_list_sort (references, qtdemux_redirects_sort_func);
10469
10470   best = (GstQtReference *) references->data;
10471
10472   g_value_init (&list_val, GST_TYPE_LIST);
10473
10474   for (l = references; l != NULL; l = l->next) {
10475     GstQtReference *ref = (GstQtReference *) l->data;
10476     GValue struct_val = { 0, };
10477
10478     ref->structure = gst_structure_new ("redirect",
10479         "new-location", G_TYPE_STRING, ref->location, NULL);
10480
10481     if (ref->min_req_bitrate > 0) {
10482       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
10483           ref->min_req_bitrate, NULL);
10484     }
10485
10486     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
10487     g_value_set_boxed (&struct_val, ref->structure);
10488     gst_value_list_append_value (&list_val, &struct_val);
10489     g_value_unset (&struct_val);
10490     /* don't free anything here yet, since we need best->structure below */
10491   }
10492
10493   g_assert (best != NULL);
10494   s = gst_structure_copy (best->structure);
10495
10496   if (g_list_length (references) > 1) {
10497     gst_structure_set_value (s, "locations", &list_val);
10498   }
10499
10500   g_value_unset (&list_val);
10501
10502   for (l = references; l != NULL; l = l->next) {
10503     GstQtReference *ref = (GstQtReference *) l->data;
10504
10505     gst_structure_free (ref->structure);
10506     g_free (ref->location);
10507     g_free (ref);
10508   }
10509   g_list_free (references);
10510
10511   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
10512   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
10513   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
10514   qtdemux->posted_redirect = TRUE;
10515 }
10516
10517 /* look for redirect nodes, collect all redirect information and
10518  * process it.
10519  */
10520 static gboolean
10521 qtdemux_parse_redirects (GstQTDemux * qtdemux)
10522 {
10523   GNode *rmra, *rmda, *rdrf;
10524
10525   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
10526   if (rmra) {
10527     GList *redirects = NULL;
10528
10529     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
10530     while (rmda) {
10531       GstQtReference ref = { NULL, NULL, 0, 0 };
10532       GNode *rmdr, *rmvc;
10533
10534       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
10535         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
10536         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
10537             ref.min_req_bitrate);
10538       }
10539
10540       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
10541         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
10542         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
10543
10544 #ifndef GST_DISABLE_GST_DEBUG
10545         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
10546 #endif
10547         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
10548
10549         GST_LOG_OBJECT (qtdemux,
10550             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
10551             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
10552             bitmask, check_type);
10553         if (package == FOURCC_qtim && check_type == 0) {
10554           ref.min_req_qt_version = version;
10555         }
10556       }
10557
10558       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
10559       if (rdrf) {
10560         guint32 ref_type;
10561         guint8 *ref_data;
10562
10563         ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
10564         ref_data = (guint8 *) rdrf->data + 20;
10565         if (ref_type == FOURCC_alis) {
10566           guint record_len, record_version, fn_len;
10567
10568           /* MacOSX alias record, google for alias-layout.txt */
10569           record_len = QT_UINT16 (ref_data + 4);
10570           record_version = QT_UINT16 (ref_data + 4 + 2);
10571           fn_len = QT_UINT8 (ref_data + 50);
10572           if (record_len > 50 && record_version == 2 && fn_len > 0) {
10573             ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
10574           }
10575         } else if (ref_type == FOURCC_url_) {
10576           ref.location = g_strdup ((gchar *) ref_data);
10577         } else {
10578           GST_DEBUG_OBJECT (qtdemux,
10579               "unknown rdrf reference type %" GST_FOURCC_FORMAT,
10580               GST_FOURCC_ARGS (ref_type));
10581         }
10582         if (ref.location != NULL) {
10583           GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
10584           redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
10585         } else {
10586           GST_WARNING_OBJECT (qtdemux,
10587               "Failed to extract redirect location from rdrf atom");
10588         }
10589       }
10590
10591       /* look for others */
10592       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
10593     }
10594
10595     if (redirects != NULL) {
10596       qtdemux_process_redirects (qtdemux, redirects);
10597     }
10598   }
10599   return TRUE;
10600 }
10601
10602 static GstTagList *
10603 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
10604 {
10605   const gchar *fmt;
10606
10607   if (tags == NULL) {
10608     tags = gst_tag_list_new_empty ();
10609     gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
10610   }
10611
10612   if (qtdemux->major_brand == FOURCC_mjp2)
10613     fmt = "Motion JPEG 2000";
10614   else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
10615     fmt = "3GP";
10616   else if (qtdemux->major_brand == FOURCC_qt__)
10617     fmt = "Quicktime";
10618   else if (qtdemux->fragmented)
10619     fmt = "ISO fMP4";
10620   else
10621     fmt = "ISO MP4/M4A";
10622
10623   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
10624       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
10625
10626   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
10627       fmt, NULL);
10628
10629   return tags;
10630 }
10631
10632 /* we have read th complete moov node now.
10633  * This function parses all of the relevant info, creates the traks and
10634  * prepares all data structures for playback
10635  */
10636 static gboolean
10637 qtdemux_parse_tree (GstQTDemux * qtdemux)
10638 {
10639   GNode *mvhd;
10640   GNode *trak;
10641   GNode *udta;
10642   GNode *mvex;
10643   GstClockTime duration;
10644   guint64 creation_time;
10645   GstDateTime *datetime = NULL;
10646   gint version;
10647
10648   /* make sure we have a usable taglist */
10649   if (!qtdemux->tag_list) {
10650     qtdemux->tag_list = gst_tag_list_new_empty ();
10651     gst_tag_list_set_scope (qtdemux->tag_list, GST_TAG_SCOPE_GLOBAL);
10652   } else {
10653     qtdemux->tag_list = gst_tag_list_make_writable (qtdemux->tag_list);
10654   }
10655
10656   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
10657   if (mvhd == NULL) {
10658     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
10659     return qtdemux_parse_redirects (qtdemux);
10660   }
10661
10662   version = QT_UINT8 ((guint8 *) mvhd->data + 8);
10663   if (version == 1) {
10664     creation_time = QT_UINT64 ((guint8 *) mvhd->data + 12);
10665     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 28);
10666     qtdemux->duration = QT_UINT64 ((guint8 *) mvhd->data + 32);
10667   } else if (version == 0) {
10668     creation_time = QT_UINT32 ((guint8 *) mvhd->data + 12);
10669     qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
10670     qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
10671   } else {
10672     GST_WARNING_OBJECT (qtdemux, "Unhandled mvhd version %d", version);
10673     return FALSE;
10674   }
10675
10676   /* Moving qt creation time (secs since 1904) to unix time */
10677   if (creation_time != 0) {
10678     /* Try to use epoch first as it should be faster and more commonly found */
10679     if (creation_time >= QTDEMUX_SECONDS_FROM_1904_TO_1970) {
10680       GTimeVal now;
10681
10682       creation_time -= QTDEMUX_SECONDS_FROM_1904_TO_1970;
10683       /* some data cleansing sanity */
10684       g_get_current_time (&now);
10685       if (now.tv_sec + 24 * 3600 < creation_time) {
10686         GST_DEBUG_OBJECT (qtdemux, "discarding bogus future creation time");
10687       } else {
10688         datetime = gst_date_time_new_from_unix_epoch_utc (creation_time);
10689       }
10690     } else {
10691       GDateTime *base_dt = g_date_time_new_utc (1904, 1, 1, 0, 0, 0);
10692       GDateTime *dt, *dt_local;
10693
10694       dt = g_date_time_add_seconds (base_dt, creation_time);
10695       dt_local = g_date_time_to_local (dt);
10696       datetime = gst_date_time_new_from_g_date_time (dt_local);
10697
10698       g_date_time_unref (base_dt);
10699       g_date_time_unref (dt);
10700     }
10701   }
10702   if (datetime) {
10703     /* Use KEEP as explicit tags should have a higher priority than mvhd tag */
10704     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_KEEP, GST_TAG_DATE_TIME,
10705         datetime, NULL);
10706     gst_date_time_unref (datetime);
10707   }
10708
10709   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
10710   GST_INFO_OBJECT (qtdemux, "duration: %" G_GUINT64_FORMAT, qtdemux->duration);
10711
10712   /* check for fragmented file and get some (default) data */
10713   mvex = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvex);
10714   if (mvex) {
10715     GNode *mehd;
10716     GstByteReader mehd_data;
10717
10718     /* let track parsing or anyone know weird stuff might happen ... */
10719     qtdemux->fragmented = TRUE;
10720
10721     /* compensate for total duration */
10722     mehd = qtdemux_tree_get_child_by_type_full (mvex, FOURCC_mehd, &mehd_data);
10723     if (mehd)
10724       qtdemux_parse_mehd (qtdemux, &mehd_data);
10725   }
10726
10727   /* set duration in the segment info */
10728   gst_qtdemux_get_duration (qtdemux, &duration);
10729   if (duration) {
10730     qtdemux->segment.duration = duration;
10731     /* also do not exceed duration; stop is set that way post seek anyway,
10732      * and segment activation falls back to duration,
10733      * whereas loop only checks stop, so let's align this here as well */
10734     qtdemux->segment.stop = duration;
10735   }
10736
10737   /* parse all traks */
10738   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
10739   while (trak) {
10740     qtdemux_parse_trak (qtdemux, trak);
10741     /* iterate all siblings */
10742     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
10743   }
10744
10745   /* find tags */
10746   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
10747   if (udta) {
10748     qtdemux_parse_udta (qtdemux, udta);
10749   } else {
10750     GST_LOG_OBJECT (qtdemux, "No udta node found.");
10751   }
10752
10753   /* maybe also some tags in meta box */
10754   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_meta);
10755   if (udta) {
10756     GST_DEBUG_OBJECT (qtdemux, "Parsing meta box for tags.");
10757     qtdemux_parse_udta (qtdemux, udta);
10758   } else {
10759     GST_LOG_OBJECT (qtdemux, "No meta node found.");
10760   }
10761
10762   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
10763
10764   return TRUE;
10765 }
10766
10767 /* taken from ffmpeg */
10768 static int
10769 read_descr_size (guint8 * ptr, guint8 * end, guint8 ** end_out)
10770 {
10771   int count = 4;
10772   int len = 0;
10773
10774   while (count--) {
10775     int c;
10776
10777     if (ptr >= end)
10778       return -1;
10779
10780     c = *ptr++;
10781     len = (len << 7) | (c & 0x7f);
10782     if (!(c & 0x80))
10783       break;
10784   }
10785   *end_out = ptr;
10786   return len;
10787 }
10788
10789 /* this can change the codec originally present in @list */
10790 static void
10791 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
10792     GNode * esds, GstTagList * list)
10793 {
10794   int len = QT_UINT32 (esds->data);
10795   guint8 *ptr = esds->data;
10796   guint8 *end = ptr + len;
10797   int tag;
10798   guint8 *data_ptr = NULL;
10799   int data_len = 0;
10800   guint8 object_type_id = 0;
10801   const char *codec_name = NULL;
10802   GstCaps *caps = NULL;
10803
10804   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
10805   ptr += 8;
10806   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
10807   ptr += 4;
10808   while (ptr + 1 < end) {
10809     tag = QT_UINT8 (ptr);
10810     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
10811     ptr++;
10812     len = read_descr_size (ptr, end, &ptr);
10813     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
10814
10815     /* Check the stated amount of data is available for reading */
10816     if (len < 0 || ptr + len > end)
10817       break;
10818
10819     switch (tag) {
10820       case ES_DESCRIPTOR_TAG:
10821         GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
10822         GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
10823         ptr += 3;
10824         break;
10825       case DECODER_CONFIG_DESC_TAG:{
10826         guint max_bitrate, avg_bitrate;
10827
10828         object_type_id = QT_UINT8 (ptr);
10829         max_bitrate = QT_UINT32 (ptr + 5);
10830         avg_bitrate = QT_UINT32 (ptr + 9);
10831         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
10832         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
10833         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
10834         GST_DEBUG_OBJECT (qtdemux, "max bitrate %u", max_bitrate);
10835         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %u", avg_bitrate);
10836         if (max_bitrate > 0 && max_bitrate < G_MAXUINT32) {
10837           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
10838               GST_TAG_MAXIMUM_BITRATE, max_bitrate, NULL);
10839         }
10840         if (avg_bitrate > 0 && avg_bitrate < G_MAXUINT32) {
10841           gst_tag_list_add (list, GST_TAG_MERGE_REPLACE, GST_TAG_BITRATE,
10842               avg_bitrate, NULL);
10843         }
10844         ptr += 13;
10845         break;
10846       }
10847       case DECODER_SPECIFIC_INFO_TAG:
10848         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
10849         if (object_type_id == 0xe0 && len == 0x40) {
10850           guint8 *data;
10851           GstStructure *s;
10852           guint32 clut[16];
10853           gint i;
10854
10855           GST_DEBUG_OBJECT (qtdemux,
10856               "Have VOBSUB palette. Creating palette event");
10857           /* move to decConfigDescr data and read palette */
10858           data = ptr;
10859           for (i = 0; i < 16; i++) {
10860             clut[i] = QT_UINT32 (data);
10861             data += 4;
10862           }
10863
10864           s = gst_structure_new ("application/x-gst-dvd", "event",
10865               G_TYPE_STRING, "dvd-spu-clut-change",
10866               "clut00", G_TYPE_INT, clut[0], "clut01", G_TYPE_INT, clut[1],
10867               "clut02", G_TYPE_INT, clut[2], "clut03", G_TYPE_INT, clut[3],
10868               "clut04", G_TYPE_INT, clut[4], "clut05", G_TYPE_INT, clut[5],
10869               "clut06", G_TYPE_INT, clut[6], "clut07", G_TYPE_INT, clut[7],
10870               "clut08", G_TYPE_INT, clut[8], "clut09", G_TYPE_INT, clut[9],
10871               "clut10", G_TYPE_INT, clut[10], "clut11", G_TYPE_INT, clut[11],
10872               "clut12", G_TYPE_INT, clut[12], "clut13", G_TYPE_INT, clut[13],
10873               "clut14", G_TYPE_INT, clut[14], "clut15", G_TYPE_INT, clut[15],
10874               NULL);
10875
10876           /* store event and trigger custom processing */
10877           stream->pending_event =
10878               gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, s);
10879         } else {
10880           /* Generic codec_data handler puts it on the caps */
10881           data_ptr = ptr;
10882           data_len = len;
10883         }
10884
10885         ptr += len;
10886         break;
10887       case SL_CONFIG_DESC_TAG:
10888         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
10889         ptr += 1;
10890         break;
10891       default:
10892         GST_DEBUG_OBJECT (qtdemux, "Unknown/unhandled descriptor tag %02x",
10893             tag);
10894         GST_MEMDUMP_OBJECT (qtdemux, "descriptor data", ptr, len);
10895         ptr += len;
10896         break;
10897     }
10898   }
10899
10900   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
10901    * in use, and should also be used to override some other parameters for some
10902    * codecs. */
10903   switch (object_type_id) {
10904     case 0x20:                 /* MPEG-4 */
10905       /* 4 bytes for the visual_object_sequence_start_code and 1 byte for the
10906        * profile_and_level_indication */
10907       if (data_ptr != NULL && data_len >= 5 &&
10908           GST_READ_UINT32_BE (data_ptr) == 0x000001b0) {
10909         gst_codec_utils_mpeg4video_caps_set_level_and_profile (stream->caps,
10910             data_ptr + 4, data_len - 4);
10911       }
10912       break;                    /* Nothing special needed here */
10913     case 0x21:                 /* H.264 */
10914       codec_name = "H.264 / AVC";
10915       caps = gst_caps_new_simple ("video/x-h264",
10916           "stream-format", G_TYPE_STRING, "avc",
10917           "alignment", G_TYPE_STRING, "au", NULL);
10918       break;
10919     case 0x40:                 /* AAC (any) */
10920     case 0x66:                 /* AAC Main */
10921     case 0x67:                 /* AAC LC */
10922     case 0x68:                 /* AAC SSR */
10923       /* Override channels and rate based on the codec_data, as it's often
10924        * wrong. */
10925       /* Only do so for basic setup without HE-AAC extension */
10926       if (data_ptr && data_len == 2) {
10927         guint channels, rateindex, rate;
10928
10929         /* FIXME: add gst_codec_utils_aac_get_{channels|sample_rate}()? */
10930         channels = (data_ptr[1] & 0x7f) >> 3;
10931         if (channels > 0 && channels < 7) {
10932           stream->n_channels = channels;
10933         } else if (channels == 7) {
10934           stream->n_channels = 8;
10935         }
10936
10937         rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
10938         rate = gst_codec_utils_aac_get_sample_rate_from_index (rateindex);
10939         if (rate > 0)
10940           stream->rate = rate;
10941       }
10942
10943       /* Set level and profile if possible */
10944       if (data_ptr != NULL && data_len >= 2) {
10945         gst_codec_utils_aac_caps_set_level_and_profile (stream->caps,
10946             data_ptr, data_len);
10947       }
10948       break;
10949     case 0x60:                 /* MPEG-2, various profiles */
10950     case 0x61:
10951     case 0x62:
10952     case 0x63:
10953     case 0x64:
10954     case 0x65:
10955       codec_name = "MPEG-2 video";
10956       caps = gst_caps_new_simple ("video/mpeg",
10957           "mpegversion", G_TYPE_INT, 2,
10958           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10959       break;
10960     case 0x69:                 /* MPEG-2 BC audio */
10961     case 0x6B:                 /* MPEG-1 audio */
10962       caps = gst_caps_new_simple ("audio/mpeg",
10963           "mpegversion", G_TYPE_INT, 1, "parsed", G_TYPE_BOOLEAN, TRUE, NULL);
10964       codec_name = "MPEG-1 audio";
10965       break;
10966     case 0x6A:                 /* MPEG-1 */
10967       codec_name = "MPEG-1 video";
10968       caps = gst_caps_new_simple ("video/mpeg",
10969           "mpegversion", G_TYPE_INT, 1,
10970           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
10971       break;
10972     case 0x6C:                 /* MJPEG */
10973       caps =
10974           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
10975           NULL);
10976       codec_name = "Motion-JPEG";
10977       break;
10978     case 0x6D:                 /* PNG */
10979       caps =
10980           gst_caps_new_simple ("image/png", "parsed", G_TYPE_BOOLEAN, TRUE,
10981           NULL);
10982       codec_name = "PNG still images";
10983       break;
10984     case 0x6E:                 /* JPEG2000 */
10985       codec_name = "JPEG-2000";
10986       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
10987       break;
10988     case 0xA4:                 /* Dirac */
10989       codec_name = "Dirac";
10990       caps = gst_caps_new_empty_simple ("video/x-dirac");
10991       break;
10992     case 0xA5:                 /* AC3 */
10993       codec_name = "AC-3 audio";
10994       caps = gst_caps_new_simple ("audio/x-ac3",
10995           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
10996       break;
10997     case 0xA9:                 /* AC3 */
10998       codec_name = "DTS audio";
10999       caps = gst_caps_new_simple ("audio/x-dts",
11000           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11001       break;
11002     case 0xE1:                 /* QCELP */
11003       /* QCELP, the codec_data is a riff tag (little endian) with
11004        * 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). */
11005       caps = gst_caps_new_empty_simple ("audio/qcelp");
11006       codec_name = "QCELP";
11007       break;
11008     default:
11009       break;
11010   }
11011
11012   /* If we have a replacement caps, then change our caps for this stream */
11013   if (caps) {
11014     gst_caps_unref (stream->caps);
11015     stream->caps = caps;
11016   }
11017
11018   if (codec_name && list)
11019     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
11020         GST_TAG_AUDIO_CODEC, codec_name, NULL);
11021
11022   /* Add the codec_data attribute to caps, if we have it */
11023   if (data_ptr) {
11024     GstBuffer *buffer;
11025
11026     buffer = gst_buffer_new_and_alloc (data_len);
11027     gst_buffer_fill (buffer, 0, data_ptr, data_len);
11028
11029     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
11030     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
11031
11032     gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
11033         buffer, NULL);
11034     gst_buffer_unref (buffer);
11035   }
11036
11037 }
11038
11039 #define _codec(name) \
11040   do { \
11041     if (codec_name) { \
11042       *codec_name = g_strdup (name); \
11043     } \
11044   } while (0)
11045
11046 static GstCaps *
11047 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11048     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11049 {
11050   GstCaps *caps = NULL;
11051   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
11052
11053   switch (fourcc) {
11054     case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
11055       _codec ("PNG still images");
11056       caps = gst_caps_new_empty_simple ("image/png");
11057       break;
11058     case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
11059       _codec ("JPEG still images");
11060       caps =
11061           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11062           NULL);
11063       break;
11064     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
11065     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
11066     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
11067     case GST_MAKE_FOURCC ('d', 'm', 'b', '1'):
11068       _codec ("Motion-JPEG");
11069       caps =
11070           gst_caps_new_simple ("image/jpeg", "parsed", G_TYPE_BOOLEAN, TRUE,
11071           NULL);
11072       break;
11073     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
11074       _codec ("Motion-JPEG format B");
11075       caps = gst_caps_new_empty_simple ("video/x-mjpeg-b");
11076       break;
11077     case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
11078       _codec ("JPEG-2000");
11079       /* override to what it should be according to spec, avoid palette_data */
11080       stream->bits_per_sample = 24;
11081       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
11082       break;
11083     case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
11084       _codec ("Sorensen video v.3");
11085       caps = gst_caps_new_simple ("video/x-svq",
11086           "svqversion", G_TYPE_INT, 3, NULL);
11087       break;
11088     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
11089     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
11090       _codec ("Sorensen video v.1");
11091       caps = gst_caps_new_simple ("video/x-svq",
11092           "svqversion", G_TYPE_INT, 1, NULL);
11093       break;
11094     case GST_MAKE_FOURCC ('W', 'R', 'A', 'W'):
11095       caps = gst_caps_new_empty_simple ("video/x-raw");
11096       gst_caps_set_simple (caps, "format", G_TYPE_STRING, "RGB8P", NULL);
11097       _codec ("Windows Raw RGB");
11098       break;
11099     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11100     {
11101       guint16 bps;
11102
11103       bps = QT_UINT16 (stsd_data + 98);
11104       switch (bps) {
11105         case 15:
11106           format = GST_VIDEO_FORMAT_RGB15;
11107           break;
11108         case 16:
11109           format = GST_VIDEO_FORMAT_RGB16;
11110           break;
11111         case 24:
11112           format = GST_VIDEO_FORMAT_RGB;
11113           break;
11114         case 32:
11115           format = GST_VIDEO_FORMAT_ARGB;
11116           break;
11117         default:
11118           /* unknown */
11119           break;
11120       }
11121       break;
11122     }
11123     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
11124       format = GST_VIDEO_FORMAT_I420;
11125       break;
11126     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
11127     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
11128       format = GST_VIDEO_FORMAT_I420;
11129       break;
11130     case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
11131     case GST_MAKE_FOURCC ('2', 'V', 'u', 'y'):
11132       format = GST_VIDEO_FORMAT_UYVY;
11133       break;
11134     case GST_MAKE_FOURCC ('v', '3', '0', '8'):
11135       format = GST_VIDEO_FORMAT_v308;
11136       break;
11137     case GST_MAKE_FOURCC ('v', '2', '1', '6'):
11138       format = GST_VIDEO_FORMAT_v216;
11139       break;
11140     case GST_MAKE_FOURCC ('v', '2', '1', '0'):
11141       format = GST_VIDEO_FORMAT_v210;
11142       break;
11143     case GST_MAKE_FOURCC ('r', '2', '1', '0'):
11144       format = GST_VIDEO_FORMAT_r210;
11145       break;
11146       /* Packed YUV 4:4:4 10 bit in 32 bits, complex
11147          case GST_MAKE_FOURCC ('v', '4', '1', '0'):
11148          format = GST_VIDEO_FORMAT_v410;
11149          break;
11150        */
11151       /* Packed YUV 4:4:4:4 8 bit in 32 bits
11152        * but different order than AYUV
11153        case GST_MAKE_FOURCC ('v', '4', '0', '8'):
11154        format = GST_VIDEO_FORMAT_v408;
11155        break;
11156        */
11157     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
11158     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
11159       _codec ("MPEG-1 video");
11160       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11161           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11162       break;
11163     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): /* HDV 720p30 */
11164     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): /* HDV 1080i60 */
11165     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): /* HDV 1080i50 */
11166     case GST_MAKE_FOURCC ('h', 'd', 'v', '4'): /* HDV 720p24 */
11167     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): /* HDV 720p25 */
11168     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): /* HDV 1080p24 */
11169     case GST_MAKE_FOURCC ('h', 'd', 'v', '7'): /* HDV 1080p25 */
11170     case GST_MAKE_FOURCC ('h', 'd', 'v', '8'): /* HDV 1080p30 */
11171     case GST_MAKE_FOURCC ('h', 'd', 'v', '9'): /* HDV 720p60 */
11172     case GST_MAKE_FOURCC ('h', 'd', 'v', 'a'): /* HDV 720p50 */
11173     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): /* MPEG2 IMX NTSC 525/60 50mb/s produced by FCP */
11174     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): /* MPEG2 IMX PAL 625/60 50mb/s produced by FCP */
11175     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): /* MPEG2 IMX NTSC 525/60 40mb/s produced by FCP */
11176     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): /* MPEG2 IMX PAL 625/60 40mb/s produced by FCP */
11177     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): /* MPEG2 IMX NTSC 525/60 30mb/s produced by FCP */
11178     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): /* MPEG2 IMX PAL 625/50 30mb/s produced by FCP */
11179     case GST_MAKE_FOURCC ('x', 'd', 'v', '1'): /* XDCAM HD 720p30 35Mb/s */
11180     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): /* XDCAM HD 1080i60 35Mb/s */
11181     case GST_MAKE_FOURCC ('x', 'd', 'v', '3'): /* XDCAM HD 1080i50 35Mb/s */
11182     case GST_MAKE_FOURCC ('x', 'd', 'v', '4'): /* XDCAM HD 720p24 35Mb/s */
11183     case GST_MAKE_FOURCC ('x', 'd', 'v', '5'): /* XDCAM HD 720p25 35Mb/s */
11184     case GST_MAKE_FOURCC ('x', 'd', 'v', '6'): /* XDCAM HD 1080p24 35Mb/s */
11185     case GST_MAKE_FOURCC ('x', 'd', 'v', '7'): /* XDCAM HD 1080p25 35Mb/s */
11186     case GST_MAKE_FOURCC ('x', 'd', 'v', '8'): /* XDCAM HD 1080p30 35Mb/s */
11187     case GST_MAKE_FOURCC ('x', 'd', 'v', '9'): /* XDCAM HD 720p60 35Mb/s */
11188     case GST_MAKE_FOURCC ('x', 'd', 'v', 'a'): /* XDCAM HD 720p50 35Mb/s */
11189     case GST_MAKE_FOURCC ('x', 'd', 'v', 'b'): /* XDCAM EX 1080i60 50Mb/s CBR */
11190     case GST_MAKE_FOURCC ('x', 'd', 'v', 'c'): /* XDCAM EX 1080i50 50Mb/s CBR */
11191     case GST_MAKE_FOURCC ('x', 'd', 'v', 'd'): /* XDCAM HD 1080p24 50Mb/s CBR */
11192     case GST_MAKE_FOURCC ('x', 'd', 'v', 'e'): /* XDCAM HD 1080p25 50Mb/s CBR */
11193     case GST_MAKE_FOURCC ('x', 'd', 'v', 'f'): /* XDCAM HD 1080p30 50Mb/s CBR */
11194     case GST_MAKE_FOURCC ('x', 'd', '5', '1'): /* XDCAM HD422 720p30 50Mb/s CBR */
11195     case GST_MAKE_FOURCC ('x', 'd', '5', '4'): /* XDCAM HD422 720p24 50Mb/s CBR */
11196     case GST_MAKE_FOURCC ('x', 'd', '5', '5'): /* XDCAM HD422 720p25 50Mb/s CBR */
11197     case GST_MAKE_FOURCC ('x', 'd', '5', '9'): /* XDCAM HD422 720p60 50Mb/s CBR */
11198     case GST_MAKE_FOURCC ('x', 'd', '5', 'a'): /* XDCAM HD422 720p50 50Mb/s CBR */
11199     case GST_MAKE_FOURCC ('x', 'd', '5', 'b'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11200     case GST_MAKE_FOURCC ('x', 'd', '5', 'c'): /* XDCAM HD422 1080i50 50Mb/s CBR */
11201     case GST_MAKE_FOURCC ('x', 'd', '5', 'd'): /* XDCAM HD422 1080p24 50Mb/s CBR */
11202     case GST_MAKE_FOURCC ('x', 'd', '5', 'e'): /* XDCAM HD422 1080p25 50Mb/s CBR */
11203     case GST_MAKE_FOURCC ('x', 'd', '5', 'f'): /* XDCAM HD422 1080p30 50Mb/s CBR */
11204     case GST_MAKE_FOURCC ('x', 'd', 'h', 'd'): /* XDCAM HD 540p */
11205     case GST_MAKE_FOURCC ('x', 'd', 'h', '2'): /* XDCAM HD422 540p */
11206     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): /* AVID IMX PAL */
11207     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): /* AVID IMX PAL */
11208     case GST_MAKE_FOURCC ('m', 'p', '2', 'v'): /* AVID IMX PAL */
11209       _codec ("MPEG-2 video");
11210       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
11211           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11212       break;
11213     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
11214       _codec ("GIF still images");
11215       caps = gst_caps_new_empty_simple ("image/gif");
11216       break;
11217     case GST_MAKE_FOURCC ('h', '2', '6', '3'):
11218     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
11219     case GST_MAKE_FOURCC ('s', '2', '6', '3'):
11220     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
11221       _codec ("H.263");
11222       /* ffmpeg uses the height/width props, don't know why */
11223       caps = gst_caps_new_simple ("video/x-h263",
11224           "variant", G_TYPE_STRING, "itu", NULL);
11225       break;
11226     case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
11227     case GST_MAKE_FOURCC ('M', 'P', '4', 'V'):
11228       _codec ("MPEG-4 video");
11229       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
11230           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11231       break;
11232     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
11233     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
11234       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
11235       caps = gst_caps_new_simple ("video/x-msmpeg",
11236           "msmpegversion", G_TYPE_INT, 43, NULL);
11237       break;
11238     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
11239       _codec ("DivX 3");
11240       caps = gst_caps_new_simple ("video/x-divx",
11241           "divxversion", G_TYPE_INT, 3, NULL);
11242       break;
11243     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
11244     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
11245       _codec ("DivX 4");
11246       caps = gst_caps_new_simple ("video/x-divx",
11247           "divxversion", G_TYPE_INT, 4, NULL);
11248       break;
11249     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
11250       _codec ("DivX 5");
11251       caps = gst_caps_new_simple ("video/x-divx",
11252           "divxversion", G_TYPE_INT, 5, NULL);
11253       break;
11254
11255     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
11256     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
11257     case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
11258     case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
11259     case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
11260     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
11261       caps = gst_caps_new_simple ("video/mpeg",
11262           "mpegversion", G_TYPE_INT, 4, NULL);
11263       if (codec_name)
11264         *codec_name = g_strdup ("MPEG-4");
11265       break;
11266
11267     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
11268       _codec ("Cinepak");
11269       caps = gst_caps_new_empty_simple ("video/x-cinepak");
11270       break;
11271     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
11272       _codec ("Apple QuickDraw");
11273       caps = gst_caps_new_empty_simple ("video/x-qdrw");
11274       break;
11275     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
11276       _codec ("Apple video");
11277       caps = gst_caps_new_empty_simple ("video/x-apple-video");
11278       break;
11279     case GST_MAKE_FOURCC ('H', '2', '6', '4'):
11280     case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
11281       _codec ("H.264 / AVC");
11282       caps = gst_caps_new_simple ("video/x-h264",
11283           "stream-format", G_TYPE_STRING, "avc",
11284           "alignment", G_TYPE_STRING, "au", NULL);
11285       break;
11286     case GST_MAKE_FOURCC ('a', 'v', 'c', '3'):
11287       _codec ("H.264 / AVC");
11288       caps = gst_caps_new_simple ("video/x-h264",
11289           "stream-format", G_TYPE_STRING, "avc3",
11290           "alignment", G_TYPE_STRING, "au", NULL);
11291       break;
11292     case GST_MAKE_FOURCC ('H', '2', '6', '5'):
11293     case GST_MAKE_FOURCC ('h', 'v', 'c', '1'):
11294       _codec ("H.265 / HEVC");
11295       caps = gst_caps_new_simple ("video/x-h265",
11296           "stream-format", G_TYPE_STRING, "hvc1",
11297           "alignment", G_TYPE_STRING, "au", NULL);
11298       break;
11299     case GST_MAKE_FOURCC ('h', 'e', 'v', '1'):
11300       _codec ("H.265 / HEVC");
11301       caps = gst_caps_new_simple ("video/x-h265",
11302           "stream-format", G_TYPE_STRING, "hev1",
11303           "alignment", G_TYPE_STRING, "au", NULL);
11304       break;
11305     case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
11306       _codec ("Run-length encoding");
11307       caps = gst_caps_new_simple ("video/x-rle",
11308           "layout", G_TYPE_STRING, "quicktime", NULL);
11309       break;
11310     case GST_MAKE_FOURCC ('W', 'R', 'L', 'E'):
11311       _codec ("Run-length encoding");
11312       caps = gst_caps_new_simple ("video/x-rle",
11313           "layout", G_TYPE_STRING, "microsoft", NULL);
11314       break;
11315     case GST_MAKE_FOURCC ('I', 'V', '3', '2'):
11316     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
11317       _codec ("Indeo Video 3");
11318       caps = gst_caps_new_simple ("video/x-indeo",
11319           "indeoversion", G_TYPE_INT, 3, NULL);
11320       break;
11321     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
11322     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
11323       _codec ("Intel Video 4");
11324       caps = gst_caps_new_simple ("video/x-indeo",
11325           "indeoversion", G_TYPE_INT, 4, NULL);
11326       break;
11327     case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
11328     case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
11329     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
11330     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
11331     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
11332     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
11333     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
11334     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
11335       _codec ("DV Video");
11336       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
11337           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11338       break;
11339     case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): /* DVCPRO50 NTSC */
11340     case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): /* DVCPRO50 PAL */
11341       _codec ("DVCPro50 Video");
11342       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
11343           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11344       break;
11345     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): /* DVCPRO HD 50i produced by FCP */
11346     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): /* DVCPRO HD 60i produced by FCP */
11347       _codec ("DVCProHD Video");
11348       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
11349           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11350       break;
11351     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
11352       _codec ("Apple Graphics (SMC)");
11353       caps = gst_caps_new_empty_simple ("video/x-smc");
11354       break;
11355     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
11356       _codec ("VP3");
11357       caps = gst_caps_new_empty_simple ("video/x-vp3");
11358       break;
11359     case GST_MAKE_FOURCC ('V', 'P', '6', 'F'):
11360       _codec ("VP6 Flash");
11361       caps = gst_caps_new_empty_simple ("video/x-vp6-flash");
11362       break;
11363     case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
11364       _codec ("Theora");
11365       caps = gst_caps_new_empty_simple ("video/x-theora");
11366       /* theora uses one byte of padding in the data stream because it does not
11367        * allow 0 sized packets while theora does */
11368       stream->padding = 1;
11369       break;
11370     case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
11371       _codec ("Dirac");
11372       caps = gst_caps_new_empty_simple ("video/x-dirac");
11373       break;
11374     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
11375       _codec ("TIFF still images");
11376       caps = gst_caps_new_empty_simple ("image/tiff");
11377       break;
11378     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
11379       _codec ("Apple Intermediate Codec");
11380       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
11381       break;
11382     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
11383       _codec ("AVID DNxHD");
11384       caps = gst_caps_from_string ("video/x-dnxhd");
11385       break;
11386     case GST_MAKE_FOURCC ('V', 'P', '8', '0'):
11387       _codec ("On2 VP8");
11388       caps = gst_caps_from_string ("video/x-vp8");
11389       break;
11390     case GST_MAKE_FOURCC ('a', 'p', 'c', 's'):
11391       _codec ("Apple ProRes LT");
11392       caps =
11393           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "lt",
11394           NULL);
11395       break;
11396     case GST_MAKE_FOURCC ('a', 'p', 'c', 'h'):
11397       _codec ("Apple ProRes HQ");
11398       caps =
11399           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING, "hq",
11400           NULL);
11401       break;
11402     case GST_MAKE_FOURCC ('a', 'p', 'c', 'n'):
11403       _codec ("Apple ProRes");
11404       caps =
11405           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11406           "standard", NULL);
11407       break;
11408     case GST_MAKE_FOURCC ('a', 'p', 'c', 'o'):
11409       _codec ("Apple ProRes Proxy");
11410       caps =
11411           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11412           "proxy", NULL);
11413       break;
11414     case GST_MAKE_FOURCC ('a', 'p', '4', 'h'):
11415       _codec ("Apple ProRes 4444");
11416       caps =
11417           gst_caps_new_simple ("video/x-prores", "variant", G_TYPE_STRING,
11418           "4444", NULL);
11419       break;
11420     case GST_MAKE_FOURCC ('v', 'c', '-', '1'):
11421     case FOURCC_ovc1:
11422       _codec ("VC-1");
11423       caps = gst_caps_new_simple ("video/x-wmv",
11424           "wmvversion", G_TYPE_INT, 3, "format", G_TYPE_STRING, "WVC1", NULL);
11425       break;
11426     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
11427     default:
11428     {
11429       char *s, fourstr[5];
11430
11431       g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11432       s = g_strdup_printf ("video/x-gst-fourcc-%s", g_strstrip (fourstr));
11433       caps = gst_caps_new_empty_simple (s);
11434       break;
11435     }
11436   }
11437
11438   if (format != GST_VIDEO_FORMAT_UNKNOWN) {
11439     GstVideoInfo info;
11440
11441     gst_video_info_init (&info);
11442     gst_video_info_set_format (&info, format, stream->width, stream->height);
11443     caps = gst_video_info_to_caps (&info);
11444     *codec_name = gst_pb_utils_get_codec_description (caps);
11445
11446     /* enable clipping for raw video streams */
11447     stream->need_clip = TRUE;
11448   }
11449
11450   return caps;
11451 }
11452
11453 static GstCaps *
11454 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11455     guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
11456 {
11457   GstCaps *caps;
11458   const GstStructure *s;
11459   const gchar *name;
11460   gint endian = 0;
11461
11462   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11463
11464   switch (fourcc) {
11465     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
11466     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
11467       _codec ("Raw 8-bit PCM audio");
11468       caps = gst_caps_new_simple ("audio/x-raw",
11469           "format", G_TYPE_STRING, "U8",
11470           "layout", G_TYPE_STRING, "interleaved", NULL);
11471       break;
11472     case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
11473       endian = G_BIG_ENDIAN;
11474       /* fall-through */
11475     case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
11476     {
11477       gchar *str;
11478       gint depth;
11479       GstAudioFormat format;
11480
11481       if (!endian)
11482         endian = G_LITTLE_ENDIAN;
11483
11484       depth = stream->bytes_per_packet * 8;
11485       format = gst_audio_format_build_integer (TRUE, endian, depth, depth);
11486
11487       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
11488       _codec (str);
11489       g_free (str);
11490
11491       caps = gst_caps_new_simple ("audio/x-raw",
11492           "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11493           "layout", G_TYPE_STRING, "interleaved", NULL);
11494       break;
11495     }
11496     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
11497       _codec ("Raw 64-bit floating-point audio");
11498       caps = gst_caps_new_simple ("audio/x-raw",
11499           "format", G_TYPE_STRING, "F64BE",
11500           "layout", G_TYPE_STRING, "interleaved", NULL);
11501       break;
11502     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
11503       _codec ("Raw 32-bit floating-point audio");
11504       caps = gst_caps_new_simple ("audio/x-raw",
11505           "format", G_TYPE_STRING, "F32BE",
11506           "layout", G_TYPE_STRING, "interleaved", NULL);
11507       break;
11508     case FOURCC_in24:
11509       _codec ("Raw 24-bit PCM audio");
11510       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
11511        * endian later */
11512       caps = gst_caps_new_simple ("audio/x-raw",
11513           "format", G_TYPE_STRING, "S24BE",
11514           "layout", G_TYPE_STRING, "interleaved", NULL);
11515       break;
11516     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
11517       _codec ("Raw 32-bit PCM audio");
11518       caps = gst_caps_new_simple ("audio/x-raw",
11519           "format", G_TYPE_STRING, "S32BE",
11520           "layout", G_TYPE_STRING, "interleaved", NULL);
11521       break;
11522     case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
11523       _codec ("Mu-law audio");
11524       caps = gst_caps_new_empty_simple ("audio/x-mulaw");
11525       break;
11526     case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
11527       _codec ("A-law audio");
11528       caps = gst_caps_new_empty_simple ("audio/x-alaw");
11529       break;
11530     case 0x0200736d:
11531     case 0x6d730002:
11532       _codec ("Microsoft ADPCM");
11533       /* Microsoft ADPCM-ACM code 2 */
11534       caps = gst_caps_new_simple ("audio/x-adpcm",
11535           "layout", G_TYPE_STRING, "microsoft", NULL);
11536       break;
11537     case 0x1100736d:
11538     case 0x6d730011:
11539       _codec ("DVI/IMA ADPCM");
11540       caps = gst_caps_new_simple ("audio/x-adpcm",
11541           "layout", G_TYPE_STRING, "dvi", NULL);
11542       break;
11543     case 0x1700736d:
11544     case 0x6d730017:
11545       _codec ("DVI/Intel IMA ADPCM");
11546       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
11547       caps = gst_caps_new_simple ("audio/x-adpcm",
11548           "layout", G_TYPE_STRING, "quicktime", NULL);
11549       break;
11550     case 0x5500736d:
11551     case 0x6d730055:
11552       /* MPEG layer 3, CBR only (pre QT4.1) */
11553     case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
11554       _codec ("MPEG-1 layer 3");
11555       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
11556       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
11557           "mpegversion", G_TYPE_INT, 1, NULL);
11558       break;
11559     case 0x20736d:
11560     case GST_MAKE_FOURCC ('e', 'c', '-', '3'):
11561       _codec ("EAC-3 audio");
11562       caps = gst_caps_new_simple ("audio/x-eac3",
11563           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11564       stream->sampled = TRUE;
11565       break;
11566     case GST_MAKE_FOURCC ('s', 'a', 'c', '3'): // Nero Recode
11567     case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
11568       _codec ("AC-3 audio");
11569       caps = gst_caps_new_simple ("audio/x-ac3",
11570           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11571       stream->sampled = TRUE;
11572       break;
11573     case GST_MAKE_FOURCC ('d', 't', 's', 'c'):
11574     case GST_MAKE_FOURCC ('D', 'T', 'S', ' '):
11575       _codec ("DTS audio");
11576       caps = gst_caps_new_simple ("audio/x-dts",
11577           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11578       stream->sampled = TRUE;
11579       break;
11580     case GST_MAKE_FOURCC ('d', 't', 's', 'h'): // DTS-HD
11581     case GST_MAKE_FOURCC ('d', 't', 's', 'l'): // DTS-HD Lossless
11582       _codec ("DTS-HD audio");
11583       caps = gst_caps_new_simple ("audio/x-dts",
11584           "framed", G_TYPE_BOOLEAN, TRUE, NULL);
11585       stream->sampled = TRUE;
11586       break;
11587     case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
11588       _codec ("MACE-3");
11589       caps = gst_caps_new_simple ("audio/x-mace",
11590           "maceversion", G_TYPE_INT, 3, NULL);
11591       break;
11592     case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
11593       _codec ("MACE-6");
11594       caps = gst_caps_new_simple ("audio/x-mace",
11595           "maceversion", G_TYPE_INT, 6, NULL);
11596       break;
11597     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
11598       /* ogg/vorbis */
11599       caps = gst_caps_new_empty_simple ("application/ogg");
11600       break;
11601     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
11602       _codec ("DV audio");
11603       caps = gst_caps_new_empty_simple ("audio/x-dv");
11604       break;
11605     case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
11606       _codec ("MPEG-4 AAC audio");
11607       caps = gst_caps_new_simple ("audio/mpeg",
11608           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE,
11609           "stream-format", G_TYPE_STRING, "raw", NULL);
11610       break;
11611     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
11612       _codec ("QDesign Music");
11613       caps = gst_caps_new_empty_simple ("audio/x-qdm");
11614       break;
11615     case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
11616       _codec ("QDesign Music v.2");
11617       /* FIXME: QDesign music version 2 (no constant) */
11618       if (FALSE && data) {
11619         caps = gst_caps_new_simple ("audio/x-qdm2",
11620             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
11621             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
11622             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
11623       } else {
11624         caps = gst_caps_new_empty_simple ("audio/x-qdm2");
11625       }
11626       break;
11627     case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
11628       _codec ("GSM audio");
11629       caps = gst_caps_new_empty_simple ("audio/x-gsm");
11630       break;
11631     case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
11632       _codec ("AMR audio");
11633       caps = gst_caps_new_empty_simple ("audio/AMR");
11634       break;
11635     case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
11636       _codec ("AMR-WB audio");
11637       caps = gst_caps_new_empty_simple ("audio/AMR-WB");
11638       break;
11639     case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
11640       _codec ("Quicktime IMA ADPCM");
11641       caps = gst_caps_new_simple ("audio/x-adpcm",
11642           "layout", G_TYPE_STRING, "quicktime", NULL);
11643       break;
11644     case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
11645       _codec ("Apple lossless audio");
11646       caps = gst_caps_new_empty_simple ("audio/x-alac");
11647       break;
11648     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
11649       _codec ("QualComm PureVoice");
11650       caps = gst_caps_from_string ("audio/qcelp");
11651       break;
11652     case GST_MAKE_FOURCC ('w', 'm', 'a', ' '):
11653     case FOURCC_owma:
11654       _codec ("WMA");
11655       caps = gst_caps_new_empty_simple ("audio/x-wma");
11656       break;
11657     case GST_MAKE_FOURCC ('l', 'p', 'c', 'm'):
11658     {
11659       guint32 flags = 0;
11660       guint32 depth = 0;
11661       guint32 width = 0;
11662       GstAudioFormat format;
11663       enum
11664       {
11665         FLAG_IS_FLOAT = 0x1,
11666         FLAG_IS_BIG_ENDIAN = 0x2,
11667         FLAG_IS_SIGNED = 0x4,
11668         FLAG_IS_PACKED = 0x8,
11669         FLAG_IS_ALIGNED_HIGH = 0x10,
11670         FLAG_IS_NON_INTERLEAVED = 0x20
11671       };
11672       _codec ("Raw LPCM audio");
11673
11674       if (data && len >= 56) {
11675         depth = QT_UINT32 (data + 40);
11676         flags = QT_UINT32 (data + 44);
11677         width = QT_UINT32 (data + 48) * 8 / stream->n_channels;
11678       }
11679       if ((flags & FLAG_IS_FLOAT) == 0) {
11680         if (depth == 0)
11681           depth = 16;
11682         if (width == 0)
11683           width = 16;
11684         format = gst_audio_format_build_integer ((flags & FLAG_IS_SIGNED) ?
11685             TRUE : FALSE, (flags & FLAG_IS_BIG_ENDIAN) ?
11686             G_BIG_ENDIAN : G_LITTLE_ENDIAN, width, depth);
11687         caps = gst_caps_new_simple ("audio/x-raw",
11688             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11689             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11690             "non-interleaved" : "interleaved", NULL);
11691       } else {
11692         if (width == 0)
11693           width = 32;
11694         if (width == 64) {
11695           if (flags & FLAG_IS_BIG_ENDIAN)
11696             format = GST_AUDIO_FORMAT_F64BE;
11697           else
11698             format = GST_AUDIO_FORMAT_F64LE;
11699         } else {
11700           if (flags & FLAG_IS_BIG_ENDIAN)
11701             format = GST_AUDIO_FORMAT_F32BE;
11702           else
11703             format = GST_AUDIO_FORMAT_F32LE;
11704         }
11705         caps = gst_caps_new_simple ("audio/x-raw",
11706             "format", G_TYPE_STRING, gst_audio_format_to_string (format),
11707             "layout", G_TYPE_STRING, (flags & FLAG_IS_NON_INTERLEAVED) ?
11708             "non-interleaved" : "interleaved", NULL);
11709       }
11710       break;
11711     }
11712     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
11713       /* ? */
11714     default:
11715     {
11716       char *s, fourstr[5];
11717
11718       g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11719       s = g_strdup_printf ("audio/x-gst-fourcc-%s", g_strstrip (fourstr));
11720       caps = gst_caps_new_empty_simple (s);
11721       break;
11722     }
11723   }
11724
11725   if (caps) {
11726     GstCaps *templ_caps =
11727         gst_static_pad_template_get_caps (&gst_qtdemux_audiosrc_template);
11728     GstCaps *intersection = gst_caps_intersect (caps, templ_caps);
11729     gst_caps_unref (caps);
11730     gst_caps_unref (templ_caps);
11731     caps = intersection;
11732   }
11733
11734   /* enable clipping for raw audio streams */
11735   s = gst_caps_get_structure (caps, 0);
11736   name = gst_structure_get_name (s);
11737   if (g_str_has_prefix (name, "audio/x-raw")) {
11738     stream->need_clip = TRUE;
11739     stream->max_buffer_size = 4096 * stream->bytes_per_frame;
11740     GST_DEBUG ("setting max buffer size to %d", stream->max_buffer_size);
11741   }
11742   return caps;
11743 }
11744
11745 static GstCaps *
11746 qtdemux_sub_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11747     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11748 {
11749   GstCaps *caps;
11750
11751   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc 0x%08x", GUINT32_TO_BE (fourcc));
11752
11753   switch (fourcc) {
11754     case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
11755       _codec ("DVD subtitle");
11756       caps = gst_caps_new_empty_simple ("subpicture/x-dvd");
11757       stream->need_process = TRUE;
11758       break;
11759     case GST_MAKE_FOURCC ('t', 'e', 'x', 't'):
11760       _codec ("Quicktime timed text");
11761       goto text;
11762     case GST_MAKE_FOURCC ('t', 'x', '3', 'g'):
11763       _codec ("3GPP timed text");
11764     text:
11765       caps = gst_caps_new_simple ("text/x-raw", "format", G_TYPE_STRING,
11766           "utf8", NULL);
11767       /* actual text piece needs to be extracted */
11768       stream->need_process = TRUE;
11769       break;
11770     default:
11771     {
11772       char *s, fourstr[5];
11773
11774       g_snprintf (fourstr, 5, "%" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
11775       s = g_strdup_printf ("text/x-gst-fourcc-%s", g_strstrip (fourstr));
11776       caps = gst_caps_new_empty_simple (s);
11777       break;
11778     }
11779   }
11780   return caps;
11781 }
11782
11783 static GstCaps *
11784 qtdemux_generic_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
11785     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
11786 {
11787   GstCaps *caps;
11788
11789   switch (fourcc) {
11790     case GST_MAKE_FOURCC ('m', '1', 'v', ' '):
11791       _codec ("MPEG 1 video");
11792       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
11793           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
11794       break;
11795     default:
11796       caps = NULL;
11797       break;
11798   }
11799   return caps;
11800 }