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