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