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