gst_plugins_good/gst/qtdemux/qtdemux.c
changeset 16 8e837d1bf446
child 11 1373546e05c6
equal deleted inserted replaced
15:4b0c6ed43234 16:8e837d1bf446
       
     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  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Library General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Library General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Library General Public
       
    18  * License along with this library; if not, write to the
       
    19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    20  * Boston, MA 02111-1307, USA.
       
    21  */
       
    22 
       
    23 /**
       
    24  * SECTION:element-qtdemux
       
    25  *
       
    26  * Demuxes a .mov file into raw or compressed audio and/or video streams.
       
    27  *
       
    28  * This element supports both push and pull-based scheduling, depending on the
       
    29  * capabilities of the upstream elements.
       
    30  *
       
    31  * <refsect2>
       
    32  * <title>Example launch line</title>
       
    33  * |[
       
    34  * gst-launch filesrc location=test.mov ! qtdemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
       
    35  * ]| Play (parse and decode) a .mov file and try to output it to
       
    36  * an automatically detected soundcard and videosink. If the MOV file contains
       
    37  * compressed audio or video data, this will only work if you have the
       
    38  * right decoder elements/plugins installed.
       
    39  * </refsect2>
       
    40  *
       
    41  * Last reviewed on 2006-12-29 (0.10.5)
       
    42  */
       
    43 
       
    44 #ifdef HAVE_CONFIG_H
       
    45 #include "config.h"
       
    46 #endif
       
    47 
       
    48 #include "gst/gst-i18n-plugin.h"
       
    49 
       
    50 #include <gst/tag/tag.h>
       
    51 
       
    52 #include "qtdemux_types.h"
       
    53 #include "qtdemux_dump.h"
       
    54 #include "qtdemux_fourcc.h"
       
    55 #include "qtdemux.h"
       
    56 #include "qtpalette.h"
       
    57 
       
    58 #include <stdlib.h>
       
    59 #include <string.h>
       
    60 
       
    61 #ifdef HAVE_ZLIB
       
    62 # include <zlib.h>
       
    63 #endif
       
    64 
       
    65 /* max. size considered 'sane' for non-mdat atoms */
       
    66 #define QTDEMUX_MAX_ATOM_SIZE (25*1024*1024)
       
    67 
       
    68 GST_DEBUG_CATEGORY (qtdemux_debug);
       
    69 
       
    70 /*typedef struct _QtNode QtNode; */
       
    71 typedef struct _QtDemuxSegment QtDemuxSegment;
       
    72 typedef struct _QtDemuxSample QtDemuxSample;
       
    73 
       
    74 /*struct _QtNode
       
    75 {
       
    76   guint32 type;
       
    77   guint8 *data;
       
    78   gint len;
       
    79 };*/
       
    80 
       
    81 struct _QtDemuxSample
       
    82 {
       
    83   guint32 size;
       
    84   guint64 offset;
       
    85   GstClockTimeDiff pts_offset;  /* Add this value to timestamp to get the pts */
       
    86   guint64 timestamp;            /* In GstClockTime */
       
    87   guint64 duration;             /* in GstClockTime */
       
    88   gboolean keyframe;            /* TRUE when this packet is a keyframe */
       
    89 };
       
    90 
       
    91 /*
       
    92  * Quicktime has tracks and segments. A track is a continuous piece of
       
    93  * multimedia content. The track is not always played from start to finish but
       
    94  * instead, pieces of the track are 'cut out' and played in sequence. This is
       
    95  * what the segments do.
       
    96  *
       
    97  * Inside the track we have keyframes (K) and delta frames. The track has its
       
    98  * own timing, which starts from 0 and extends to end. The position in the track
       
    99  * is called the media_time.
       
   100  *
       
   101  * The segments now describe the pieces that should be played from this track
       
   102  * and are basically tupples of media_time/duration/rate entries. We can have
       
   103  * multiple segments and they are all played after one another. An example:
       
   104  *
       
   105  * segment 1: media_time: 1 second, duration: 1 second, rate 1
       
   106  * segment 2: media_time: 3 second, duration: 2 second, rate 2
       
   107  *
       
   108  * To correctly play back this track, one must play: 1 second of media starting
       
   109  * from media_time 1 followed by 2 seconds of media starting from media_time 3
       
   110  * at a rate of 2.
       
   111  *
       
   112  * Each of the segments will be played at a specific time, the first segment at
       
   113  * time 0, the second one after the duration of the first one, etc.. Note that
       
   114  * the time in resulting playback is not identical to the media_time of the
       
   115  * track anymore.
       
   116  *
       
   117  * Visually, assuming the track has 4 second of media_time:
       
   118  *
       
   119  *                (a)                   (b)          (c)              (d)
       
   120  *         .-----------------------------------------------------------.
       
   121  * track:  | K.....K.........K........K.......K.......K...........K... |
       
   122  *         '-----------------------------------------------------------'
       
   123  *         0              1              2              3              4    
       
   124  *           .------------^              ^   .----------^              ^
       
   125  *          /              .-------------'  /       .------------------'
       
   126  *         /              /          .-----'       /
       
   127  *         .--------------.         .--------------.
       
   128  *         | segment 1    |         | segment 2    |
       
   129  *         '--------------'         '--------------'
       
   130  *       
       
   131  * The challenge here is to cut out the right pieces of the track for each of
       
   132  * the playback segments. This fortunatly can easily be done with the SEGMENT
       
   133  * events of gstreamer.
       
   134  *
       
   135  * For playback of segment 1, we need to provide the decoder with the keyframe
       
   136  * (a), in the above figure, but we must instruct it only to output the decoded
       
   137  * data between second 1 and 2. We do this with a SEGMENT event for 1 to 2, time
       
   138  * position set to the time of the segment: 0.
       
   139  *
       
   140  * We then proceed to push data from keyframe (a) to frame (b). The decoder
       
   141  * decodes but clips all before media_time 1.
       
   142  * 
       
   143  * After finishing a segment, we push out a new SEGMENT event with the clipping
       
   144  * boundaries of the new data.
       
   145  *
       
   146  * This is a good usecase for the GStreamer accumulated SEGMENT events.
       
   147  */
       
   148 
       
   149 struct _QtDemuxSegment
       
   150 {
       
   151   /* global time and duration, all gst time */
       
   152   guint64 time;
       
   153   guint64 stop_time;
       
   154   guint64 duration;
       
   155   /* media time of trak, all gst time */
       
   156   guint64 media_start;
       
   157   guint64 media_stop;
       
   158   gdouble rate;
       
   159 };
       
   160 
       
   161 struct _QtDemuxStream
       
   162 {
       
   163   GstPad *pad;
       
   164 
       
   165   /* stream type */
       
   166   guint32 subtype;
       
   167   GstCaps *caps;
       
   168   guint32 fourcc;
       
   169 
       
   170   /* duration/scale */
       
   171   guint64 duration;             /* in timescale */
       
   172   guint32 timescale;
       
   173 
       
   174   /* our samples */
       
   175   guint32 n_samples;
       
   176   QtDemuxSample *samples;
       
   177   gboolean all_keyframe;        /* TRUE when all samples are keyframes (no stss) */
       
   178   guint32 min_duration;         /* duration in timescale of first sample, used for figuring out
       
   179                                    the framerate, in timescale units */
       
   180 
       
   181   /* if we use chunks or samples */
       
   182   gboolean sampled;
       
   183   guint padding;
       
   184 
       
   185   /* video info */
       
   186   gint width;
       
   187   gint height;
       
   188   /* aspect ratio */
       
   189   gint display_width;
       
   190   gint display_height;
       
   191   gint par_w;
       
   192   gint par_h;
       
   193   /* Numerator/denominator framerate */
       
   194   gint fps_n;
       
   195   gint fps_d;
       
   196   guint16 bits_per_sample;
       
   197   guint16 color_table_id;
       
   198 
       
   199   /* audio info */
       
   200   gdouble rate;
       
   201   gint n_channels;
       
   202   guint samples_per_packet;
       
   203   guint samples_per_frame;
       
   204   guint bytes_per_packet;
       
   205   guint bytes_per_sample;
       
   206   guint bytes_per_frame;
       
   207   guint compression;
       
   208 
       
   209   /* when a discontinuity is pending */
       
   210   gboolean discont;
       
   211 
       
   212   /* list of buffers to push first */
       
   213   GSList *buffers;
       
   214 
       
   215   /* if we need to clip this buffer. This is only needed for uncompressed
       
   216    * data */
       
   217   gboolean need_clip;
       
   218 
       
   219   /* current position */
       
   220   guint32 segment_index;
       
   221   guint32 sample_index;
       
   222   guint64 time_position;        /* in gst time */
       
   223 
       
   224   /* the Gst segment we are processing out, used for clipping */
       
   225   GstSegment segment;
       
   226 
       
   227   /* last GstFlowReturn */
       
   228   GstFlowReturn last_ret;
       
   229 
       
   230   /* quicktime segments */
       
   231   guint32 n_segments;
       
   232   QtDemuxSegment *segments;
       
   233   guint32 from_sample;
       
   234   guint32 to_sample;
       
   235 
       
   236   gboolean sent_eos;
       
   237 };
       
   238 
       
   239 enum QtDemuxState
       
   240 {
       
   241   QTDEMUX_STATE_INITIAL,        /* Initial state (haven't got the header yet) */
       
   242   QTDEMUX_STATE_HEADER,         /* Parsing the header */
       
   243   QTDEMUX_STATE_MOVIE,          /* Parsing/Playing the media data */
       
   244   QTDEMUX_STATE_BUFFER_MDAT     /* Buffering the mdat atom */
       
   245 };
       
   246 
       
   247 static GNode *qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc);
       
   248 static GNode *qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc);
       
   249 
       
   250 static const GstElementDetails gst_qtdemux_details =
       
   251 GST_ELEMENT_DETAILS ("QuickTime demuxer",
       
   252     "Codec/Demuxer",
       
   253     "Demultiplex a QuickTime file into audio and video streams",
       
   254     "David Schleef <ds@schleef.org>, Wim Taymans <wim@fluendo.com>");
       
   255 
       
   256 static GstStaticPadTemplate gst_qtdemux_sink_template =
       
   257     GST_STATIC_PAD_TEMPLATE ("sink",
       
   258     GST_PAD_SINK,
       
   259     GST_PAD_ALWAYS,
       
   260     GST_STATIC_CAPS ("video/quicktime; video/mj2; audio/x-m4a; "
       
   261         "application/x-3gp")
       
   262     );
       
   263 
       
   264 static GstStaticPadTemplate gst_qtdemux_videosrc_template =
       
   265 GST_STATIC_PAD_TEMPLATE ("video_%02d",
       
   266     GST_PAD_SRC,
       
   267     GST_PAD_SOMETIMES,
       
   268     GST_STATIC_CAPS_ANY);
       
   269 
       
   270 static GstStaticPadTemplate gst_qtdemux_audiosrc_template =
       
   271 GST_STATIC_PAD_TEMPLATE ("audio_%02d",
       
   272     GST_PAD_SRC,
       
   273     GST_PAD_SOMETIMES,
       
   274     GST_STATIC_CAPS_ANY);
       
   275 
       
   276 static GstStaticPadTemplate gst_qtdemux_subpsrc_template =
       
   277 GST_STATIC_PAD_TEMPLATE ("subp_%02d",
       
   278     GST_PAD_SRC,
       
   279     GST_PAD_SOMETIMES,
       
   280     GST_STATIC_CAPS_ANY);
       
   281 
       
   282 static GstElementClass *parent_class = NULL;
       
   283 
       
   284 static void gst_qtdemux_class_init (GstQTDemuxClass * klass);
       
   285 static void gst_qtdemux_base_init (GstQTDemuxClass * klass);
       
   286 static void gst_qtdemux_init (GstQTDemux * quicktime_demux);
       
   287 static void gst_qtdemux_dispose (GObject * object);
       
   288 
       
   289 static GstStateChangeReturn gst_qtdemux_change_state (GstElement * element,
       
   290     GstStateChange transition);
       
   291 static gboolean qtdemux_sink_activate (GstPad * sinkpad);
       
   292 static gboolean qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active);
       
   293 static gboolean qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active);
       
   294 
       
   295 static void gst_qtdemux_loop (GstPad * pad);
       
   296 static GstFlowReturn gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf);
       
   297 static gboolean gst_qtdemux_handle_sink_event (GstPad * pad, GstEvent * event);
       
   298 
       
   299 static gboolean qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer,
       
   300     int length);
       
   301 static gboolean qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node,
       
   302     const guint8 * buffer, int length);
       
   303 static gboolean qtdemux_parse_tree (GstQTDemux * qtdemux);
       
   304 
       
   305 static void gst_qtdemux_handle_esds (GstQTDemux * qtdemux,
       
   306     QtDemuxStream * stream, GNode * esds, GstTagList * list);
       
   307 static GstCaps *qtdemux_video_caps (GstQTDemux * qtdemux,
       
   308     QtDemuxStream * stream, guint32 fourcc, const guint8 * stsd_data,
       
   309     gchar ** codec_name);
       
   310 static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
       
   311     QtDemuxStream * stream, guint32 fourcc, const guint8 * data, int len,
       
   312     gchar ** codec_name);
       
   313 static GstCaps *qtdemux_subp_caps (GstQTDemux * qtdemux,
       
   314     QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
       
   315     gchar ** codec_name);
       
   316 
       
   317 GType
       
   318 gst_qtdemux_get_type (void)
       
   319 {
       
   320   static GType qtdemux_type = 0;
       
   321 
       
   322   if (G_UNLIKELY (!qtdemux_type)) {
       
   323     static const GTypeInfo qtdemux_info = {
       
   324       sizeof (GstQTDemuxClass),
       
   325       (GBaseInitFunc) gst_qtdemux_base_init, NULL,
       
   326       (GClassInitFunc) gst_qtdemux_class_init,
       
   327       NULL, NULL, sizeof (GstQTDemux), 0,
       
   328       (GInstanceInitFunc) gst_qtdemux_init,
       
   329     };
       
   330 
       
   331     qtdemux_type =
       
   332         g_type_register_static (GST_TYPE_ELEMENT, "GstQTDemux", &qtdemux_info,
       
   333         0);
       
   334   }
       
   335   return qtdemux_type;
       
   336 }
       
   337 
       
   338 static void
       
   339 gst_qtdemux_base_init (GstQTDemuxClass * klass)
       
   340 {
       
   341   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
       
   342 
       
   343   gst_element_class_add_pad_template (element_class,
       
   344       gst_static_pad_template_get (&gst_qtdemux_sink_template));
       
   345   gst_element_class_add_pad_template (element_class,
       
   346       gst_static_pad_template_get (&gst_qtdemux_videosrc_template));
       
   347   gst_element_class_add_pad_template (element_class,
       
   348       gst_static_pad_template_get (&gst_qtdemux_audiosrc_template));
       
   349   gst_element_class_set_details (element_class, &gst_qtdemux_details);
       
   350 
       
   351   GST_DEBUG_CATEGORY_INIT (qtdemux_debug, "qtdemux", 0, "qtdemux plugin");
       
   352 }
       
   353 
       
   354 static void
       
   355 gst_qtdemux_class_init (GstQTDemuxClass * klass)
       
   356 {
       
   357   GObjectClass *gobject_class;
       
   358   GstElementClass *gstelement_class;
       
   359 
       
   360   gobject_class = (GObjectClass *) klass;
       
   361   gstelement_class = (GstElementClass *) klass;
       
   362 
       
   363   parent_class = g_type_class_peek_parent (klass);
       
   364 
       
   365   gobject_class->dispose = gst_qtdemux_dispose;
       
   366 
       
   367   gstelement_class->change_state = gst_qtdemux_change_state;
       
   368 }
       
   369 
       
   370 static void
       
   371 gst_qtdemux_init (GstQTDemux * qtdemux)
       
   372 {
       
   373   qtdemux->sinkpad =
       
   374       gst_pad_new_from_static_template (&gst_qtdemux_sink_template, "sink");
       
   375   gst_pad_set_activate_function (qtdemux->sinkpad, qtdemux_sink_activate);
       
   376   gst_pad_set_activatepull_function (qtdemux->sinkpad,
       
   377       qtdemux_sink_activate_pull);
       
   378   gst_pad_set_activatepush_function (qtdemux->sinkpad,
       
   379       qtdemux_sink_activate_push);
       
   380   gst_pad_set_chain_function (qtdemux->sinkpad, gst_qtdemux_chain);
       
   381   gst_pad_set_event_function (qtdemux->sinkpad, gst_qtdemux_handle_sink_event);
       
   382   gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), qtdemux->sinkpad);
       
   383 
       
   384   qtdemux->state = QTDEMUX_STATE_INITIAL;
       
   385   /* FIXME, use segment last_stop for this */
       
   386   qtdemux->last_ts = GST_CLOCK_TIME_NONE;
       
   387   qtdemux->pullbased = FALSE;
       
   388   qtdemux->neededbytes = 16;
       
   389   qtdemux->todrop = 0;
       
   390   qtdemux->adapter = gst_adapter_new ();
       
   391   qtdemux->offset = 0;
       
   392   qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
       
   393   qtdemux->mdatbuffer = NULL;
       
   394   gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
       
   395 }
       
   396 
       
   397 static void
       
   398 gst_qtdemux_dispose (GObject * object)
       
   399 {
       
   400   GstQTDemux *qtdemux = GST_QTDEMUX (object);
       
   401 
       
   402   if (qtdemux->adapter) {
       
   403     g_object_unref (G_OBJECT (qtdemux->adapter));
       
   404     qtdemux->adapter = NULL;
       
   405   }
       
   406 
       
   407   G_OBJECT_CLASS (parent_class)->dispose (object);
       
   408 }
       
   409 
       
   410 static GstFlowReturn
       
   411 gst_qtdemux_pull_atom (GstQTDemux * qtdemux, guint64 offset, guint64 size,
       
   412     GstBuffer ** buf)
       
   413 {
       
   414   GstFlowReturn flow;
       
   415 
       
   416   /* Sanity check: catch bogus sizes (fuzzed/broken files) */
       
   417   if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
       
   418     GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
       
   419         (_("This file is invalid and cannot be played.")),
       
   420         ("atom has bogus size %" G_GUINT64_FORMAT, size));
       
   421     return GST_FLOW_ERROR;
       
   422   }
       
   423 
       
   424   flow = gst_pad_pull_range (qtdemux->sinkpad, offset, size, buf);
       
   425 
       
   426   if (G_UNLIKELY (flow != GST_FLOW_OK))
       
   427     return flow;
       
   428 
       
   429   /* Catch short reads - we don't want any partial atoms */
       
   430   if (G_UNLIKELY (GST_BUFFER_SIZE (*buf) < size)) {
       
   431     GST_WARNING_OBJECT (qtdemux, "short read: %u < %" G_GUINT64_FORMAT,
       
   432         GST_BUFFER_SIZE (*buf), size);
       
   433     gst_buffer_unref (*buf);
       
   434     *buf = NULL;
       
   435     return GST_FLOW_UNEXPECTED;
       
   436   }
       
   437 
       
   438   return flow;
       
   439 }
       
   440 
       
   441 #if 0
       
   442 static gboolean
       
   443 gst_qtdemux_src_convert (GstPad * pad, GstFormat src_format, gint64 src_value,
       
   444     GstFormat * dest_format, gint64 * dest_value)
       
   445 {
       
   446   gboolean res = TRUE;
       
   447   QtDemuxStream *stream = gst_pad_get_element_private (pad);
       
   448 
       
   449   if (stream->subtype == GST_MAKE_FOURCC ('v', 'i', 'd', 'e') &&
       
   450       (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
       
   451     return FALSE;
       
   452 
       
   453   switch (src_format) {
       
   454     case GST_FORMAT_TIME:
       
   455       switch (*dest_format) {
       
   456         case GST_FORMAT_BYTES:
       
   457           *dest_value = src_value * 1;  /* FIXME */
       
   458           break;
       
   459         case GST_FORMAT_DEFAULT:
       
   460           *dest_value = src_value * 1;  /* FIXME */
       
   461           break;
       
   462         default:
       
   463           res = FALSE;
       
   464           break;
       
   465       }
       
   466       break;
       
   467     case GST_FORMAT_BYTES:
       
   468       switch (*dest_format) {
       
   469         case GST_FORMAT_TIME:
       
   470           *dest_value = src_value * 1;  /* FIXME */
       
   471           break;
       
   472         default:
       
   473           res = FALSE;
       
   474           break;
       
   475       }
       
   476       break;
       
   477     case GST_FORMAT_DEFAULT:
       
   478       switch (*dest_format) {
       
   479         case GST_FORMAT_TIME:
       
   480           *dest_value = src_value * 1;  /* FIXME */
       
   481           break;
       
   482         default:
       
   483           res = FALSE;
       
   484           break;
       
   485       }
       
   486       break;
       
   487     default:
       
   488       res = FALSE;
       
   489   }
       
   490 
       
   491   return res;
       
   492 }
       
   493 #endif
       
   494 
       
   495 static const GstQueryType *
       
   496 gst_qtdemux_get_src_query_types (GstPad * pad)
       
   497 {
       
   498   static const GstQueryType src_types[] = {
       
   499     GST_QUERY_POSITION,
       
   500     GST_QUERY_DURATION,
       
   501     GST_QUERY_SEEKING,
       
   502     0
       
   503   };
       
   504 
       
   505   return src_types;
       
   506 }
       
   507 
       
   508 static gboolean
       
   509 gst_qtdemux_get_duration (GstQTDemux * qtdemux, gint64 * duration)
       
   510 {
       
   511   gboolean res = TRUE;
       
   512 
       
   513   *duration = GST_CLOCK_TIME_NONE;
       
   514 
       
   515   if (qtdemux->duration != 0) {
       
   516     if (qtdemux->duration != G_MAXINT32 && qtdemux->timescale != 0) {
       
   517       *duration = gst_util_uint64_scale (qtdemux->duration,
       
   518           GST_SECOND, qtdemux->timescale);
       
   519     }
       
   520   }
       
   521   return res;
       
   522 }
       
   523 
       
   524 static gboolean
       
   525 gst_qtdemux_handle_src_query (GstPad * pad, GstQuery * query)
       
   526 {
       
   527   gboolean res = FALSE;
       
   528   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
       
   529 
       
   530   GST_LOG_OBJECT (pad, "%s query", GST_QUERY_TYPE_NAME (query));
       
   531 
       
   532   switch (GST_QUERY_TYPE (query)) {
       
   533     case GST_QUERY_POSITION:
       
   534       if (GST_CLOCK_TIME_IS_VALID (qtdemux->segment.last_stop)) {
       
   535         gst_query_set_position (query, GST_FORMAT_TIME,
       
   536             qtdemux->segment.last_stop);
       
   537         res = TRUE;
       
   538       }
       
   539       break;
       
   540     case GST_QUERY_DURATION:{
       
   541       GstFormat fmt;
       
   542 
       
   543       gst_query_parse_duration (query, &fmt, NULL);
       
   544       if (fmt == GST_FORMAT_TIME) {
       
   545         gint64 duration = -1;
       
   546 
       
   547         gst_qtdemux_get_duration (qtdemux, &duration);
       
   548         if (duration > 0) {
       
   549           gst_query_set_duration (query, GST_FORMAT_TIME, duration);
       
   550           res = TRUE;
       
   551         }
       
   552       }
       
   553       break;
       
   554     }
       
   555     case GST_QUERY_SEEKING:{
       
   556       GstFormat fmt;
       
   557       gboolean seekable;
       
   558 
       
   559       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
       
   560       if (fmt == GST_FORMAT_TIME) {
       
   561         gint64 duration = -1;
       
   562 
       
   563         gst_qtdemux_get_duration (qtdemux, &duration);
       
   564         seekable = TRUE;
       
   565         if (!qtdemux->pullbased) {
       
   566           GstQuery *q;
       
   567 
       
   568           /* we might be able with help from upstream */
       
   569           seekable = FALSE;
       
   570           q = gst_query_new_seeking (GST_FORMAT_BYTES);
       
   571           if (gst_pad_peer_query (qtdemux->sinkpad, q)) {
       
   572             gst_query_parse_seeking (q, &fmt, &seekable, NULL, NULL);
       
   573             GST_LOG_OBJECT (qtdemux, "upstream BYTE seekable %d", seekable);
       
   574           }
       
   575           gst_query_unref (q);
       
   576         }
       
   577         gst_query_set_seeking (query, GST_FORMAT_TIME, seekable, 0, duration);
       
   578         res = TRUE;
       
   579       }
       
   580       break;
       
   581     }
       
   582     default:
       
   583       res = gst_pad_query_default (pad, query);
       
   584       break;
       
   585   }
       
   586 
       
   587   gst_object_unref (qtdemux);
       
   588 
       
   589   return res;
       
   590 }
       
   591 
       
   592 /* push event on all source pads; takes ownership of the event */
       
   593 static void
       
   594 gst_qtdemux_push_event (GstQTDemux * qtdemux, GstEvent * event)
       
   595 {
       
   596   guint n;
       
   597 
       
   598   GST_DEBUG_OBJECT (qtdemux, "pushing %s event on all source pads",
       
   599       GST_EVENT_TYPE_NAME (event));
       
   600 
       
   601   for (n = 0; n < qtdemux->n_streams; n++) {
       
   602     GstPad *pad;
       
   603 
       
   604     if ((pad = qtdemux->streams[n]->pad))
       
   605       gst_pad_push_event (pad, gst_event_ref (event));
       
   606   }
       
   607   gst_event_unref (event);
       
   608 }
       
   609 
       
   610 /* push a pending newsegment event, if any from the streaming thread */
       
   611 static void
       
   612 gst_qtdemux_push_pending_newsegment (GstQTDemux * qtdemux)
       
   613 {
       
   614   if (qtdemux->pending_newsegment) {
       
   615     gst_qtdemux_push_event (qtdemux, qtdemux->pending_newsegment);
       
   616     qtdemux->pending_newsegment = NULL;
       
   617   }
       
   618 }
       
   619 
       
   620 typedef struct
       
   621 {
       
   622   guint64 media_time;
       
   623 } FindData;
       
   624 
       
   625 static gint
       
   626 find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
       
   627 {
       
   628   if (s1->timestamp > *media_time)
       
   629     return 1;
       
   630 
       
   631   return -1;
       
   632 }
       
   633 
       
   634 /* find the index of the sample that includes the data for @media_time
       
   635  *
       
   636  * Returns the index of the sample.
       
   637  */
       
   638 static guint32
       
   639 gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
       
   640     guint64 media_time)
       
   641 {
       
   642   QtDemuxSample *result;
       
   643   guint32 index;
       
   644 
       
   645   result = gst_util_array_binary_search (str->samples, str->n_samples,
       
   646       sizeof (QtDemuxSample), (GCompareDataFunc) find_func,
       
   647       GST_SEARCH_MODE_BEFORE, &media_time, NULL);
       
   648 
       
   649   if (G_LIKELY (result))
       
   650     index = result - str->samples;
       
   651   else
       
   652     index = 0;
       
   653 
       
   654   return index;
       
   655 }
       
   656 
       
   657 /* find the index of the keyframe needed to decode the sample at @index
       
   658  * of stream @str.
       
   659  *
       
   660  * Returns the index of the keyframe.
       
   661  */
       
   662 static guint32
       
   663 gst_qtdemux_find_keyframe (GstQTDemux * qtdemux, QtDemuxStream * str,
       
   664     guint32 index)
       
   665 {
       
   666   guint32 new_index = index;
       
   667 
       
   668   if (index >= str->n_samples) {
       
   669     new_index = str->n_samples;
       
   670     goto beach;
       
   671   }
       
   672 
       
   673   /* all keyframes, return index */
       
   674   if (str->all_keyframe) {
       
   675     new_index = index;
       
   676     goto beach;
       
   677   }
       
   678 
       
   679   /* else go back until we have a keyframe */
       
   680   while (TRUE) {
       
   681     if (str->samples[new_index].keyframe)
       
   682       break;
       
   683 
       
   684     if (new_index == 0)
       
   685       break;
       
   686 
       
   687     new_index--;
       
   688   }
       
   689 
       
   690 beach:
       
   691   GST_DEBUG_OBJECT (qtdemux, "searching for keyframe index before index %u "
       
   692       "gave %u", index, new_index);
       
   693 
       
   694   return new_index;
       
   695 }
       
   696 
       
   697 /* find the segment for @time_position for @stream
       
   698  *
       
   699  * Returns -1 if the segment cannot be found.
       
   700  */
       
   701 static guint32
       
   702 gst_qtdemux_find_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
   703     guint64 time_position)
       
   704 {
       
   705   gint i;
       
   706   guint32 seg_idx;
       
   707 
       
   708   GST_LOG_OBJECT (qtdemux, "finding segment for %" GST_TIME_FORMAT,
       
   709       GST_TIME_ARGS (time_position));
       
   710 
       
   711   /* find segment corresponding to time_position if we are looking
       
   712    * for a segment. */
       
   713   seg_idx = -1;
       
   714   for (i = 0; i < stream->n_segments; i++) {
       
   715     QtDemuxSegment *segment = &stream->segments[i];
       
   716 
       
   717     GST_LOG_OBJECT (qtdemux,
       
   718         "looking at segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
       
   719         GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->stop_time));
       
   720 
       
   721     /* For the last segment we include stop_time in the last segment */
       
   722     if (i < stream->n_segments - 1) {
       
   723       if (segment->time <= time_position && time_position < segment->stop_time) {
       
   724         GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
       
   725         seg_idx = i;
       
   726         break;
       
   727       }
       
   728     } else {
       
   729       if (segment->time <= time_position && time_position <= segment->stop_time) {
       
   730         GST_LOG_OBJECT (qtdemux, "segment %d matches", i);
       
   731         seg_idx = i;
       
   732         break;
       
   733       }
       
   734     }
       
   735   }
       
   736   return seg_idx;
       
   737 }
       
   738 
       
   739 /* move the stream @str to the sample position @index.
       
   740  *
       
   741  * Updates @str->sample_index and marks discontinuity if needed.
       
   742  */
       
   743 static void
       
   744 gst_qtdemux_move_stream (GstQTDemux * qtdemux, QtDemuxStream * str,
       
   745     guint32 index)
       
   746 {
       
   747   /* no change needed */
       
   748   if (index == str->sample_index)
       
   749     return;
       
   750 
       
   751   GST_DEBUG_OBJECT (qtdemux, "moving to sample %u of %u", index,
       
   752       str->n_samples);
       
   753 
       
   754   /* position changed, we have a discont */
       
   755   str->sample_index = index;
       
   756   /* Each time we move in the stream we store the position where we are 
       
   757    * starting from */
       
   758   str->from_sample = index;
       
   759   str->discont = TRUE;
       
   760 }
       
   761 
       
   762 static void
       
   763 gst_qtdemux_adjust_seek (GstQTDemux * qtdemux, gint64 desired_time,
       
   764     gint64 * key_time, gint64 * key_offset)
       
   765 {
       
   766   guint64 min_offset;
       
   767   gint64 min_byte_offset = -1;
       
   768   gint n;
       
   769 
       
   770   min_offset = desired_time;
       
   771 
       
   772   /* for each stream, find the index of the sample in the segment
       
   773    * and move back to the previous keyframe. */
       
   774   for (n = 0; n < qtdemux->n_streams; n++) {
       
   775     QtDemuxStream *str;
       
   776     guint32 index, kindex;
       
   777     guint32 seg_idx;
       
   778     guint64 media_start;
       
   779     guint64 media_time;
       
   780     guint64 seg_time;
       
   781     QtDemuxSegment *seg;
       
   782 
       
   783     str = qtdemux->streams[n];
       
   784 
       
   785     seg_idx = gst_qtdemux_find_segment (qtdemux, str, desired_time);
       
   786     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
       
   787 
       
   788     /* segment not found, continue with normal flow */
       
   789     if (seg_idx == -1)
       
   790       continue;
       
   791 
       
   792     /* get segment and time in the segment */
       
   793     seg = &str->segments[seg_idx];
       
   794     seg_time = desired_time - seg->time;
       
   795 
       
   796     /* get the media time in the segment */
       
   797     media_start = seg->media_start + seg_time;
       
   798 
       
   799     /* get the index of the sample with media time */
       
   800     index = gst_qtdemux_find_index (qtdemux, str, media_start);
       
   801     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
       
   802         GST_TIME_ARGS (media_start), index);
       
   803 
       
   804     /* find previous keyframe */
       
   805     kindex = gst_qtdemux_find_keyframe (qtdemux, str, index);
       
   806 
       
   807     /* if the keyframe is at a different position, we need to update the
       
   808      * requested seek time */
       
   809     if (index != kindex) {
       
   810       index = kindex;
       
   811 
       
   812       /* get timestamp of keyframe */
       
   813       media_time = str->samples[kindex].timestamp;
       
   814       GST_DEBUG_OBJECT (qtdemux, "keyframe at %u with time %" GST_TIME_FORMAT,
       
   815           kindex, GST_TIME_ARGS (media_time));
       
   816 
       
   817       /* keyframes in the segment get a chance to change the
       
   818        * desired_offset. keyframes out of the segment are
       
   819        * ignored. */
       
   820       if (media_time >= seg->media_start) {
       
   821         guint64 seg_time;
       
   822 
       
   823         /* this keyframe is inside the segment, convert back to
       
   824          * segment time */
       
   825         seg_time = (media_time - seg->media_start) + seg->time;
       
   826         if (seg_time < min_offset)
       
   827           min_offset = seg_time;
       
   828       }
       
   829     }
       
   830 
       
   831     if (min_byte_offset < 0 || str->samples[index].offset < min_byte_offset)
       
   832       min_byte_offset = str->samples[index].offset;
       
   833   }
       
   834 
       
   835   if (key_time)
       
   836     *key_time = min_offset;
       
   837   if (key_offset)
       
   838     *key_offset = min_byte_offset;
       
   839 }
       
   840 
       
   841 static gboolean
       
   842 gst_qtdemux_convert_seek (GstPad * pad, GstFormat * format,
       
   843     GstSeekType cur_type, gint64 * cur, GstSeekType stop_type, gint64 * stop)
       
   844 {
       
   845   gboolean res;
       
   846   GstFormat fmt;
       
   847 
       
   848   g_return_val_if_fail (format != NULL, FALSE);
       
   849   g_return_val_if_fail (cur != NULL, FALSE);
       
   850   g_return_val_if_fail (stop != NULL, FALSE);
       
   851 
       
   852   if (*format == GST_FORMAT_TIME)
       
   853     return TRUE;
       
   854 
       
   855   fmt = GST_FORMAT_TIME;
       
   856   res = TRUE;
       
   857   if (cur_type != GST_SEEK_TYPE_NONE)
       
   858     res = gst_pad_query_convert (pad, *format, *cur, &fmt, cur);
       
   859   if (res && stop_type != GST_SEEK_TYPE_NONE)
       
   860     res = gst_pad_query_convert (pad, *format, *stop, &fmt, stop);
       
   861 
       
   862   if (res)
       
   863     *format = GST_FORMAT_TIME;
       
   864 
       
   865   return res;
       
   866 }
       
   867 
       
   868 /* perform seek in push based mode:
       
   869    find BYTE position to move to based on time and delegate to upstream
       
   870 */
       
   871 static gboolean
       
   872 gst_qtdemux_do_push_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
       
   873 {
       
   874   gdouble rate;
       
   875   GstFormat format;
       
   876   GstSeekFlags flags;
       
   877   GstSeekType cur_type, stop_type;
       
   878   gint64 cur, stop;
       
   879   gboolean res;
       
   880   gint64 byte_cur;
       
   881 
       
   882   GST_DEBUG_OBJECT (qtdemux, "doing push-based seek");
       
   883 
       
   884   gst_event_parse_seek (event, &rate, &format, &flags,
       
   885       &cur_type, &cur, &stop_type, &stop);
       
   886 
       
   887   if (stop_type != GST_SEEK_TYPE_NONE)
       
   888     goto unsupported_seek;
       
   889   stop = -1;
       
   890 
       
   891   /* only forward streaming and seeking is possible */
       
   892   if (rate <= 0)
       
   893     goto unsupported_seek;
       
   894 
       
   895   /* convert to TIME if needed and possible */
       
   896   if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
       
   897           stop_type, &stop))
       
   898     goto no_format;
       
   899 
       
   900   /* find reasonable corresponding BYTE position,
       
   901    * also try to mind about keyframes, since we can not go back a bit for them
       
   902    * later on */
       
   903   gst_qtdemux_adjust_seek (qtdemux, cur, NULL, &byte_cur);
       
   904 
       
   905   if (byte_cur == -1)
       
   906     goto abort_seek;
       
   907 
       
   908   GST_DEBUG_OBJECT (qtdemux, "Pushing BYTE seek rate %g, "
       
   909       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
       
   910       stop);
       
   911   /* BYTE seek event */
       
   912   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
       
   913       stop_type, stop);
       
   914   res = gst_pad_push_event (qtdemux->sinkpad, event);
       
   915 
       
   916   return res;
       
   917 
       
   918   /* ERRORS */
       
   919 abort_seek:
       
   920   {
       
   921     GST_DEBUG_OBJECT (qtdemux, "could not determine byte position to seek to, "
       
   922         "seek aborted.");
       
   923     return FALSE;
       
   924   }
       
   925 unsupported_seek:
       
   926   {
       
   927     GST_DEBUG_OBJECT (qtdemux, "unsupported seek, seek aborted.");
       
   928     return FALSE;
       
   929   }
       
   930 no_format:
       
   931   {
       
   932     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
       
   933     return FALSE;
       
   934   }
       
   935 }
       
   936 
       
   937 /* perform the seek.
       
   938  *
       
   939  * We set all segment_indexes in the streams to unknown and
       
   940  * adjust the time_position to the desired position. this is enough
       
   941  * to trigger a segment switch in the streaming thread to start
       
   942  * streaming from the desired position.
       
   943  *
       
   944  * Keyframe seeking is a little more complicated when dealing with
       
   945  * segments. Ideally we want to move to the previous keyframe in
       
   946  * the segment but there might not be a keyframe in the segment. In
       
   947  * fact, none of the segments could contain a keyframe. We take a
       
   948  * practical approach: seek to the previous keyframe in the segment,
       
   949  * if there is none, seek to the beginning of the segment.
       
   950  *
       
   951  * Called with STREAM_LOCK
       
   952  */
       
   953 static gboolean
       
   954 gst_qtdemux_perform_seek (GstQTDemux * qtdemux, GstSegment * segment)
       
   955 {
       
   956   gint64 desired_offset;
       
   957   gint n;
       
   958 
       
   959   desired_offset = segment->last_stop;
       
   960 
       
   961   GST_DEBUG_OBJECT (qtdemux, "seeking to %" GST_TIME_FORMAT,
       
   962       GST_TIME_ARGS (desired_offset));
       
   963 
       
   964   if (segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
       
   965     gint64 min_offset;
       
   966 
       
   967     gst_qtdemux_adjust_seek (qtdemux, desired_offset, &min_offset, NULL);
       
   968     GST_DEBUG_OBJECT (qtdemux, "keyframe seek, align to %"
       
   969         GST_TIME_FORMAT, GST_TIME_ARGS (min_offset));
       
   970     desired_offset = min_offset;
       
   971   }
       
   972 
       
   973   /* and set all streams to the final position */
       
   974   for (n = 0; n < qtdemux->n_streams; n++) {
       
   975     QtDemuxStream *stream = qtdemux->streams[n];
       
   976 
       
   977     stream->time_position = desired_offset;
       
   978     stream->sample_index = -1;
       
   979     stream->segment_index = -1;
       
   980     stream->last_ret = GST_FLOW_OK;
       
   981     stream->sent_eos = FALSE;
       
   982   }
       
   983   segment->last_stop = desired_offset;
       
   984   segment->time = desired_offset;
       
   985 
       
   986   /* we stop at the end */
       
   987   if (segment->stop == -1)
       
   988     segment->stop = segment->duration;
       
   989 
       
   990   return TRUE;
       
   991 }
       
   992 
       
   993 /* do a seek in pull based mode */
       
   994 static gboolean
       
   995 gst_qtdemux_do_seek (GstQTDemux * qtdemux, GstPad * pad, GstEvent * event)
       
   996 {
       
   997   gdouble rate;
       
   998   GstFormat format;
       
   999   GstSeekFlags flags;
       
  1000   GstSeekType cur_type, stop_type;
       
  1001   gint64 cur, stop;
       
  1002   gboolean flush;
       
  1003   gboolean update;
       
  1004   GstSegment seeksegment;
       
  1005   int i;
       
  1006 
       
  1007   if (event) {
       
  1008     GST_DEBUG_OBJECT (qtdemux, "doing seek with event");
       
  1009 
       
  1010     gst_event_parse_seek (event, &rate, &format, &flags,
       
  1011         &cur_type, &cur, &stop_type, &stop);
       
  1012 
       
  1013     /* we have to have a format as the segment format. Try to convert
       
  1014      * if not. */
       
  1015     if (!gst_qtdemux_convert_seek (pad, &format, cur_type, &cur,
       
  1016             stop_type, &stop))
       
  1017       goto no_format;
       
  1018 
       
  1019     GST_DEBUG_OBJECT (qtdemux, "seek format %s", gst_format_get_name (format));
       
  1020   } else {
       
  1021     GST_DEBUG_OBJECT (qtdemux, "doing seek without event");
       
  1022     flags = 0;
       
  1023   }
       
  1024 
       
  1025   flush = flags & GST_SEEK_FLAG_FLUSH;
       
  1026 
       
  1027   /* stop streaming, either by flushing or by pausing the task */
       
  1028   if (flush) {
       
  1029     /* unlock upstream pull_range */
       
  1030     gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_start ());
       
  1031     /* make sure out loop function exits */
       
  1032     gst_qtdemux_push_event (qtdemux, gst_event_new_flush_start ());
       
  1033   } else {
       
  1034     /* non flushing seek, pause the task */
       
  1035     gst_pad_pause_task (qtdemux->sinkpad);
       
  1036   }
       
  1037 
       
  1038   /* wait for streaming to finish */
       
  1039   GST_PAD_STREAM_LOCK (qtdemux->sinkpad);
       
  1040 
       
  1041   /* copy segment, we need this because we still need the old
       
  1042    * segment when we close the current segment. */
       
  1043   memcpy (&seeksegment, &qtdemux->segment, sizeof (GstSegment));
       
  1044 
       
  1045   if (event) {
       
  1046     /* configure the segment with the seek variables */
       
  1047     GST_DEBUG_OBJECT (qtdemux, "configuring seek");
       
  1048     gst_segment_set_seek (&seeksegment, rate, format, flags,
       
  1049         cur_type, cur, stop_type, stop, &update);
       
  1050   }
       
  1051 
       
  1052   /* now do the seek, this actually never returns FALSE */
       
  1053   gst_qtdemux_perform_seek (qtdemux, &seeksegment);
       
  1054 
       
  1055   /* prepare for streaming again */
       
  1056   if (flush) {
       
  1057     gst_pad_push_event (qtdemux->sinkpad, gst_event_new_flush_stop ());
       
  1058     gst_qtdemux_push_event (qtdemux, gst_event_new_flush_stop ());
       
  1059   } else if (qtdemux->segment_running) {
       
  1060     /* we are running the current segment and doing a non-flushing seek,
       
  1061      * close the segment first based on the last_stop. */
       
  1062     GST_DEBUG_OBJECT (qtdemux, "closing running segment %" G_GINT64_FORMAT
       
  1063         " to %" G_GINT64_FORMAT, qtdemux->segment.start,
       
  1064         qtdemux->segment.last_stop);
       
  1065 
       
  1066     if (qtdemux->segment.rate >= 0) {
       
  1067       /* FIXME, rate is the product of the global rate and the (quicktime)
       
  1068        * segment rate. */
       
  1069       qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
       
  1070           qtdemux->segment.rate, qtdemux->segment.format,
       
  1071           qtdemux->segment.start, qtdemux->segment.last_stop,
       
  1072           qtdemux->segment.time);
       
  1073     } else {                    /* For Reverse Playback */
       
  1074       guint64 stop;
       
  1075 
       
  1076       if ((stop = qtdemux->segment.stop) == -1)
       
  1077         stop = qtdemux->segment.duration;
       
  1078       /* for reverse playback, we played from stop to last_stop. */
       
  1079       qtdemux->pending_newsegment = gst_event_new_new_segment (TRUE,
       
  1080           qtdemux->segment.rate, qtdemux->segment.format,
       
  1081           qtdemux->segment.last_stop, stop, qtdemux->segment.last_stop);
       
  1082     }
       
  1083   }
       
  1084 
       
  1085   /* commit the new segment */
       
  1086   memcpy (&qtdemux->segment, &seeksegment, sizeof (GstSegment));
       
  1087 
       
  1088   if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
       
  1089     gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
       
  1090         gst_message_new_segment_start (GST_OBJECT_CAST (qtdemux),
       
  1091             qtdemux->segment.format, qtdemux->segment.last_stop));
       
  1092   }
       
  1093 
       
  1094   /* restart streaming, NEWSEGMENT will be sent from the streaming
       
  1095    * thread. */
       
  1096   qtdemux->segment_running = TRUE;
       
  1097   for (i = 0; i < qtdemux->n_streams; i++)
       
  1098     qtdemux->streams[i]->last_ret = GST_FLOW_OK;
       
  1099 
       
  1100   gst_pad_start_task (qtdemux->sinkpad, (GstTaskFunction) gst_qtdemux_loop,
       
  1101       qtdemux->sinkpad);
       
  1102 
       
  1103   GST_PAD_STREAM_UNLOCK (qtdemux->sinkpad);
       
  1104 
       
  1105   return TRUE;
       
  1106 
       
  1107   /* ERRORS */
       
  1108 no_format:
       
  1109   {
       
  1110     GST_DEBUG_OBJECT (qtdemux, "unsupported format given, seek aborted.");
       
  1111     return FALSE;
       
  1112   }
       
  1113 }
       
  1114 
       
  1115 static gboolean
       
  1116 gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
       
  1117 {
       
  1118   gboolean res = TRUE;
       
  1119   GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
       
  1120 
       
  1121   switch (GST_EVENT_TYPE (event)) {
       
  1122     case GST_EVENT_SEEK:
       
  1123       if (qtdemux->pullbased) {
       
  1124         res = gst_qtdemux_do_seek (qtdemux, pad, event);
       
  1125       } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) {
       
  1126         res = gst_qtdemux_do_push_seek (qtdemux, pad, event);
       
  1127       } else {
       
  1128         GST_DEBUG_OBJECT (qtdemux,
       
  1129             "ignoring seek in push mode in current state");
       
  1130         res = FALSE;
       
  1131       }
       
  1132       gst_event_unref (event);
       
  1133       break;
       
  1134     case GST_EVENT_QOS:
       
  1135     case GST_EVENT_NAVIGATION:
       
  1136       res = FALSE;
       
  1137       gst_event_unref (event);
       
  1138       break;
       
  1139     default:
       
  1140       res = gst_pad_event_default (pad, event);
       
  1141       break;
       
  1142   }
       
  1143 
       
  1144   gst_object_unref (qtdemux);
       
  1145 
       
  1146   return res;
       
  1147 }
       
  1148 
       
  1149 /* stream/index return sample that is min/max w.r.t. byte position,
       
  1150  * time is min/max w.r.t. time of samples,
       
  1151  * the latter need not be time of the former sample */
       
  1152 static void
       
  1153 gst_qtdemux_find_sample (GstQTDemux * qtdemux, gint64 byte_pos, gboolean fw,
       
  1154     gboolean set, QtDemuxStream ** _stream, gint * _index, gint64 * _time)
       
  1155 {
       
  1156   gint i, n, index;
       
  1157   gint64 time, min_time;
       
  1158   QtDemuxStream *stream;
       
  1159 
       
  1160   min_time = -1;
       
  1161   stream = NULL;
       
  1162   index = -1;
       
  1163 
       
  1164   for (n = 0; n < qtdemux->n_streams; ++n) {
       
  1165     QtDemuxStream *str;
       
  1166     gint inc;
       
  1167     gboolean set_sample;
       
  1168 
       
  1169 
       
  1170     str = qtdemux->streams[n];
       
  1171     set_sample = !set;
       
  1172 
       
  1173     if (fw) {
       
  1174       i = 0;
       
  1175       inc = 1;
       
  1176     } else {
       
  1177       i = str->n_samples - 1;
       
  1178       inc = -1;
       
  1179     }
       
  1180     for (; (i >= 0) && (i < str->n_samples); i += inc) {
       
  1181       if (str->samples[i].size &&
       
  1182           ((fw && (str->samples[i].offset >= byte_pos)) ||
       
  1183               (!fw &&
       
  1184                   (str->samples[i].offset + str->samples[i].size <=
       
  1185                       byte_pos)))) {
       
  1186         /* move stream to first available sample */
       
  1187         if (set) {
       
  1188           gst_qtdemux_move_stream (qtdemux, str, i);
       
  1189           set_sample = TRUE;
       
  1190         }
       
  1191         /* determine min/max time */
       
  1192         time = str->samples[i].timestamp + str->samples[i].pts_offset;
       
  1193         if (min_time == -1 || (fw && min_time > time) ||
       
  1194             (!fw && min_time < time)) {
       
  1195           min_time = time;
       
  1196         }
       
  1197         /* determine stream with leading sample, to get its position */
       
  1198         /* only needed in fw case */
       
  1199         if (fw && (!stream ||
       
  1200                 str->samples[i].offset < stream->samples[index].offset)) {
       
  1201           stream = str;
       
  1202           index = i;
       
  1203         }
       
  1204         break;
       
  1205       }
       
  1206     }
       
  1207     /* no sample for this stream, mark eos */
       
  1208     if (!set_sample)
       
  1209       gst_qtdemux_move_stream (qtdemux, str, str->n_samples);
       
  1210   }
       
  1211 
       
  1212   if (_time)
       
  1213     *_time = min_time;
       
  1214   if (_stream)
       
  1215     *_stream = stream;
       
  1216   if (_index)
       
  1217     *_index = index;
       
  1218 }
       
  1219 
       
  1220 static gboolean
       
  1221 gst_qtdemux_handle_sink_event (GstPad * sinkpad, GstEvent * event)
       
  1222 {
       
  1223   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
       
  1224   gboolean res;
       
  1225 
       
  1226   GST_LOG_OBJECT (demux, "handling %s event", GST_EVENT_TYPE_NAME (event));
       
  1227 
       
  1228   switch (GST_EVENT_TYPE (event)) {
       
  1229     case GST_EVENT_NEWSEGMENT:
       
  1230     {
       
  1231       GstFormat format;
       
  1232       gdouble rate, arate;
       
  1233       gint64 start, stop, time, offset = 0;
       
  1234       QtDemuxStream *stream;
       
  1235       gint idx;
       
  1236       gboolean update;
       
  1237       GstSegment segment;
       
  1238 
       
  1239       /* some debug output */
       
  1240       gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
       
  1241       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
       
  1242           &start, &stop, &time);
       
  1243       gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
       
  1244           start, stop, time);
       
  1245       GST_DEBUG_OBJECT (demux,
       
  1246           "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
       
  1247           &segment);
       
  1248 
       
  1249       /* chain will send initial newsegment after pads have been added */
       
  1250       if (demux->state != QTDEMUX_STATE_MOVIE || !demux->n_streams) {
       
  1251         GST_DEBUG_OBJECT (demux, "still starting, eating event");
       
  1252         goto exit;
       
  1253       }
       
  1254 
       
  1255       /* we only expect a BYTE segment, e.g. following a seek */
       
  1256       if (format == GST_FORMAT_BYTES) {
       
  1257         if (start > 0) {
       
  1258           offset = start;
       
  1259           gst_qtdemux_find_sample (demux, start, TRUE, FALSE, NULL, NULL,
       
  1260               &start);
       
  1261           start = MAX (start, 0);
       
  1262         }
       
  1263         if (stop > 0) {
       
  1264           gst_qtdemux_find_sample (demux, stop, FALSE, FALSE, NULL, NULL,
       
  1265               &stop);
       
  1266           stop = MAX (stop, 0);
       
  1267         }
       
  1268       } else {
       
  1269         GST_DEBUG_OBJECT (demux, "unsupported segment format, ignoring");
       
  1270         goto exit;
       
  1271       }
       
  1272 
       
  1273       /* accept upstream's notion of segment and distribute along */
       
  1274       gst_segment_set_newsegment_full (&demux->segment, update, rate, arate,
       
  1275           GST_FORMAT_TIME, start, stop, start);
       
  1276       GST_DEBUG_OBJECT (demux, "Pushing newseg update %d, rate %g, "
       
  1277           "applied rate %g, format %d, start %" G_GINT64_FORMAT ", "
       
  1278           "stop %" G_GINT64_FORMAT, update, rate, arate, GST_FORMAT_TIME,
       
  1279           start, stop);
       
  1280       gst_qtdemux_push_event (demux,
       
  1281           gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
       
  1282               start, stop, start));
       
  1283 
       
  1284       /* clear leftover in current segment, if any */
       
  1285       gst_adapter_clear (demux->adapter);
       
  1286       /* set up streaming thread */
       
  1287       gst_qtdemux_find_sample (demux, offset, TRUE, TRUE, &stream, &idx, NULL);
       
  1288       demux->offset = offset;
       
  1289       if (stream) {
       
  1290         demux->todrop = stream->samples[idx].offset - offset;
       
  1291         demux->neededbytes = demux->todrop + stream->samples[idx].size;
       
  1292       } else {
       
  1293         /* set up for EOS */
       
  1294         demux->neededbytes = -1;
       
  1295         demux->todrop = 0;
       
  1296       }
       
  1297     exit:
       
  1298       gst_event_unref (event);
       
  1299       res = TRUE;
       
  1300       goto drop;
       
  1301       break;
       
  1302     }
       
  1303     case GST_EVENT_FLUSH_STOP:
       
  1304     {
       
  1305       gint i;
       
  1306 
       
  1307       /* clean up, force EOS if no more info follows */
       
  1308       gst_adapter_clear (demux->adapter);
       
  1309       demux->offset = 0;
       
  1310       demux->neededbytes = -1;
       
  1311       /* reset flow return, e.g. following seek */
       
  1312       for (i = 0; i < demux->n_streams; i++) {
       
  1313         demux->streams[i]->last_ret = GST_FLOW_OK;
       
  1314         demux->streams[i]->sent_eos = FALSE;
       
  1315       }
       
  1316       break;
       
  1317     }
       
  1318     case GST_EVENT_EOS:
       
  1319       /* If we are in push mode, and get an EOS before we've seen any streams,
       
  1320        * then error out - we have nowhere to send the EOS */
       
  1321       if (!demux->pullbased && demux->n_streams == 0) {
       
  1322         GST_ELEMENT_ERROR (demux, STREAM, DECODE,
       
  1323             (_("This file contains no playable streams.")),
       
  1324             ("no known streams found"));
       
  1325       }
       
  1326       break;
       
  1327     default:
       
  1328       break;
       
  1329   }
       
  1330 
       
  1331   res = gst_pad_event_default (demux->sinkpad, event);
       
  1332 
       
  1333 drop:
       
  1334   return res;
       
  1335 }
       
  1336 
       
  1337 static GstStateChangeReturn
       
  1338 gst_qtdemux_change_state (GstElement * element, GstStateChange transition)
       
  1339 {
       
  1340   GstQTDemux *qtdemux = GST_QTDEMUX (element);
       
  1341   GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;
       
  1342 
       
  1343   switch (transition) {
       
  1344     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
  1345       break;
       
  1346     default:
       
  1347       break;
       
  1348   }
       
  1349 
       
  1350   result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
  1351 
       
  1352   switch (transition) {
       
  1353     case GST_STATE_CHANGE_PAUSED_TO_READY:{
       
  1354       gint n;
       
  1355 
       
  1356       qtdemux->state = QTDEMUX_STATE_INITIAL;
       
  1357       qtdemux->last_ts = GST_CLOCK_TIME_NONE;
       
  1358       qtdemux->neededbytes = 16;
       
  1359       qtdemux->todrop = 0;
       
  1360       qtdemux->pullbased = FALSE;
       
  1361       qtdemux->offset = 0;
       
  1362       qtdemux->mdatoffset = GST_CLOCK_TIME_NONE;
       
  1363       if (qtdemux->mdatbuffer)
       
  1364         gst_buffer_unref (qtdemux->mdatbuffer);
       
  1365       qtdemux->mdatbuffer = NULL;
       
  1366       gst_adapter_clear (qtdemux->adapter);
       
  1367       for (n = 0; n < qtdemux->n_streams; n++) {
       
  1368         QtDemuxStream *stream = qtdemux->streams[n];
       
  1369 
       
  1370         while (stream->buffers) {
       
  1371           gst_buffer_unref (GST_BUFFER_CAST (stream->buffers->data));
       
  1372           stream->buffers =
       
  1373               g_slist_delete_link (stream->buffers, stream->buffers);
       
  1374         }
       
  1375         if (stream->pad)
       
  1376           gst_element_remove_pad (element, stream->pad);
       
  1377         if (stream->samples)
       
  1378           g_free (stream->samples);
       
  1379         if (stream->caps)
       
  1380           gst_caps_unref (stream->caps);
       
  1381         if (stream->segments)
       
  1382           g_free (stream->segments);
       
  1383         g_free (stream);
       
  1384       }
       
  1385       qtdemux->major_brand = 0;
       
  1386       qtdemux->n_streams = 0;
       
  1387       qtdemux->n_video_streams = 0;
       
  1388       qtdemux->n_audio_streams = 0;
       
  1389       qtdemux->n_subp_streams = 0;
       
  1390       gst_segment_init (&qtdemux->segment, GST_FORMAT_TIME);
       
  1391       break;
       
  1392     }
       
  1393     default:
       
  1394       break;
       
  1395   }
       
  1396 
       
  1397   return result;
       
  1398 }
       
  1399 
       
  1400 static void
       
  1401 extract_initial_length_and_fourcc (const guint8 * data, guint64 * plength,
       
  1402     guint32 * pfourcc)
       
  1403 {
       
  1404   guint64 length;
       
  1405   guint32 fourcc;
       
  1406 
       
  1407   length = QT_UINT32 (data);
       
  1408   GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
       
  1409   fourcc = QT_FOURCC (data + 4);
       
  1410   GST_DEBUG ("atom type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
       
  1411 
       
  1412   if (length == 0) {
       
  1413     length = G_MAXUINT32;
       
  1414   } else if (length == 1) {
       
  1415     /* this means we have an extended size, which is the 64 bit value of
       
  1416      * the next 8 bytes */
       
  1417     length = QT_UINT64 (data + 8);
       
  1418     GST_DEBUG ("length 0x%08" G_GINT64_MODIFIER "x", length);
       
  1419   }
       
  1420 
       
  1421   if (plength)
       
  1422     *plength = length;
       
  1423   if (pfourcc)
       
  1424     *pfourcc = fourcc;
       
  1425 }
       
  1426 
       
  1427 static GstFlowReturn
       
  1428 gst_qtdemux_loop_state_header (GstQTDemux * qtdemux)
       
  1429 {
       
  1430   guint64 length = 0;
       
  1431   guint32 fourcc;
       
  1432   GstBuffer *buf = NULL;
       
  1433   GstFlowReturn ret = GST_FLOW_OK;
       
  1434   guint64 cur_offset = qtdemux->offset;
       
  1435 
       
  1436   ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, 16, &buf);
       
  1437   if (G_UNLIKELY (ret != GST_FLOW_OK))
       
  1438     goto beach;
       
  1439   if (G_LIKELY (GST_BUFFER_SIZE (buf) == 16))
       
  1440     extract_initial_length_and_fourcc (GST_BUFFER_DATA (buf), &length, &fourcc);
       
  1441   gst_buffer_unref (buf);
       
  1442 
       
  1443   if (G_UNLIKELY (length == 0)) {
       
  1444     GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
       
  1445         (_("This file is invalid and cannot be played.")),
       
  1446         ("Header atom '%" GST_FOURCC_FORMAT "' has empty length",
       
  1447             GST_FOURCC_ARGS (fourcc)));
       
  1448     ret = GST_FLOW_ERROR;
       
  1449     goto beach;
       
  1450   }
       
  1451 
       
  1452   switch (fourcc) {
       
  1453     case FOURCC_mdat:
       
  1454     case FOURCC_free:
       
  1455     case FOURCC_wide:
       
  1456     case FOURCC_PICT:
       
  1457     case FOURCC_pnot:
       
  1458     {
       
  1459       GST_LOG_OBJECT (qtdemux,
       
  1460           "skipping atom '%" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT,
       
  1461           GST_FOURCC_ARGS (fourcc), cur_offset);
       
  1462       qtdemux->offset += length;
       
  1463       break;
       
  1464     }
       
  1465     case FOURCC_moov:
       
  1466     {
       
  1467       GstBuffer *moov;
       
  1468 
       
  1469       ret = gst_pad_pull_range (qtdemux->sinkpad, cur_offset, length, &moov);
       
  1470       if (ret != GST_FLOW_OK)
       
  1471         goto beach;
       
  1472       if (length != GST_BUFFER_SIZE (moov)) {
       
  1473         /* Some files have a 'moov' atom at the end of the file which contains
       
  1474          * a terminal 'free' atom where the body of the atom is missing.
       
  1475          * Check for, and permit, this special case.
       
  1476          */
       
  1477         if (GST_BUFFER_SIZE (moov) >= 8) {
       
  1478           guint8 *final_data = GST_BUFFER_DATA (moov) +
       
  1479               (GST_BUFFER_SIZE (moov) - 8);
       
  1480           guint32 final_length = QT_UINT32 (final_data);
       
  1481           guint32 final_fourcc = QT_FOURCC (final_data + 4);
       
  1482           if (final_fourcc == FOURCC_free &&
       
  1483               GST_BUFFER_SIZE (moov) + final_length - 8 == length) {
       
  1484             /* Ok, we've found that special case. Allocate a new buffer with
       
  1485              * that free atom actually present. */
       
  1486             GstBuffer *newmoov = gst_buffer_new_and_alloc (length);
       
  1487             gst_buffer_copy_metadata (newmoov, moov,
       
  1488                 GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
       
  1489                 GST_BUFFER_COPY_CAPS);
       
  1490             memcpy (GST_BUFFER_DATA (newmoov), GST_BUFFER_DATA (moov),
       
  1491                 GST_BUFFER_SIZE (moov));
       
  1492             memset (GST_BUFFER_DATA (newmoov) + GST_BUFFER_SIZE (moov), 0,
       
  1493                 final_length - 8);
       
  1494             gst_buffer_unref (moov);
       
  1495             moov = newmoov;
       
  1496           }
       
  1497         }
       
  1498       }
       
  1499 
       
  1500       if (length != GST_BUFFER_SIZE (moov)) {
       
  1501         GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
       
  1502             (_("This file is incomplete and cannot be played.")),
       
  1503             ("We got less than expected (received %u, wanted %u, offset %"
       
  1504                 G_GUINT64_FORMAT ")",
       
  1505                 GST_BUFFER_SIZE (moov), (guint) length, cur_offset));
       
  1506         ret = GST_FLOW_ERROR;
       
  1507         goto beach;
       
  1508       }
       
  1509       qtdemux->offset += length;
       
  1510 
       
  1511       qtdemux_parse_moov (qtdemux, GST_BUFFER_DATA (moov), length);
       
  1512       qtdemux_node_dump (qtdemux, qtdemux->moov_node);
       
  1513 
       
  1514       qtdemux_parse_tree (qtdemux);
       
  1515       g_node_destroy (qtdemux->moov_node);
       
  1516       gst_buffer_unref (moov);
       
  1517       qtdemux->moov_node = NULL;
       
  1518       qtdemux->state = QTDEMUX_STATE_MOVIE;
       
  1519       GST_DEBUG_OBJECT (qtdemux, "switching state to STATE_MOVIE (%d)",
       
  1520           qtdemux->state);
       
  1521       break;
       
  1522     }
       
  1523     case FOURCC_ftyp:
       
  1524     {
       
  1525       GstBuffer *ftyp;
       
  1526 
       
  1527       /* extract major brand; might come in handy for ISO vs QT issues */
       
  1528       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &ftyp);
       
  1529       if (ret != GST_FLOW_OK)
       
  1530         goto beach;
       
  1531       qtdemux->offset += length;
       
  1532       /* only consider at least a sufficiently complete ftyp atom */
       
  1533       if (length >= 20) {
       
  1534         qtdemux->major_brand = QT_FOURCC (GST_BUFFER_DATA (ftyp) + 8);
       
  1535         GST_DEBUG_OBJECT (qtdemux, "major brand: %" GST_FOURCC_FORMAT,
       
  1536             GST_FOURCC_ARGS (qtdemux->major_brand));
       
  1537       }
       
  1538       gst_buffer_unref (ftyp);
       
  1539       break;
       
  1540     }
       
  1541     default:
       
  1542     {
       
  1543       GstBuffer *unknown;
       
  1544 
       
  1545       GST_LOG_OBJECT (qtdemux,
       
  1546           "unknown %08x '%" GST_FOURCC_FORMAT "' of size %" G_GUINT64_FORMAT
       
  1547           " at %" G_GUINT64_FORMAT, fourcc, GST_FOURCC_ARGS (fourcc), length,
       
  1548           cur_offset);
       
  1549       ret = gst_qtdemux_pull_atom (qtdemux, cur_offset, length, &unknown);
       
  1550       if (ret != GST_FLOW_OK)
       
  1551         goto beach;
       
  1552       GST_MEMDUMP ("Unknown tag", GST_BUFFER_DATA (unknown),
       
  1553           GST_BUFFER_SIZE (unknown));
       
  1554       gst_buffer_unref (unknown);
       
  1555       qtdemux->offset += length;
       
  1556       break;
       
  1557     }
       
  1558   }
       
  1559 
       
  1560 beach:
       
  1561   return ret;
       
  1562 }
       
  1563 
       
  1564 /* Seeks to the previous keyframe of the indexed stream and 
       
  1565  * aligns other streams with respect to the keyframe timestamp 
       
  1566  * of indexed stream. Only called in case of Reverse Playback
       
  1567  */
       
  1568 static GstFlowReturn
       
  1569 gst_qtdemux_seek_to_previous_keyframe (GstQTDemux * qtdemux)
       
  1570 {
       
  1571   guint8 n = 0;
       
  1572   guint32 seg_idx = 0, k_index = 0;
       
  1573   guint64 k_pos = 0, last_stop = 0;
       
  1574   QtDemuxSegment *seg = NULL;
       
  1575   QtDemuxStream *ref_str = NULL;
       
  1576 
       
  1577   /* Now we choose an arbitrary stream, get the previous keyframe timestamp
       
  1578    * and finally align all the other streams on that timestamp with their 
       
  1579    * respective keyframes */
       
  1580   for (n = 0; n < qtdemux->n_streams; n++) {
       
  1581     QtDemuxStream *str = qtdemux->streams[n];
       
  1582 
       
  1583     seg_idx = gst_qtdemux_find_segment (qtdemux, str,
       
  1584         qtdemux->segment.last_stop);
       
  1585 
       
  1586     /* segment not found, continue with normal flow */
       
  1587     if (seg_idx == -1)
       
  1588       continue;
       
  1589 
       
  1590     /* No candidate yet, take that one */
       
  1591     if (!ref_str) {
       
  1592       ref_str = str;
       
  1593       continue;
       
  1594     }
       
  1595 
       
  1596     /* So that stream has a segment, we prefer video streams */
       
  1597     if (str->subtype == FOURCC_vide) {
       
  1598       ref_str = str;
       
  1599       break;
       
  1600     }
       
  1601   }
       
  1602 
       
  1603   if (G_UNLIKELY (!ref_str)) {
       
  1604     GST_DEBUG_OBJECT (qtdemux, "couldn't find any stream");
       
  1605     goto eos;
       
  1606   }
       
  1607 
       
  1608   if (G_UNLIKELY (!ref_str->from_sample)) {
       
  1609     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of the file");
       
  1610     goto eos;
       
  1611   }
       
  1612 
       
  1613   /* So that stream has been playing from from_sample to to_sample. We will
       
  1614    * get the timestamp of the previous sample and search for a keyframe before
       
  1615    * that. For audio streams we do an arbitrary jump in the past (10 samples) */
       
  1616   if (ref_str->subtype == FOURCC_vide) {
       
  1617     k_index = gst_qtdemux_find_keyframe (qtdemux, ref_str,
       
  1618         ref_str->from_sample - 1);
       
  1619   } else {
       
  1620     k_index = ref_str->from_sample - 10;
       
  1621   }
       
  1622 
       
  1623   /* get current segment for that stream */
       
  1624   seg = &ref_str->segments[ref_str->segment_index];
       
  1625   /* Crawl back through segments to find the one containing this I frame */
       
  1626   while (ref_str->samples[k_index].timestamp < seg->media_start) {
       
  1627     GST_DEBUG_OBJECT (qtdemux, "keyframe position is out of segment %u",
       
  1628         ref_str->segment_index);
       
  1629     if (G_UNLIKELY (!ref_str->segment_index)) {
       
  1630       /* Reached first segment, let's consider it's EOS */
       
  1631       goto eos;
       
  1632     }
       
  1633     ref_str->segment_index--;
       
  1634     seg = &ref_str->segments[ref_str->segment_index];
       
  1635   }
       
  1636   /* Calculate time position of the keyframe and where we should stop */
       
  1637   k_pos = (ref_str->samples[k_index].timestamp - seg->media_start) + seg->time;
       
  1638   last_stop = ref_str->samples[ref_str->from_sample].timestamp;
       
  1639   last_stop = (last_stop - seg->media_start) + seg->time;
       
  1640 
       
  1641   GST_DEBUG_OBJECT (qtdemux, "preferred stream played from sample %u, "
       
  1642       "now going to sample %u (pts %" GST_TIME_FORMAT ")", ref_str->from_sample,
       
  1643       k_index, GST_TIME_ARGS (k_pos));
       
  1644 
       
  1645   /* Set last_stop with the keyframe timestamp we pushed of that stream */
       
  1646   gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, last_stop);
       
  1647   GST_DEBUG_OBJECT (qtdemux, "last_stop now is %" GST_TIME_FORMAT,
       
  1648       GST_TIME_ARGS (last_stop));
       
  1649 
       
  1650   if (G_UNLIKELY (last_stop < qtdemux->segment.start)) {
       
  1651     GST_DEBUG_OBJECT (qtdemux, "reached the beginning of segment");
       
  1652     goto eos;
       
  1653   }
       
  1654 
       
  1655   /* Align them all on this */
       
  1656   for (n = 0; n < qtdemux->n_streams; n++) {
       
  1657     guint32 index = 0;
       
  1658     guint64 media_start = 0, seg_time = 0;
       
  1659     QtDemuxStream *str = qtdemux->streams[n];
       
  1660 
       
  1661     seg_idx = gst_qtdemux_find_segment (qtdemux, str, k_pos);
       
  1662     GST_DEBUG_OBJECT (qtdemux, "align segment %d", seg_idx);
       
  1663 
       
  1664     /* segment not found, continue with normal flow */
       
  1665     if (seg_idx == -1)
       
  1666       continue;
       
  1667 
       
  1668     /* get segment and time in the segment */
       
  1669     seg = &str->segments[seg_idx];
       
  1670     seg_time = k_pos - seg->time;
       
  1671 
       
  1672     /* get the media time in the segment */
       
  1673     media_start = seg->media_start + seg_time;
       
  1674 
       
  1675     /* get the index of the sample with media time */
       
  1676     index = gst_qtdemux_find_index (qtdemux, str, media_start);
       
  1677     GST_DEBUG_OBJECT (qtdemux, "sample for %" GST_TIME_FORMAT " at %u",
       
  1678         GST_TIME_ARGS (media_start), index);
       
  1679 
       
  1680     /* find previous keyframe */
       
  1681     k_index = gst_qtdemux_find_keyframe (qtdemux, str, index);
       
  1682 
       
  1683     /* Remember until where we want to go */
       
  1684     str->to_sample = str->from_sample - 1;
       
  1685     /* Define our time position */
       
  1686     str->time_position =
       
  1687         (str->samples[k_index].timestamp - seg->media_start) + seg->time;
       
  1688     /* Now seek back in time */
       
  1689     gst_qtdemux_move_stream (qtdemux, str, k_index);
       
  1690     GST_DEBUG_OBJECT (qtdemux, "keyframe at %u, time position %"
       
  1691         GST_TIME_FORMAT " playing from sample %u to %u", k_index,
       
  1692         GST_TIME_ARGS (str->time_position), str->from_sample, str->to_sample);
       
  1693   }
       
  1694 
       
  1695   return GST_FLOW_OK;
       
  1696 
       
  1697 eos:
       
  1698   return GST_FLOW_UNEXPECTED;
       
  1699 }
       
  1700 
       
  1701 /* activate the given segment number @seg_idx of @stream at time @offset.
       
  1702  * @offset is an absolute global position over all the segments.
       
  1703  *
       
  1704  * This will push out a NEWSEGMENT event with the right values and
       
  1705  * position the stream index to the first decodable sample before
       
  1706  * @offset.
       
  1707  */
       
  1708 static gboolean
       
  1709 gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  1710     guint32 seg_idx, guint64 offset)
       
  1711 {
       
  1712   GstEvent *event;
       
  1713   QtDemuxSegment *segment;
       
  1714   guint32 index, kf_index;
       
  1715   guint64 seg_time;
       
  1716   guint64 start, stop, time;
       
  1717   gdouble rate;
       
  1718 
       
  1719   GST_LOG_OBJECT (qtdemux, "activate segment %d, offset %" G_GUINT64_FORMAT,
       
  1720       seg_idx, offset);
       
  1721 
       
  1722   /* update the current segment */
       
  1723   stream->segment_index = seg_idx;
       
  1724 
       
  1725   /* get the segment */
       
  1726   segment = &stream->segments[seg_idx];
       
  1727 
       
  1728   if (G_UNLIKELY (offset < segment->time)) {
       
  1729     GST_WARNING_OBJECT (qtdemux, "offset < segment->time %" G_GUINT64_FORMAT,
       
  1730         segment->time);
       
  1731     return FALSE;
       
  1732   }
       
  1733 
       
  1734   /* get time in this segment */
       
  1735   seg_time = offset - segment->time;
       
  1736 
       
  1737   GST_LOG_OBJECT (qtdemux, "seg_time %" GST_TIME_FORMAT,
       
  1738       GST_TIME_ARGS (seg_time));
       
  1739 
       
  1740   if (G_UNLIKELY (seg_time > segment->duration)) {
       
  1741     GST_LOG_OBJECT (qtdemux, "seg_time > segment->duration %" GST_TIME_FORMAT,
       
  1742         GST_TIME_ARGS (segment->duration));
       
  1743     return FALSE;
       
  1744   }
       
  1745 
       
  1746   /* qtdemux->segment.stop is in outside-time-realm, whereas
       
  1747    * segment->media_stop is in track-time-realm.
       
  1748    * 
       
  1749    * In order to compare the two, we need to bring segment.stop
       
  1750    * into the track-time-realm */
       
  1751 
       
  1752   if (qtdemux->segment.stop == -1)
       
  1753     stop = segment->media_stop;
       
  1754   else
       
  1755     stop =
       
  1756         MIN (segment->media_stop,
       
  1757         qtdemux->segment.stop - segment->time + segment->media_start);
       
  1758 
       
  1759   if (qtdemux->segment.rate >= 0) {
       
  1760     start = MIN (segment->media_start + seg_time, stop);
       
  1761     time = offset;
       
  1762   } else {
       
  1763     start = segment->media_start;
       
  1764     stop = MIN (segment->media_start + seg_time, stop);
       
  1765     time = segment->time;
       
  1766   }
       
  1767 
       
  1768   GST_DEBUG_OBJECT (qtdemux, "newsegment %d from %" GST_TIME_FORMAT
       
  1769       " to %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT, seg_idx,
       
  1770       GST_TIME_ARGS (start), GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
       
  1771 
       
  1772   /* combine global rate with that of the segment */
       
  1773   rate = segment->rate * qtdemux->segment.rate;
       
  1774 
       
  1775   /* update the segment values used for clipping */
       
  1776   gst_segment_init (&stream->segment, GST_FORMAT_TIME);
       
  1777   gst_segment_set_newsegment (&stream->segment, FALSE, rate, GST_FORMAT_TIME,
       
  1778       start, stop, time);
       
  1779 
       
  1780   /* now prepare and send the segment */
       
  1781   if (stream->pad) {
       
  1782     event = gst_event_new_new_segment (FALSE, rate, GST_FORMAT_TIME,
       
  1783         start, stop, time);
       
  1784     gst_pad_push_event (stream->pad, event);
       
  1785     /* assume we can send more data now */
       
  1786     stream->last_ret = GST_FLOW_OK;
       
  1787   }
       
  1788 
       
  1789   /* and move to the keyframe before the indicated media time of the
       
  1790    * segment */
       
  1791   if (qtdemux->segment.rate >= 0) {
       
  1792     index = gst_qtdemux_find_index (qtdemux, stream, start);
       
  1793     stream->to_sample = stream->n_samples;
       
  1794     GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
       
  1795         ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
       
  1796         GST_TIME_ARGS (stream->samples[index].timestamp));
       
  1797   } else {
       
  1798     index = gst_qtdemux_find_index (qtdemux, stream, stop);
       
  1799     stream->to_sample = index;
       
  1800     GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
       
  1801         ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
       
  1802         GST_TIME_ARGS (stream->samples[index].timestamp));
       
  1803   }
       
  1804 
       
  1805   /* we're at the right spot */
       
  1806   if (index == stream->sample_index) {
       
  1807     GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
       
  1808     return TRUE;
       
  1809   }
       
  1810 
       
  1811   /* find keyframe of the target index */
       
  1812   kf_index = gst_qtdemux_find_keyframe (qtdemux, stream, index);
       
  1813 
       
  1814   /* if we move forwards, we don't have to go back to the previous
       
  1815    * keyframe since we already sent that. We can also just jump to
       
  1816    * the keyframe right before the target index if there is one. */
       
  1817   if (index > stream->sample_index) {
       
  1818     /* moving forwards check if we move past a keyframe */
       
  1819     if (kf_index > stream->sample_index) {
       
  1820       GST_DEBUG_OBJECT (qtdemux, "moving forwards to keyframe at %u (pts %"
       
  1821           GST_TIME_FORMAT, kf_index,
       
  1822           GST_TIME_ARGS (stream->samples[kf_index].timestamp));
       
  1823       gst_qtdemux_move_stream (qtdemux, stream, kf_index);
       
  1824     } else {
       
  1825       GST_DEBUG_OBJECT (qtdemux, "moving forwards, keyframe at %u (pts %"
       
  1826           GST_TIME_FORMAT " already sent", kf_index,
       
  1827           GST_TIME_ARGS (stream->samples[kf_index].timestamp));
       
  1828     }
       
  1829   } else {
       
  1830     GST_DEBUG_OBJECT (qtdemux, "moving backwards to keyframe at %u (pts %"
       
  1831         GST_TIME_FORMAT, kf_index,
       
  1832         GST_TIME_ARGS (stream->samples[kf_index].timestamp));
       
  1833     gst_qtdemux_move_stream (qtdemux, stream, kf_index);
       
  1834   }
       
  1835 
       
  1836   return TRUE;
       
  1837 }
       
  1838 
       
  1839 /* prepare to get the current sample of @stream, getting essential values.
       
  1840  *
       
  1841  * This function will also prepare and send the segment when needed.
       
  1842  *
       
  1843  * Return FALSE if the stream is EOS.
       
  1844  */
       
  1845 static gboolean
       
  1846 gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
       
  1847     QtDemuxStream * stream, guint64 * offset, guint * size, guint64 * timestamp,
       
  1848     guint64 * duration, gboolean * keyframe)
       
  1849 {
       
  1850   QtDemuxSample *sample;
       
  1851   guint64 time_position;
       
  1852   guint32 seg_idx;
       
  1853 
       
  1854   g_return_val_if_fail (stream != NULL, FALSE);
       
  1855 
       
  1856   time_position = stream->time_position;
       
  1857   if (G_UNLIKELY (time_position == -1))
       
  1858     goto eos;
       
  1859 
       
  1860   seg_idx = stream->segment_index;
       
  1861   if (G_UNLIKELY (seg_idx == -1)) {
       
  1862     /* find segment corresponding to time_position if we are looking
       
  1863      * for a segment. */
       
  1864     seg_idx = gst_qtdemux_find_segment (qtdemux, stream, time_position);
       
  1865 
       
  1866     /* nothing found, we're really eos */
       
  1867     if (seg_idx == -1)
       
  1868       goto eos;
       
  1869   }
       
  1870 
       
  1871   /* different segment, activate it, sample_index will be set. */
       
  1872   if (G_UNLIKELY (stream->segment_index != seg_idx))
       
  1873     gst_qtdemux_activate_segment (qtdemux, stream, seg_idx, time_position);
       
  1874 
       
  1875   GST_LOG_OBJECT (qtdemux, "segment active, index = %u of %u",
       
  1876       stream->sample_index, stream->n_samples);
       
  1877 
       
  1878   /* send out pending buffers */
       
  1879   while (stream->buffers) {
       
  1880     GstBuffer *buffer = (GstBuffer *) stream->buffers->data;
       
  1881 
       
  1882     if (G_UNLIKELY (stream->discont)) {
       
  1883       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
       
  1884       GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
       
  1885       stream->discont = FALSE;
       
  1886     }
       
  1887     gst_buffer_set_caps (buffer, stream->caps);
       
  1888 
       
  1889     gst_pad_push (stream->pad, buffer);
       
  1890 
       
  1891     stream->buffers = g_slist_delete_link (stream->buffers, stream->buffers);
       
  1892   }
       
  1893 
       
  1894   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
       
  1895     goto eos;
       
  1896 
       
  1897   /* now get the info for the sample we're at */
       
  1898   sample = &stream->samples[stream->sample_index];
       
  1899 
       
  1900   *timestamp = sample->timestamp + sample->pts_offset;
       
  1901   *offset = sample->offset;
       
  1902   *size = sample->size;
       
  1903   *duration = sample->duration;
       
  1904   *keyframe = stream->all_keyframe || sample->keyframe;
       
  1905 
       
  1906   /* add padding */
       
  1907   if (stream->padding) {
       
  1908     *offset += stream->padding;
       
  1909     *size -= stream->padding;
       
  1910   }
       
  1911 
       
  1912   return TRUE;
       
  1913 
       
  1914   /* special cases */
       
  1915 eos:
       
  1916   {
       
  1917     stream->time_position = -1;
       
  1918     return FALSE;
       
  1919   }
       
  1920 }
       
  1921 
       
  1922 /* move to the next sample in @stream.
       
  1923  *
       
  1924  * Moves to the next segment when needed.
       
  1925  */
       
  1926 static void
       
  1927 gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
       
  1928 {
       
  1929   QtDemuxSample *sample;
       
  1930   QtDemuxSegment *segment;
       
  1931 
       
  1932   if (G_UNLIKELY (stream->sample_index >= stream->to_sample)) {
       
  1933     /* Mark the stream as EOS */
       
  1934     GST_DEBUG_OBJECT (qtdemux, "reached max allowed sample %u, mark EOS",
       
  1935         stream->to_sample);
       
  1936     stream->time_position = -1;
       
  1937     return;
       
  1938   }
       
  1939 
       
  1940   /* move to next sample */
       
  1941   stream->sample_index++;
       
  1942 
       
  1943   /* get current segment */
       
  1944   segment = &stream->segments[stream->segment_index];
       
  1945 
       
  1946   /* reached the last sample, we need the next segment */
       
  1947   if (G_UNLIKELY (stream->sample_index >= stream->n_samples))
       
  1948     goto next_segment;
       
  1949 
       
  1950   /* get next sample */
       
  1951   sample = &stream->samples[stream->sample_index];
       
  1952 
       
  1953   /* see if we are past the segment */
       
  1954   if (G_UNLIKELY (sample->timestamp >= segment->media_stop))
       
  1955     goto next_segment;
       
  1956 
       
  1957   if (sample->timestamp >= segment->media_start) {
       
  1958     /* inside the segment, update time_position, looks very familiar to
       
  1959      * GStreamer segments, doesn't it? */
       
  1960     stream->time_position =
       
  1961         (sample->timestamp - segment->media_start) + segment->time;
       
  1962   } else {
       
  1963     /* not yet in segment, time does not yet increment. This means
       
  1964      * that we are still prerolling keyframes to the decoder so it can
       
  1965      * decode the first sample of the segment. */
       
  1966     stream->time_position = segment->time;
       
  1967   }
       
  1968   return;
       
  1969 
       
  1970   /* move to the next segment */
       
  1971 next_segment:
       
  1972   {
       
  1973     GST_DEBUG_OBJECT (qtdemux, "segment %d ended ", stream->segment_index);
       
  1974 
       
  1975     if (stream->segment_index == stream->n_segments - 1) {
       
  1976       /* are we at the end of the last segment, we're EOS */
       
  1977       stream->time_position = -1;
       
  1978     } else {
       
  1979       /* else we're only at the end of the current segment */
       
  1980       stream->time_position = segment->stop_time;
       
  1981     }
       
  1982     /* make sure we select a new segment */
       
  1983     stream->segment_index = -1;
       
  1984   }
       
  1985 }
       
  1986 
       
  1987 static void
       
  1988 gst_qtdemux_sync_streams (GstQTDemux * demux)
       
  1989 {
       
  1990   gint i;
       
  1991 
       
  1992   if (demux->n_streams <= 1)
       
  1993     return;
       
  1994 
       
  1995   for (i = 0; i < demux->n_streams; i++) {
       
  1996     QtDemuxStream *stream;
       
  1997     GstClockTime end_time;
       
  1998 
       
  1999     stream = demux->streams[i];
       
  2000 
       
  2001     if (!stream->pad)
       
  2002       continue;
       
  2003 
       
  2004     /* TODO advance time on subtitle streams here, if any some day */
       
  2005 
       
  2006     /* some clips/trailers may have unbalanced streams at the end,
       
  2007      * so send EOS on shorter stream to prevent stalling others */
       
  2008 
       
  2009     /* do not mess with EOS if SEGMENT seeking */
       
  2010     if (demux->segment.flags & GST_SEEK_FLAG_SEGMENT)
       
  2011       continue;
       
  2012 
       
  2013     if (demux->pullbased) {
       
  2014       /* loop mode is sample time based */
       
  2015       if (stream->time_position != -1)
       
  2016         continue;
       
  2017     } else {
       
  2018       /* push mode is byte position based */
       
  2019       if (stream->samples[stream->n_samples - 1].offset >= demux->offset)
       
  2020         continue;
       
  2021     }
       
  2022 
       
  2023     if (stream->sent_eos)
       
  2024       continue;
       
  2025 
       
  2026     /* only act if some gap */
       
  2027     end_time = stream->segments[stream->n_segments - 1].stop_time;
       
  2028     GST_LOG_OBJECT (demux, "current position: %" GST_TIME_FORMAT
       
  2029         ", stream end: %" GST_TIME_FORMAT, GST_TIME_ARGS (end_time),
       
  2030         GST_TIME_ARGS (demux->segment.last_stop));
       
  2031     if (end_time + 2 * GST_SECOND < demux->segment.last_stop) {
       
  2032       GST_DEBUG_OBJECT (demux, "sending EOS for stream %s",
       
  2033           GST_PAD_NAME (stream->pad));
       
  2034       stream->sent_eos = TRUE;
       
  2035       gst_pad_push_event (stream->pad, gst_event_new_eos ());
       
  2036     }
       
  2037   }
       
  2038 }
       
  2039 
       
  2040 /* UNEXPECTED and NOT_LINKED need to be combined. This means that we return:
       
  2041  *  
       
  2042  *  GST_FLOW_NOT_LINKED: when all pads NOT_LINKED.
       
  2043  *  GST_FLOW_UNEXPECTED: when all pads UNEXPECTED or NOT_LINKED.
       
  2044  */
       
  2045 static GstFlowReturn
       
  2046 gst_qtdemux_combine_flows (GstQTDemux * demux, QtDemuxStream * stream,
       
  2047     GstFlowReturn ret)
       
  2048 {
       
  2049   gint i;
       
  2050   gboolean unexpected = FALSE, not_linked = TRUE;
       
  2051 
       
  2052   GST_LOG_OBJECT (demux, "flow return: %s", gst_flow_get_name (ret));
       
  2053 
       
  2054   /* store the value */
       
  2055   stream->last_ret = ret;
       
  2056 
       
  2057   for (i = 0; i < demux->n_streams; i++) {
       
  2058     QtDemuxStream *ostream = demux->streams[i];
       
  2059 
       
  2060     ret = ostream->last_ret;
       
  2061 
       
  2062     /* no unexpected or unlinked, return */
       
  2063     if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
       
  2064       goto done;
       
  2065 
       
  2066     /* we check to see if we have at least 1 unexpected or all unlinked */
       
  2067     unexpected |= (ret == GST_FLOW_UNEXPECTED);
       
  2068     not_linked &= (ret == GST_FLOW_NOT_LINKED);
       
  2069   }
       
  2070 
       
  2071   /* when we get here, we all have unlinked or unexpected */
       
  2072   if (not_linked)
       
  2073     ret = GST_FLOW_NOT_LINKED;
       
  2074   else if (unexpected)
       
  2075     ret = GST_FLOW_UNEXPECTED;
       
  2076 done:
       
  2077   GST_LOG_OBJECT (demux, "combined flow return: %s", gst_flow_get_name (ret));
       
  2078   return ret;
       
  2079 }
       
  2080 
       
  2081 /* the input buffer metadata must be writable. Returns NULL when the buffer is
       
  2082  * completely cliped */
       
  2083 static GstBuffer *
       
  2084 gst_qtdemux_clip_buffer (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  2085     GstBuffer * buf)
       
  2086 {
       
  2087   gint64 start, stop, cstart, cstop, diff;
       
  2088   GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
       
  2089   guint8 *data;
       
  2090   guint size;
       
  2091   gint num_rate, denom_rate;
       
  2092   gint frame_size;
       
  2093   gboolean clip_data;
       
  2094 
       
  2095   data = GST_BUFFER_DATA (buf);
       
  2096   size = GST_BUFFER_SIZE (buf);
       
  2097 
       
  2098   /* depending on the type, setup the clip parameters */
       
  2099   if (stream->subtype == FOURCC_soun) {
       
  2100     frame_size = stream->bytes_per_frame;
       
  2101     num_rate = GST_SECOND;
       
  2102     denom_rate = (gint) stream->rate;
       
  2103     clip_data = TRUE;
       
  2104   } else if (stream->subtype == FOURCC_vide) {
       
  2105     frame_size = size;
       
  2106     num_rate = stream->fps_n;
       
  2107     denom_rate = stream->fps_d;
       
  2108     clip_data = FALSE;
       
  2109   } else
       
  2110     goto wrong_type;
       
  2111 
       
  2112   /* we can only clip if we have a valid timestamp */
       
  2113   timestamp = GST_BUFFER_TIMESTAMP (buf);
       
  2114   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp)))
       
  2115     goto no_timestamp;
       
  2116 
       
  2117   if (G_LIKELY (GST_BUFFER_DURATION_IS_VALID (buf))) {
       
  2118     duration = GST_BUFFER_DURATION (buf);
       
  2119   } else {
       
  2120     duration =
       
  2121         gst_util_uint64_scale_int (size / frame_size, num_rate, denom_rate);
       
  2122   }
       
  2123 
       
  2124   start = timestamp;
       
  2125   stop = start + duration;
       
  2126 
       
  2127   if (G_UNLIKELY (!gst_segment_clip (&stream->segment, GST_FORMAT_TIME,
       
  2128               start, stop, &cstart, &cstop)))
       
  2129     goto clipped;
       
  2130 
       
  2131   /* see if some clipping happened */
       
  2132   diff = cstart - start;
       
  2133   if (diff > 0) {
       
  2134     timestamp = cstart;
       
  2135     duration -= diff;
       
  2136 
       
  2137     if (clip_data) {
       
  2138       /* bring clipped time to samples and to bytes */
       
  2139       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
       
  2140       diff *= frame_size;
       
  2141 
       
  2142       GST_DEBUG_OBJECT (qtdemux, "clipping start to %" GST_TIME_FORMAT " %"
       
  2143           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstart), diff);
       
  2144 
       
  2145       data += diff;
       
  2146       size -= diff;
       
  2147     }
       
  2148   }
       
  2149   diff = stop - cstop;
       
  2150   if (diff > 0) {
       
  2151     duration -= diff;
       
  2152 
       
  2153     if (clip_data) {
       
  2154       /* bring clipped time to samples and then to bytes */
       
  2155       diff = gst_util_uint64_scale_int (diff, denom_rate, num_rate);
       
  2156       diff *= frame_size;
       
  2157 
       
  2158       GST_DEBUG_OBJECT (qtdemux, "clipping stop to %" GST_TIME_FORMAT " %"
       
  2159           G_GUINT64_FORMAT " bytes", GST_TIME_ARGS (cstop), diff);
       
  2160 
       
  2161       size -= diff;
       
  2162     }
       
  2163   }
       
  2164 
       
  2165   GST_BUFFER_TIMESTAMP (buf) = timestamp;
       
  2166   GST_BUFFER_DURATION (buf) = duration;
       
  2167   GST_BUFFER_SIZE (buf) = size;
       
  2168   GST_BUFFER_DATA (buf) = data;
       
  2169 
       
  2170   return buf;
       
  2171 
       
  2172   /* dropped buffer */
       
  2173 wrong_type:
       
  2174   {
       
  2175     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
       
  2176     return buf;
       
  2177   }
       
  2178 no_timestamp:
       
  2179   {
       
  2180     GST_DEBUG_OBJECT (qtdemux, "no timestamp on buffer");
       
  2181     return buf;
       
  2182   }
       
  2183 clipped:
       
  2184   {
       
  2185     GST_DEBUG_OBJECT (qtdemux, "clipped buffer");
       
  2186     gst_buffer_unref (buf);
       
  2187     return NULL;
       
  2188   }
       
  2189 }
       
  2190 
       
  2191 static GstFlowReturn
       
  2192 gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
       
  2193 {
       
  2194   GstFlowReturn ret = GST_FLOW_OK;
       
  2195   GstBuffer *buf = NULL;
       
  2196   QtDemuxStream *stream;
       
  2197   guint64 min_time;
       
  2198   guint64 offset = 0;
       
  2199   guint64 timestamp = GST_CLOCK_TIME_NONE;
       
  2200   guint64 duration = 0;
       
  2201   gboolean keyframe = FALSE;
       
  2202   guint size = 0;
       
  2203   gint index;
       
  2204   gint i;
       
  2205 
       
  2206   gst_qtdemux_push_pending_newsegment (qtdemux);
       
  2207 
       
  2208   /* Figure out the next stream sample to output, min_time is expressed in
       
  2209    * global time and runs over the edit list segments. */
       
  2210   min_time = G_MAXUINT64;
       
  2211   index = -1;
       
  2212   for (i = 0; i < qtdemux->n_streams; i++) {
       
  2213     guint64 position;
       
  2214 
       
  2215     stream = qtdemux->streams[i];
       
  2216     position = stream->time_position;
       
  2217 
       
  2218     /* position of -1 is EOS */
       
  2219     if (position != -1 && position < min_time) {
       
  2220       min_time = position;
       
  2221       index = i;
       
  2222     }
       
  2223   }
       
  2224   /* all are EOS */
       
  2225   if (G_UNLIKELY (index == -1)) {
       
  2226     GST_DEBUG_OBJECT (qtdemux, "all streams are EOS");
       
  2227     goto eos;
       
  2228   }
       
  2229 
       
  2230   /* check for segment end */
       
  2231   if (G_UNLIKELY (qtdemux->segment.stop != -1
       
  2232           && qtdemux->segment.stop < min_time)) {
       
  2233     GST_DEBUG_OBJECT (qtdemux, "we reached the end of our segment.");
       
  2234     goto eos;
       
  2235   }
       
  2236 
       
  2237   stream = qtdemux->streams[index];
       
  2238 
       
  2239   /* fetch info for the current sample of this stream */
       
  2240   if (G_UNLIKELY (!gst_qtdemux_prepare_current_sample (qtdemux, stream, &offset,
       
  2241               &size, &timestamp, &duration, &keyframe)))
       
  2242     goto eos_stream;
       
  2243 
       
  2244   GST_LOG_OBJECT (qtdemux,
       
  2245       "pushing from stream %d, offset %" G_GUINT64_FORMAT
       
  2246       ", size %d, timestamp=%" GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT,
       
  2247       index, offset, size, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (duration));
       
  2248 
       
  2249   /* hmm, empty sample, skip and move to next sample */
       
  2250   if (G_UNLIKELY (size <= 0))
       
  2251     goto next;
       
  2252 
       
  2253   /* last pushed sample was out of boundary, goto next sample */
       
  2254   if (G_UNLIKELY (stream->last_ret == GST_FLOW_UNEXPECTED))
       
  2255     goto next;
       
  2256 
       
  2257   GST_LOG_OBJECT (qtdemux, "reading %d bytes @ %" G_GUINT64_FORMAT, size,
       
  2258       offset);
       
  2259 
       
  2260   ret = gst_qtdemux_pull_atom (qtdemux, offset, size, &buf);
       
  2261   if (G_UNLIKELY (ret != GST_FLOW_OK))
       
  2262     goto beach;
       
  2263 
       
  2264   if (G_UNLIKELY (stream->fourcc == FOURCC_rtsp)) {
       
  2265     GstMessage *m;
       
  2266     gchar *url;
       
  2267 
       
  2268     url = g_strndup ((gchar *) GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
       
  2269 
       
  2270     /* we have RTSP redirect now */
       
  2271     m = gst_message_new_element (GST_OBJECT_CAST (qtdemux),
       
  2272         gst_structure_new ("redirect",
       
  2273             "new-location", G_TYPE_STRING, url, NULL));
       
  2274     g_free (url);
       
  2275 
       
  2276     gst_element_post_message (GST_ELEMENT_CAST (qtdemux), m);
       
  2277   }
       
  2278 
       
  2279   qtdemux->last_ts = min_time;
       
  2280   if (qtdemux->segment.rate >= 0) {
       
  2281     gst_segment_set_last_stop (&qtdemux->segment, GST_FORMAT_TIME, min_time);
       
  2282     gst_qtdemux_sync_streams (qtdemux);
       
  2283   }
       
  2284   if (G_LIKELY (stream->pad)) {
       
  2285     /* we're going to modify the metadata */
       
  2286     buf = gst_buffer_make_metadata_writable (buf);
       
  2287 
       
  2288     GST_BUFFER_TIMESTAMP (buf) = timestamp;
       
  2289     GST_BUFFER_DURATION (buf) = duration;
       
  2290     GST_BUFFER_OFFSET (buf) = -1;
       
  2291     GST_BUFFER_OFFSET_END (buf) = -1;
       
  2292 
       
  2293     if (stream->need_clip)
       
  2294       buf = gst_qtdemux_clip_buffer (qtdemux, stream, buf);
       
  2295 
       
  2296     if (buf == NULL)
       
  2297       goto next;
       
  2298 
       
  2299     if (stream->discont) {
       
  2300       GST_LOG_OBJECT (qtdemux, "marking discont buffer");
       
  2301       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
       
  2302       stream->discont = FALSE;
       
  2303     }
       
  2304 
       
  2305     if (!keyframe)
       
  2306       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
       
  2307 
       
  2308     gst_buffer_set_caps (buf, stream->caps);
       
  2309 
       
  2310     GST_LOG_OBJECT (qtdemux,
       
  2311         "Pushing buffer with time %" GST_TIME_FORMAT ", duration %"
       
  2312         GST_TIME_FORMAT " on pad %s",
       
  2313         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
       
  2314         GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_PAD_NAME (stream->pad));
       
  2315 
       
  2316     ret = gst_pad_push (stream->pad, buf);
       
  2317   } else {
       
  2318     GST_DEBUG_OBJECT (qtdemux, "No output pad for stream, ignoring");
       
  2319     gst_buffer_unref (buf);
       
  2320     ret = GST_FLOW_OK;
       
  2321   }
       
  2322 
       
  2323   /* combine flows */
       
  2324   ret = gst_qtdemux_combine_flows (qtdemux, stream, ret);
       
  2325   /* ignore unlinked, we will not push on the pad anymore and we will EOS when
       
  2326    * we have no more data for the pad to push */
       
  2327   if (ret == GST_FLOW_UNEXPECTED)
       
  2328     ret = GST_FLOW_OK;
       
  2329 
       
  2330 next:
       
  2331   gst_qtdemux_advance_sample (qtdemux, stream);
       
  2332 
       
  2333 beach:
       
  2334   return ret;
       
  2335 
       
  2336   /* special cases */
       
  2337 eos:
       
  2338   {
       
  2339     GST_DEBUG_OBJECT (qtdemux, "No samples left for any streams - EOS");
       
  2340     ret = GST_FLOW_UNEXPECTED;
       
  2341     goto beach;
       
  2342   }
       
  2343 eos_stream:
       
  2344   {
       
  2345     GST_DEBUG_OBJECT (qtdemux, "No samples left for stream");
       
  2346     /* EOS will be raised if all are EOS */
       
  2347     ret = GST_FLOW_OK;
       
  2348     goto beach;
       
  2349   }
       
  2350 }
       
  2351 
       
  2352 static void
       
  2353 gst_qtdemux_loop (GstPad * pad)
       
  2354 {
       
  2355   GstQTDemux *qtdemux;
       
  2356   guint64 cur_offset;
       
  2357   GstFlowReturn ret;
       
  2358 
       
  2359   qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
       
  2360 
       
  2361   cur_offset = qtdemux->offset;
       
  2362   GST_LOG_OBJECT (qtdemux, "loop at position %" G_GUINT64_FORMAT ", state %d",
       
  2363       cur_offset, qtdemux->state);
       
  2364 
       
  2365   switch (qtdemux->state) {
       
  2366     case QTDEMUX_STATE_INITIAL:
       
  2367     case QTDEMUX_STATE_HEADER:
       
  2368       ret = gst_qtdemux_loop_state_header (qtdemux);
       
  2369       break;
       
  2370     case QTDEMUX_STATE_MOVIE:
       
  2371       ret = gst_qtdemux_loop_state_movie (qtdemux);
       
  2372       if (qtdemux->segment.rate < 0 && ret == GST_FLOW_UNEXPECTED) {
       
  2373         ret = gst_qtdemux_seek_to_previous_keyframe (qtdemux);
       
  2374       }
       
  2375       break;
       
  2376     default:
       
  2377       /* ouch */
       
  2378       goto invalid_state;
       
  2379   }
       
  2380 
       
  2381   /* if something went wrong, pause */
       
  2382   if (ret != GST_FLOW_OK)
       
  2383     goto pause;
       
  2384 
       
  2385 done:
       
  2386   gst_object_unref (qtdemux);
       
  2387   return;
       
  2388 
       
  2389   /* ERRORS */
       
  2390 invalid_state:
       
  2391   {
       
  2392     GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
       
  2393         (NULL), ("streaming stopped, invalid state"));
       
  2394     qtdemux->segment_running = FALSE;
       
  2395     gst_pad_pause_task (pad);
       
  2396     gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
       
  2397     goto done;
       
  2398   }
       
  2399 pause:
       
  2400   {
       
  2401     const gchar *reason = gst_flow_get_name (ret);
       
  2402 
       
  2403     GST_LOG_OBJECT (qtdemux, "pausing task, reason %s", reason);
       
  2404 
       
  2405     qtdemux->segment_running = FALSE;
       
  2406     gst_pad_pause_task (pad);
       
  2407 
       
  2408     /* fatal errors need special actions */
       
  2409     if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
       
  2410       /* check EOS */
       
  2411       if (ret == GST_FLOW_UNEXPECTED) {
       
  2412         if (qtdemux->n_streams == 0) {
       
  2413           /* we have no streams, post an error */
       
  2414           GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
       
  2415               (_("This file contains no playable streams.")),
       
  2416               ("no known streams found"));
       
  2417         }
       
  2418         if (qtdemux->segment.flags & GST_SEEK_FLAG_SEGMENT) {
       
  2419           gint64 stop;
       
  2420 
       
  2421           /* FIXME: I am not sure this is the right fix. If the sinks are
       
  2422            * supposed to detect the segment is complete and accumulate 
       
  2423            * automatically, it does not seem to work here. Need more work */
       
  2424           qtdemux->segment_running = TRUE;
       
  2425 
       
  2426           if ((stop = qtdemux->segment.stop) == -1)
       
  2427             stop = qtdemux->segment.duration;
       
  2428 
       
  2429           if (qtdemux->segment.rate >= 0) {
       
  2430             GST_LOG_OBJECT (qtdemux, "Sending segment done, at end of segment");
       
  2431             gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
       
  2432                 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
       
  2433                     GST_FORMAT_TIME, stop));
       
  2434           } else {
       
  2435             /*  For Reverse Playback */
       
  2436             GST_LOG_OBJECT (qtdemux,
       
  2437                 "Sending segment done, at start of segment");
       
  2438             gst_element_post_message (GST_ELEMENT_CAST (qtdemux),
       
  2439                 gst_message_new_segment_done (GST_OBJECT_CAST (qtdemux),
       
  2440                     GST_FORMAT_TIME, qtdemux->segment.start));
       
  2441           }
       
  2442         } else {
       
  2443           GST_LOG_OBJECT (qtdemux, "Sending EOS at end of segment");
       
  2444           gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
       
  2445         }
       
  2446       } else {
       
  2447         GST_ELEMENT_ERROR (qtdemux, STREAM, FAILED,
       
  2448             (NULL), ("streaming stopped, reason %s", reason));
       
  2449         gst_qtdemux_push_event (qtdemux, gst_event_new_eos ());
       
  2450       }
       
  2451     }
       
  2452     goto done;
       
  2453   }
       
  2454 }
       
  2455 
       
  2456 /*
       
  2457  * next_entry_size
       
  2458  *
       
  2459  * Returns the size of the first entry at the current offset.
       
  2460  * If -1, there are none (which means EOS or empty file).
       
  2461  */
       
  2462 static guint64
       
  2463 next_entry_size (GstQTDemux * demux)
       
  2464 {
       
  2465   QtDemuxStream *stream;
       
  2466   int i;
       
  2467   int smallidx = -1;
       
  2468   guint64 smalloffs = (guint64) - 1;
       
  2469 
       
  2470   GST_LOG_OBJECT (demux, "Finding entry at offset %lld", demux->offset);
       
  2471 
       
  2472   for (i = 0; i < demux->n_streams; i++) {
       
  2473     stream = demux->streams[i];
       
  2474 
       
  2475     if (stream->sample_index == -1)
       
  2476       stream->sample_index = 0;
       
  2477 
       
  2478     if (stream->sample_index >= stream->n_samples) {
       
  2479       GST_LOG_OBJECT (demux, "stream %d samples exhausted", i);
       
  2480       continue;
       
  2481     }
       
  2482 
       
  2483     GST_LOG_OBJECT (demux,
       
  2484         "Checking Stream %d (sample_index:%d / offset:%lld / size:%d)",
       
  2485         i, stream->sample_index, stream->samples[stream->sample_index].offset,
       
  2486         stream->samples[stream->sample_index].size);
       
  2487 
       
  2488     if (((smalloffs == -1)
       
  2489             || (stream->samples[stream->sample_index].offset < smalloffs))
       
  2490         && (stream->samples[stream->sample_index].size)) {
       
  2491       smallidx = i;
       
  2492       smalloffs = stream->samples[stream->sample_index].offset;
       
  2493     }
       
  2494   }
       
  2495 
       
  2496   GST_LOG_OBJECT (demux, "stream %d offset %lld demux->offset :%lld",
       
  2497       smallidx, smalloffs, demux->offset);
       
  2498 
       
  2499   if (smallidx == -1)
       
  2500     return -1;
       
  2501   stream = demux->streams[smallidx];
       
  2502 
       
  2503   if (stream->samples[stream->sample_index].offset >= demux->offset) {
       
  2504     demux->todrop =
       
  2505         stream->samples[stream->sample_index].offset - demux->offset;
       
  2506     return stream->samples[stream->sample_index].size + demux->todrop;
       
  2507   }
       
  2508 
       
  2509   GST_DEBUG_OBJECT (demux, "There wasn't any entry at offset %lld",
       
  2510       demux->offset);
       
  2511   return -1;
       
  2512 }
       
  2513 
       
  2514 static void
       
  2515 gst_qtdemux_post_progress (GstQTDemux * demux, gint num, gint denom)
       
  2516 {
       
  2517   gint perc = (gint) ((gdouble) num * 100.0 / (gdouble) denom);
       
  2518 
       
  2519   gst_element_post_message (GST_ELEMENT_CAST (demux),
       
  2520       gst_message_new_element (GST_OBJECT_CAST (demux),
       
  2521           gst_structure_new ("progress", "percent", G_TYPE_INT, perc, NULL)));
       
  2522 }
       
  2523 
       
  2524 /* FIXME, unverified after edit list updates */
       
  2525 static GstFlowReturn
       
  2526 gst_qtdemux_chain (GstPad * sinkpad, GstBuffer * inbuf)
       
  2527 {
       
  2528   GstQTDemux *demux;
       
  2529   GstFlowReturn ret = GST_FLOW_OK;
       
  2530 
       
  2531   demux = GST_QTDEMUX (gst_pad_get_parent (sinkpad));
       
  2532 
       
  2533   gst_adapter_push (demux->adapter, inbuf);
       
  2534 
       
  2535   /* we never really mean to buffer that much */
       
  2536   if (demux->neededbytes == -1)
       
  2537     goto eos;
       
  2538 
       
  2539   GST_DEBUG_OBJECT (demux, "pushing in inbuf %p, neededbytes:%u, available:%u",
       
  2540       inbuf, demux->neededbytes, gst_adapter_available (demux->adapter));
       
  2541 
       
  2542   while (((gst_adapter_available (demux->adapter)) >= demux->neededbytes) &&
       
  2543       (ret == GST_FLOW_OK)) {
       
  2544 
       
  2545     GST_DEBUG_OBJECT (demux,
       
  2546         "state:%d , demux->neededbytes:%d, demux->offset:%lld", demux->state,
       
  2547         demux->neededbytes, demux->offset);
       
  2548 
       
  2549     switch (demux->state) {
       
  2550       case QTDEMUX_STATE_INITIAL:{
       
  2551         const guint8 *data;
       
  2552         guint32 fourcc;
       
  2553         guint64 size;
       
  2554 
       
  2555         data = gst_adapter_peek (demux->adapter, demux->neededbytes);
       
  2556 
       
  2557         /* get fourcc/length, set neededbytes */
       
  2558         extract_initial_length_and_fourcc ((guint8 *) data, &size, &fourcc);
       
  2559         GST_DEBUG_OBJECT (demux, "Peeking found [%" GST_FOURCC_FORMAT "] "
       
  2560             "size: %" G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc), size);
       
  2561         if (size == 0) {
       
  2562           GST_ELEMENT_ERROR (demux, STREAM, DECODE,
       
  2563               (_("This file is invalid and cannot be played.")),
       
  2564               ("initial atom '%" GST_FOURCC_FORMAT "' has empty length",
       
  2565                   GST_FOURCC_ARGS (fourcc)));
       
  2566           ret = GST_FLOW_ERROR;
       
  2567           break;
       
  2568         }
       
  2569         if (fourcc == FOURCC_mdat) {
       
  2570           if (demux->n_streams > 0) {
       
  2571             demux->state = QTDEMUX_STATE_MOVIE;
       
  2572             demux->neededbytes = next_entry_size (demux);
       
  2573           } else {
       
  2574             guint bs;
       
  2575 
       
  2576           buffer_data:
       
  2577             /* there may be multiple mdat (or alike) buffers */
       
  2578             /* sanity check */
       
  2579             if (demux->mdatbuffer)
       
  2580               bs = GST_BUFFER_SIZE (demux->mdatbuffer);
       
  2581             else
       
  2582               bs = 0;
       
  2583             if (size + bs > 10 * (1 << 20))
       
  2584               goto no_moov;
       
  2585             demux->state = QTDEMUX_STATE_BUFFER_MDAT;
       
  2586             demux->neededbytes = size;
       
  2587             if (!demux->mdatbuffer)
       
  2588               demux->mdatoffset = demux->offset;
       
  2589           }
       
  2590         } else if (G_UNLIKELY (size > QTDEMUX_MAX_ATOM_SIZE)) {
       
  2591           GST_ELEMENT_ERROR (demux, STREAM, DECODE,
       
  2592               (_("This file is invalid and cannot be played.")),
       
  2593               ("atom %" GST_FOURCC_FORMAT " has bogus size %" G_GUINT64_FORMAT,
       
  2594                   GST_FOURCC_ARGS (fourcc), size));
       
  2595           ret = GST_FLOW_ERROR;
       
  2596           break;
       
  2597         } else {
       
  2598           /* this means we already started buffering and still no moov header,
       
  2599            * let's continue buffering everything till we get moov */
       
  2600           if (demux->mdatbuffer && (fourcc != FOURCC_moov))
       
  2601             goto buffer_data;
       
  2602           demux->neededbytes = size;
       
  2603           demux->state = QTDEMUX_STATE_HEADER;
       
  2604         }
       
  2605         break;
       
  2606       }
       
  2607       case QTDEMUX_STATE_HEADER:{
       
  2608         const guint8 *data;
       
  2609         guint32 fourcc;
       
  2610 
       
  2611         GST_DEBUG_OBJECT (demux, "In header");
       
  2612 
       
  2613         data = gst_adapter_peek (demux->adapter, demux->neededbytes);
       
  2614 
       
  2615         /* parse the header */
       
  2616         extract_initial_length_and_fourcc (data, NULL, &fourcc);
       
  2617         if (fourcc == FOURCC_moov) {
       
  2618           GST_DEBUG_OBJECT (demux, "Parsing [moov]");
       
  2619 
       
  2620           qtdemux_parse_moov (demux, data, demux->neededbytes);
       
  2621           qtdemux_node_dump (demux, demux->moov_node);
       
  2622           qtdemux_parse_tree (demux);
       
  2623 
       
  2624           g_node_destroy (demux->moov_node);
       
  2625           demux->moov_node = NULL;
       
  2626           GST_DEBUG_OBJECT (demux, "Finished parsing the header");
       
  2627         } else {
       
  2628           GST_WARNING_OBJECT (demux,
       
  2629               "Unknown fourcc while parsing header : %" GST_FOURCC_FORMAT,
       
  2630               GST_FOURCC_ARGS (fourcc));
       
  2631           /* Let's jump that one and go back to initial state */
       
  2632         }
       
  2633 
       
  2634         if (demux->mdatbuffer && demux->n_streams) {
       
  2635           GstBuffer *buf;
       
  2636 
       
  2637           /* the mdat was before the header */
       
  2638           GST_DEBUG_OBJECT (demux, "We have n_streams:%d and mdatbuffer:%p",
       
  2639               demux->n_streams, demux->mdatbuffer);
       
  2640           /* restore our adapter/offset view of things with upstream;
       
  2641            * put preceding buffered data ahead of current moov data.
       
  2642            * This should also handle evil mdat, moov, mdat cases and alike */
       
  2643           buf = gst_adapter_take_buffer (demux->adapter,
       
  2644               gst_adapter_available (demux->adapter));
       
  2645           gst_adapter_clear (demux->adapter);
       
  2646           gst_adapter_push (demux->adapter, demux->mdatbuffer);
       
  2647           gst_adapter_push (demux->adapter, buf);
       
  2648           demux->mdatbuffer = NULL;
       
  2649           demux->offset = demux->mdatoffset;
       
  2650           demux->neededbytes = next_entry_size (demux);
       
  2651           demux->state = QTDEMUX_STATE_MOVIE;
       
  2652         } else {
       
  2653           GST_DEBUG_OBJECT (demux, "Carrying on normally");
       
  2654           gst_adapter_flush (demux->adapter, demux->neededbytes);
       
  2655           demux->offset += demux->neededbytes;
       
  2656           demux->neededbytes = 16;
       
  2657           demux->state = QTDEMUX_STATE_INITIAL;
       
  2658         }
       
  2659 
       
  2660         break;
       
  2661       }
       
  2662       case QTDEMUX_STATE_BUFFER_MDAT:{
       
  2663         GstBuffer *buf;
       
  2664 
       
  2665         GST_DEBUG_OBJECT (demux, "Got our buffer at offset %lld",
       
  2666             demux->offset);
       
  2667         buf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
       
  2668         GST_DEBUG_OBJECT (demux, "mdatbuffer starts with %" GST_FOURCC_FORMAT,
       
  2669             GST_FOURCC_ARGS (QT_FOURCC (GST_BUFFER_DATA (buf) + 4)));
       
  2670         if (demux->mdatbuffer)
       
  2671           demux->mdatbuffer = gst_buffer_join (demux->mdatbuffer, buf);
       
  2672         else
       
  2673           demux->mdatbuffer = buf;
       
  2674         demux->offset += demux->neededbytes;
       
  2675         demux->neededbytes = 16;
       
  2676         demux->state = QTDEMUX_STATE_INITIAL;
       
  2677         gst_qtdemux_post_progress (demux, 1, 1);
       
  2678 
       
  2679         break;
       
  2680       }
       
  2681       case QTDEMUX_STATE_MOVIE:{
       
  2682         GstBuffer *outbuf;
       
  2683         QtDemuxStream *stream = NULL;
       
  2684         int i = -1;
       
  2685 
       
  2686         GST_DEBUG_OBJECT (demux, "BEGIN // in MOVIE for offset %lld",
       
  2687             demux->offset);
       
  2688 
       
  2689         if (demux->todrop) {
       
  2690           GST_LOG_OBJECT (demux, "Dropping %d bytes", demux->todrop);
       
  2691           gst_adapter_flush (demux->adapter, demux->todrop);
       
  2692           demux->neededbytes -= demux->todrop;
       
  2693           demux->offset += demux->todrop;
       
  2694         }
       
  2695 
       
  2696         /* Figure out which stream this is packet belongs to */
       
  2697         for (i = 0; i < demux->n_streams; i++) {
       
  2698           stream = demux->streams[i];
       
  2699           if (stream->sample_index >= stream->n_samples)
       
  2700             continue;
       
  2701           GST_LOG_OBJECT (demux,
       
  2702               "Checking stream %d (sample_index:%d / offset:%lld / size:%d)",
       
  2703               i, stream->sample_index,
       
  2704               stream->samples[stream->sample_index].offset,
       
  2705               stream->samples[stream->sample_index].size);
       
  2706 
       
  2707           if (stream->samples[stream->sample_index].offset == demux->offset)
       
  2708             break;
       
  2709         }
       
  2710 
       
  2711         if (G_UNLIKELY (stream == NULL || i == demux->n_streams))
       
  2712           goto unknown_stream;
       
  2713 
       
  2714         /* first buffer? */
       
  2715         /* initial newsegment sent here after having added pads,
       
  2716          * possible others in sink_event */
       
  2717         if (G_UNLIKELY (demux->last_ts == GST_CLOCK_TIME_NONE)) {
       
  2718           gst_qtdemux_push_event (demux,
       
  2719               gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
       
  2720                   0, GST_CLOCK_TIME_NONE, 0));
       
  2721         }
       
  2722 
       
  2723         /* Put data in a buffer, set timestamps, caps, ... */
       
  2724         outbuf = gst_adapter_take_buffer (demux->adapter, demux->neededbytes);
       
  2725         GST_DEBUG_OBJECT (demux, "stream : %" GST_FOURCC_FORMAT,
       
  2726             GST_FOURCC_ARGS (stream->fourcc));
       
  2727 
       
  2728         g_return_val_if_fail (outbuf != NULL, GST_FLOW_ERROR);
       
  2729 
       
  2730         if (stream->samples[stream->sample_index].pts_offset) {
       
  2731           demux->last_ts = stream->samples[stream->sample_index].timestamp;
       
  2732           GST_BUFFER_TIMESTAMP (outbuf) = demux->last_ts +
       
  2733               stream->samples[stream->sample_index].pts_offset;
       
  2734         } else {
       
  2735           GST_BUFFER_TIMESTAMP (outbuf) =
       
  2736               stream->samples[stream->sample_index].timestamp;
       
  2737           demux->last_ts = GST_BUFFER_TIMESTAMP (outbuf);
       
  2738         }
       
  2739         GST_BUFFER_DURATION (outbuf) =
       
  2740             stream->samples[stream->sample_index].duration;
       
  2741         if (!stream->all_keyframe &&
       
  2742             !stream->samples[stream->sample_index].keyframe)
       
  2743           GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
       
  2744 
       
  2745         /* position reporting */
       
  2746         gst_segment_set_last_stop (&demux->segment, GST_FORMAT_TIME,
       
  2747             demux->last_ts);
       
  2748         gst_qtdemux_sync_streams (demux);
       
  2749 
       
  2750         /* send buffer */
       
  2751         if (stream->pad) {
       
  2752           GST_LOG_OBJECT (demux,
       
  2753               "Pushing buffer with time %" GST_TIME_FORMAT " on pad %p",
       
  2754               GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)), stream->pad);
       
  2755           gst_buffer_set_caps (outbuf, stream->caps);
       
  2756           ret = gst_pad_push (stream->pad, outbuf);
       
  2757         } else {
       
  2758           gst_buffer_unref (outbuf);
       
  2759           ret = GST_FLOW_OK;
       
  2760         }
       
  2761 
       
  2762         /* combine flows */
       
  2763         ret = gst_qtdemux_combine_flows (demux, stream, ret);
       
  2764 
       
  2765         stream->sample_index++;
       
  2766 
       
  2767         /* update current offset and figure out size of next buffer */
       
  2768         GST_LOG_OBJECT (demux, "increasing offset %" G_GUINT64_FORMAT " by %u",
       
  2769             demux->offset, demux->neededbytes);
       
  2770         demux->offset += demux->neededbytes;
       
  2771         GST_LOG_OBJECT (demux, "offset is now %lld", demux->offset);
       
  2772 
       
  2773         if ((demux->neededbytes = next_entry_size (demux)) == -1)
       
  2774           goto eos;
       
  2775         break;
       
  2776       }
       
  2777       default:
       
  2778         goto invalid_state;
       
  2779     }
       
  2780   }
       
  2781 
       
  2782   /* when buffering movie data, at least show user something is happening */
       
  2783   if (ret == GST_FLOW_OK && demux->state == QTDEMUX_STATE_BUFFER_MDAT &&
       
  2784       gst_adapter_available (demux->adapter) <= demux->neededbytes) {
       
  2785     gst_qtdemux_post_progress (demux, gst_adapter_available (demux->adapter),
       
  2786         demux->neededbytes);
       
  2787   }
       
  2788 done:
       
  2789   gst_object_unref (demux);
       
  2790 
       
  2791   return ret;
       
  2792 
       
  2793   /* ERRORS */
       
  2794 unknown_stream:
       
  2795   {
       
  2796     GST_ELEMENT_ERROR (demux, STREAM, FAILED, (NULL), ("unknown stream found"));
       
  2797     ret = GST_FLOW_ERROR;
       
  2798     goto done;
       
  2799   }
       
  2800 eos:
       
  2801   {
       
  2802     GST_DEBUG_OBJECT (demux, "no next entry, EOS");
       
  2803     ret = GST_FLOW_UNEXPECTED;
       
  2804     goto done;
       
  2805   }
       
  2806 invalid_state:
       
  2807   {
       
  2808     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
       
  2809         (NULL), ("qtdemuxer invalid state %d", demux->state));
       
  2810     ret = GST_FLOW_ERROR;
       
  2811     goto done;
       
  2812   }
       
  2813 no_moov:
       
  2814   {
       
  2815     GST_ELEMENT_ERROR (demux, STREAM, FAILED,
       
  2816         (NULL), ("no 'moov' atom withing first 10 MB"));
       
  2817     ret = GST_FLOW_ERROR;
       
  2818     goto done;
       
  2819   }
       
  2820 }
       
  2821 
       
  2822 static gboolean
       
  2823 qtdemux_sink_activate (GstPad * sinkpad)
       
  2824 {
       
  2825   if (gst_pad_check_pull_range (sinkpad))
       
  2826     return gst_pad_activate_pull (sinkpad, TRUE);
       
  2827   else
       
  2828     return gst_pad_activate_push (sinkpad, TRUE);
       
  2829 }
       
  2830 
       
  2831 static gboolean
       
  2832 qtdemux_sink_activate_pull (GstPad * sinkpad, gboolean active)
       
  2833 {
       
  2834   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
       
  2835 
       
  2836   if (active) {
       
  2837     demux->pullbased = TRUE;
       
  2838     demux->segment_running = TRUE;
       
  2839     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_qtdemux_loop,
       
  2840         sinkpad);
       
  2841   } else {
       
  2842     demux->segment_running = FALSE;
       
  2843     return gst_pad_stop_task (sinkpad);
       
  2844   }
       
  2845 }
       
  2846 
       
  2847 static gboolean
       
  2848 qtdemux_sink_activate_push (GstPad * sinkpad, gboolean active)
       
  2849 {
       
  2850   GstQTDemux *demux = GST_QTDEMUX (GST_PAD_PARENT (sinkpad));
       
  2851 
       
  2852   demux->pullbased = FALSE;
       
  2853 
       
  2854   return TRUE;
       
  2855 }
       
  2856 
       
  2857 #ifdef HAVE_ZLIB
       
  2858 static void *
       
  2859 qtdemux_zalloc (void *opaque, unsigned int items, unsigned int size)
       
  2860 {
       
  2861   return g_malloc (items * size);
       
  2862 }
       
  2863 
       
  2864 static void
       
  2865 qtdemux_zfree (void *opaque, void *addr)
       
  2866 {
       
  2867   g_free (addr);
       
  2868 }
       
  2869 
       
  2870 static void *
       
  2871 qtdemux_inflate (void *z_buffer, int z_length, int length)
       
  2872 {
       
  2873   guint8 *buffer;
       
  2874   z_stream *z;
       
  2875   int ret;
       
  2876 
       
  2877   z = g_new0 (z_stream, 1);
       
  2878   z->zalloc = qtdemux_zalloc;
       
  2879   z->zfree = qtdemux_zfree;
       
  2880   z->opaque = NULL;
       
  2881 
       
  2882   z->next_in = z_buffer;
       
  2883   z->avail_in = z_length;
       
  2884 
       
  2885   buffer = (guint8 *) g_malloc (length);
       
  2886   ret = inflateInit (z);
       
  2887   while (z->avail_in > 0) {
       
  2888     if (z->avail_out == 0) {
       
  2889       length += 1024;
       
  2890       buffer = (guint8 *) g_realloc (buffer, length);
       
  2891       z->next_out = buffer + z->total_out;
       
  2892       z->avail_out = 1024;
       
  2893     }
       
  2894     ret = inflate (z, Z_SYNC_FLUSH);
       
  2895     if (ret != Z_OK)
       
  2896       break;
       
  2897   }
       
  2898   if (ret != Z_STREAM_END) {
       
  2899     g_warning ("inflate() returned %d", ret);
       
  2900   }
       
  2901 
       
  2902   g_free (z);
       
  2903   return buffer;
       
  2904 }
       
  2905 #endif /* HAVE_ZLIB */
       
  2906 
       
  2907 static gboolean
       
  2908 qtdemux_parse_moov (GstQTDemux * qtdemux, const guint8 * buffer, int length)
       
  2909 {
       
  2910   GNode *cmov;
       
  2911 
       
  2912   qtdemux->moov_node = g_node_new ((guint8 *) buffer);
       
  2913 
       
  2914   GST_DEBUG_OBJECT (qtdemux, "parsing 'moov' atom");
       
  2915   qtdemux_parse_node (qtdemux, qtdemux->moov_node, buffer, length);
       
  2916 
       
  2917   cmov = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_cmov);
       
  2918   if (cmov) {
       
  2919     guint32 method;
       
  2920     GNode *dcom;
       
  2921     GNode *cmvd;
       
  2922 
       
  2923     dcom = qtdemux_tree_get_child_by_type (cmov, FOURCC_dcom);
       
  2924     cmvd = qtdemux_tree_get_child_by_type (cmov, FOURCC_cmvd);
       
  2925     if (dcom == NULL || cmvd == NULL)
       
  2926       goto invalid_compression;
       
  2927 
       
  2928     method = QT_FOURCC ((guint8 *) dcom->data + 8);
       
  2929     switch (method) {
       
  2930 #ifdef HAVE_ZLIB
       
  2931       case GST_MAKE_FOURCC ('z', 'l', 'i', 'b'):{
       
  2932         int uncompressed_length;
       
  2933         int compressed_length;
       
  2934         guint8 *buf;
       
  2935 
       
  2936         uncompressed_length = QT_UINT32 ((guint8 *) cmvd->data + 8);
       
  2937         compressed_length = QT_UINT32 ((guint8 *) cmvd->data + 4) - 12;
       
  2938         GST_LOG ("length = %d", uncompressed_length);
       
  2939 
       
  2940         buf =
       
  2941             (guint8 *) qtdemux_inflate ((guint8 *) cmvd->data + 12,
       
  2942             compressed_length, uncompressed_length);
       
  2943 
       
  2944         qtdemux->moov_node_compressed = qtdemux->moov_node;
       
  2945         qtdemux->moov_node = g_node_new (buf);
       
  2946 
       
  2947         qtdemux_parse_node (qtdemux, qtdemux->moov_node, buf,
       
  2948             uncompressed_length);
       
  2949         break;
       
  2950       }
       
  2951 #endif /* HAVE_ZLIB */
       
  2952       default:
       
  2953         GST_WARNING_OBJECT (qtdemux, "unknown or unhandled header compression "
       
  2954             "type %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (method));
       
  2955         break;
       
  2956     }
       
  2957   }
       
  2958   return TRUE;
       
  2959 
       
  2960   /* ERRORS */
       
  2961 invalid_compression:
       
  2962   {
       
  2963     GST_ERROR_OBJECT (qtdemux, "invalid compressed header");
       
  2964     return FALSE;
       
  2965   }
       
  2966 }
       
  2967 
       
  2968 static gboolean
       
  2969 qtdemux_parse_container (GstQTDemux * qtdemux, GNode * node, const guint8 * buf,
       
  2970     const guint8 * end)
       
  2971 {
       
  2972   while (G_UNLIKELY (buf < end)) {
       
  2973     GNode *child;
       
  2974     guint32 len;
       
  2975 
       
  2976     if (G_UNLIKELY (buf + 4 > end)) {
       
  2977       GST_LOG_OBJECT (qtdemux, "buffer overrun");
       
  2978       break;
       
  2979     }
       
  2980     len = QT_UINT32 (buf);
       
  2981     if (G_UNLIKELY (len == 0)) {
       
  2982       GST_LOG_OBJECT (qtdemux, "empty container");
       
  2983       break;
       
  2984     }
       
  2985     if (G_UNLIKELY (len < 8)) {
       
  2986       GST_WARNING_OBJECT (qtdemux, "length too short (%d < 8)", len);
       
  2987       break;
       
  2988     }
       
  2989     if (G_UNLIKELY (len > (end - buf))) {
       
  2990       GST_WARNING_OBJECT (qtdemux, "length too long (%d > %d)", len, end - buf);
       
  2991       break;
       
  2992     }
       
  2993 
       
  2994     child = g_node_new ((guint8 *) buf);
       
  2995     g_node_append (node, child);
       
  2996     qtdemux_parse_node (qtdemux, child, buf, len);
       
  2997 
       
  2998     buf += len;
       
  2999   }
       
  3000   return TRUE;
       
  3001 }
       
  3002 
       
  3003 static gboolean
       
  3004 qtdemux_parse_theora_extension (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  3005     GNode * xdxt)
       
  3006 {
       
  3007   int len = QT_UINT32 (xdxt->data);
       
  3008   guint8 *buf = xdxt->data;
       
  3009   guint8 *end = buf + len;
       
  3010   GstBuffer *buffer;
       
  3011 
       
  3012   /* skip size and type */
       
  3013   buf += 8;
       
  3014   end -= 8;
       
  3015 
       
  3016   while (buf < end) {
       
  3017     gint size;
       
  3018     guint32 type;
       
  3019 
       
  3020     size = QT_UINT32 (buf);
       
  3021     type = QT_FOURCC (buf + 4);
       
  3022 
       
  3023     GST_LOG_OBJECT (qtdemux, "%p %p", buf, end);
       
  3024 
       
  3025     if (buf + size > end || size <= 0)
       
  3026       break;
       
  3027 
       
  3028     buf += 8;
       
  3029     size -= 8;
       
  3030 
       
  3031     GST_WARNING_OBJECT (qtdemux, "have cookie %" GST_FOURCC_FORMAT,
       
  3032         GST_FOURCC_ARGS (type));
       
  3033 
       
  3034     switch (type) {
       
  3035       case FOURCC_tCtH:
       
  3036         buffer = gst_buffer_new_and_alloc (size);
       
  3037         memcpy (GST_BUFFER_DATA (buffer), buf, size);
       
  3038         stream->buffers = g_slist_append (stream->buffers, buffer);
       
  3039         GST_LOG_OBJECT (qtdemux, "parsing theora header");
       
  3040         break;
       
  3041       case FOURCC_tCt_:
       
  3042         buffer = gst_buffer_new_and_alloc (size);
       
  3043         memcpy (GST_BUFFER_DATA (buffer), buf, size);
       
  3044         stream->buffers = g_slist_append (stream->buffers, buffer);
       
  3045         GST_LOG_OBJECT (qtdemux, "parsing theora comment");
       
  3046         break;
       
  3047       case FOURCC_tCtC:
       
  3048         buffer = gst_buffer_new_and_alloc (size);
       
  3049         memcpy (GST_BUFFER_DATA (buffer), buf, size);
       
  3050         stream->buffers = g_slist_append (stream->buffers, buffer);
       
  3051         GST_LOG_OBJECT (qtdemux, "parsing theora codebook");
       
  3052         break;
       
  3053       default:
       
  3054         GST_WARNING_OBJECT (qtdemux,
       
  3055             "unknown theora cookie %" GST_FOURCC_FORMAT,
       
  3056             GST_FOURCC_ARGS (type));
       
  3057         break;
       
  3058     }
       
  3059     buf += size;
       
  3060   }
       
  3061   return TRUE;
       
  3062 }
       
  3063 
       
  3064 static gboolean
       
  3065 qtdemux_parse_node (GstQTDemux * qtdemux, GNode * node, const guint8 * buffer,
       
  3066     int length)
       
  3067 {
       
  3068   guint32 fourcc;
       
  3069   guint32 node_length;
       
  3070   const QtNodeType *type;
       
  3071   const guint8 *end;
       
  3072 
       
  3073   GST_LOG_OBJECT (qtdemux, "qtdemux_parse buffer %p length %d", buffer, length);
       
  3074 
       
  3075   node_length = QT_UINT32 (buffer);
       
  3076   fourcc = QT_FOURCC (buffer + 4);
       
  3077 
       
  3078   /* ignore empty nodes */
       
  3079   if (G_UNLIKELY (fourcc == 0 || node_length == 8))
       
  3080     return TRUE;
       
  3081 
       
  3082   type = qtdemux_type_get (fourcc);
       
  3083 
       
  3084   end = buffer + length;
       
  3085 
       
  3086   GST_LOG_OBJECT (qtdemux,
       
  3087       "parsing '%" GST_FOURCC_FORMAT "', length=%d, name '%s'",
       
  3088       GST_FOURCC_ARGS (fourcc), node_length, type->name);
       
  3089 
       
  3090   if (type->flags & QT_FLAG_CONTAINER) {
       
  3091     qtdemux_parse_container (qtdemux, node, buffer + 8, end);
       
  3092   } else {
       
  3093     switch (fourcc) {
       
  3094       case FOURCC_stsd:
       
  3095       {
       
  3096         if (node_length < 20) {
       
  3097           GST_LOG_OBJECT (qtdemux, "skipping small stsd box");
       
  3098           break;
       
  3099         }
       
  3100         GST_DEBUG_OBJECT (qtdemux,
       
  3101             "parsing stsd (sample table, sample description) atom");
       
  3102         qtdemux_parse_container (qtdemux, node, buffer + 16, end);
       
  3103         break;
       
  3104       }
       
  3105       case FOURCC_mp4a:
       
  3106       {
       
  3107         guint32 version;
       
  3108         guint32 offset;
       
  3109 
       
  3110         if (length < 20) {
       
  3111           /* small boxes are also inside wave inside the mp4a box */
       
  3112           GST_LOG_OBJECT (qtdemux, "skipping small mp4a box");
       
  3113           break;
       
  3114         }
       
  3115         version = QT_UINT32 (buffer + 16);
       
  3116 
       
  3117         GST_DEBUG_OBJECT (qtdemux, "mp4a version 0x%08x", version);
       
  3118 
       
  3119         /* parse any esds descriptors */
       
  3120         switch (version) {
       
  3121           case 0x00000000:
       
  3122             offset = 0x24;
       
  3123             break;
       
  3124           case 0x00010000:
       
  3125             offset = 0x34;
       
  3126             break;
       
  3127           case 0x00020000:
       
  3128             offset = 0x58;
       
  3129             break;
       
  3130           default:
       
  3131             GST_WARNING_OBJECT (qtdemux, "unhandled mp4a version 0x%08x",
       
  3132                 version);
       
  3133             offset = 0;
       
  3134             break;
       
  3135         }
       
  3136         if (offset)
       
  3137           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
       
  3138         break;
       
  3139       }
       
  3140       case FOURCC_mp4v:
       
  3141       {
       
  3142         const guint8 *buf;
       
  3143         guint32 version;
       
  3144         int tlen;
       
  3145 
       
  3146         GST_DEBUG_OBJECT (qtdemux, "parsing in mp4v");
       
  3147         version = QT_UINT32 (buffer + 16);
       
  3148         GST_DEBUG_OBJECT (qtdemux, "version %08x", version);
       
  3149         if (1 || version == 0x00000000) {
       
  3150           buf = buffer + 0x32;
       
  3151 
       
  3152           /* FIXME Quicktime uses PASCAL string while
       
  3153            * the iso format uses C strings. Check the file
       
  3154            * type before attempting to parse the string here. */
       
  3155           tlen = QT_UINT8 (buf);
       
  3156           GST_DEBUG_OBJECT (qtdemux, "tlen = %d", tlen);
       
  3157           buf++;
       
  3158           GST_DEBUG_OBJECT (qtdemux, "string = %.*s", tlen, (char *) buf);
       
  3159           /* the string has a reserved space of 32 bytes so skip
       
  3160            * the remaining 31 */
       
  3161           buf += 31;
       
  3162           buf += 4;             /* and 4 bytes reserved */
       
  3163 
       
  3164           GST_MEMDUMP_OBJECT (qtdemux, "mp4v", buf, end - buf);
       
  3165 
       
  3166           qtdemux_parse_container (qtdemux, node, buf, end);
       
  3167         }
       
  3168         break;
       
  3169       }
       
  3170       case FOURCC_mjp2:
       
  3171       {
       
  3172         qtdemux_parse_container (qtdemux, node, buffer + 86, end);
       
  3173         break;
       
  3174       }
       
  3175       case FOURCC_meta:
       
  3176       {
       
  3177         GST_DEBUG_OBJECT (qtdemux, "parsing meta atom");
       
  3178         qtdemux_parse_container (qtdemux, node, buffer + 12, end);
       
  3179         break;
       
  3180       }
       
  3181       case FOURCC_XiTh:
       
  3182       {
       
  3183         guint32 version;
       
  3184         guint32 offset;
       
  3185 
       
  3186         version = QT_UINT32 (buffer + 12);
       
  3187         GST_DEBUG_OBJECT (qtdemux, "parsing XiTh atom version 0x%08x", version);
       
  3188 
       
  3189         switch (version) {
       
  3190           case 0x00000001:
       
  3191             offset = 0x62;
       
  3192             break;
       
  3193           default:
       
  3194             GST_DEBUG_OBJECT (qtdemux, "unknown version 0x%08x", version);
       
  3195             offset = 0;
       
  3196             break;
       
  3197         }
       
  3198         if (offset)
       
  3199           qtdemux_parse_container (qtdemux, node, buffer + offset, end);
       
  3200         break;
       
  3201       }
       
  3202       case FOURCC_in24:
       
  3203       {
       
  3204         qtdemux_parse_container (qtdemux, node, buffer + 0x34, end);
       
  3205         break;
       
  3206       }
       
  3207       default:
       
  3208         if (!strcmp (type->name, "unknown"))
       
  3209           GST_MEMDUMP ("Unknown tag", buffer + 4, end - buffer - 4);
       
  3210         break;
       
  3211     }
       
  3212   }
       
  3213   GST_LOG_OBJECT (qtdemux, "parsed '%" GST_FOURCC_FORMAT,
       
  3214       GST_FOURCC_ARGS (fourcc));
       
  3215   return TRUE;
       
  3216 }
       
  3217 
       
  3218 static GNode *
       
  3219 qtdemux_tree_get_child_by_type (GNode * node, guint32 fourcc)
       
  3220 {
       
  3221   GNode *child;
       
  3222   guint8 *buffer;
       
  3223   guint32 child_fourcc;
       
  3224 
       
  3225   for (child = g_node_first_child (node); child;
       
  3226       child = g_node_next_sibling (child)) {
       
  3227     buffer = (guint8 *) child->data;
       
  3228 
       
  3229     child_fourcc = QT_FOURCC (buffer + 4);
       
  3230 
       
  3231     if (G_UNLIKELY (child_fourcc == fourcc)) {
       
  3232       return child;
       
  3233     }
       
  3234   }
       
  3235   return NULL;
       
  3236 }
       
  3237 
       
  3238 static GNode *
       
  3239 qtdemux_tree_get_sibling_by_type (GNode * node, guint32 fourcc)
       
  3240 {
       
  3241   GNode *child;
       
  3242   guint8 *buffer;
       
  3243   guint32 child_fourcc;
       
  3244 
       
  3245   for (child = g_node_next_sibling (node); child;
       
  3246       child = g_node_next_sibling (child)) {
       
  3247     buffer = (guint8 *) child->data;
       
  3248 
       
  3249     child_fourcc = QT_FOURCC (buffer + 4);
       
  3250 
       
  3251     if (child_fourcc == fourcc) {
       
  3252       return child;
       
  3253     }
       
  3254   }
       
  3255   return NULL;
       
  3256 }
       
  3257 
       
  3258 static gboolean
       
  3259 gst_qtdemux_add_stream (GstQTDemux * qtdemux,
       
  3260     QtDemuxStream * stream, GstTagList * list)
       
  3261 {
       
  3262   if (qtdemux->n_streams >= GST_QTDEMUX_MAX_STREAMS)
       
  3263     goto too_many_streams;
       
  3264 
       
  3265   if (stream->subtype == FOURCC_vide) {
       
  3266     gchar *name = g_strdup_printf ("video_%02d", qtdemux->n_video_streams);
       
  3267 
       
  3268     stream->pad =
       
  3269         gst_pad_new_from_static_template (&gst_qtdemux_videosrc_template, name);
       
  3270     g_free (name);
       
  3271 
       
  3272     /* fps is calculated base on the duration of the first frames since
       
  3273      * qt does not have a fixed framerate. */
       
  3274     if ((stream->n_samples == 1) && (stream->min_duration == 0)) {
       
  3275       /* still frame */
       
  3276       stream->fps_n = 0;
       
  3277       stream->fps_d = 1;
       
  3278     } else {
       
  3279       stream->fps_n = stream->timescale;
       
  3280       if (stream->min_duration == 0)
       
  3281         stream->fps_d = 1;
       
  3282       else
       
  3283         stream->fps_d = stream->min_duration;
       
  3284     }
       
  3285 
       
  3286     if (stream->caps) {
       
  3287       gboolean gray;
       
  3288       gint depth, palette_count;
       
  3289       const guint32 *palette_data = NULL;
       
  3290 
       
  3291       gst_caps_set_simple (stream->caps,
       
  3292           "width", G_TYPE_INT, stream->width,
       
  3293           "height", G_TYPE_INT, stream->height,
       
  3294           "framerate", GST_TYPE_FRACTION, stream->fps_n, stream->fps_d, NULL);
       
  3295 
       
  3296       /* iso files:
       
  3297        * calculate pixel-aspect-ratio using display width and height */
       
  3298       if (qtdemux->major_brand != FOURCC_qt__) {
       
  3299         GST_DEBUG_OBJECT (qtdemux,
       
  3300             "video size %dx%d, target display size %dx%d", stream->width,
       
  3301             stream->height, stream->display_width, stream->display_height);
       
  3302 
       
  3303         if (stream->display_width > 0 && stream->display_height > 0 &&
       
  3304             stream->width > 0 && stream->height > 0) {
       
  3305           gint n, d;
       
  3306 
       
  3307           /* calculate the pixel aspect ratio using the display and pixel w/h */
       
  3308           n = stream->display_width * stream->height;
       
  3309           d = stream->display_height * stream->width;
       
  3310           if (n != d) {
       
  3311             GST_DEBUG_OBJECT (qtdemux, "setting PAR to %d/%d", n, d);
       
  3312             gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
       
  3313                 GST_TYPE_FRACTION, n, d, NULL);
       
  3314           }
       
  3315         }
       
  3316       }
       
  3317 
       
  3318       /* qt file might have pasp atom */
       
  3319       if (stream->par_w > 0 && stream->par_h > 0) {
       
  3320         GST_DEBUG_OBJECT (qtdemux, "par %d:%d", stream->par_w, stream->par_h);
       
  3321         gst_caps_set_simple (stream->caps, "pixel-aspect-ratio",
       
  3322             GST_TYPE_FRACTION, stream->par_w, stream->par_h, NULL);
       
  3323       }
       
  3324 
       
  3325       depth = stream->bits_per_sample;
       
  3326 
       
  3327       /* more than 32 bits means grayscale */
       
  3328       gray = (depth > 32);
       
  3329       /* low 32 bits specify the depth  */
       
  3330       depth &= 0x1F;
       
  3331 
       
  3332       /* different number of palette entries is determined by depth. */
       
  3333       palette_count = 0;
       
  3334       if ((depth == 1) || (depth == 2) || (depth == 4) || (depth == 8))
       
  3335         palette_count = (1 << depth);
       
  3336 
       
  3337       switch (palette_count) {
       
  3338         case 0:
       
  3339           break;
       
  3340         case 2:
       
  3341           palette_data = ff_qt_default_palette_2;
       
  3342           break;
       
  3343         case 4:
       
  3344           palette_data = ff_qt_default_palette_4;
       
  3345           break;
       
  3346         case 16:
       
  3347           if (gray)
       
  3348             palette_data = ff_qt_grayscale_palette_16;
       
  3349           else
       
  3350             palette_data = ff_qt_default_palette_16;
       
  3351           break;
       
  3352         case 256:
       
  3353           if (gray)
       
  3354             palette_data = ff_qt_grayscale_palette_256;
       
  3355           else
       
  3356             palette_data = ff_qt_default_palette_256;
       
  3357           break;
       
  3358         default:
       
  3359           GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
       
  3360               (_("The video in this file might not play correctly.")),
       
  3361               ("unsupported palette depth %d", depth));
       
  3362           break;
       
  3363       }
       
  3364       if (palette_data) {
       
  3365         GstBuffer *palette;
       
  3366 
       
  3367         /* make sure it's not writable. We leave MALLOCDATA to NULL so that we
       
  3368          * don't free any of the buffer data. */
       
  3369         palette = gst_buffer_new ();
       
  3370         GST_BUFFER_FLAG_SET (palette, GST_BUFFER_FLAG_READONLY);
       
  3371         GST_BUFFER_DATA (palette) = (guint8 *) palette_data;
       
  3372         GST_BUFFER_SIZE (palette) = sizeof (guint32) * palette_count;
       
  3373 
       
  3374         gst_caps_set_simple (stream->caps, "palette_data",
       
  3375             GST_TYPE_BUFFER, palette, NULL);
       
  3376         gst_buffer_unref (palette);
       
  3377       } else if (palette_count != 0) {
       
  3378         GST_ELEMENT_WARNING (qtdemux, STREAM, NOT_IMPLEMENTED,
       
  3379             (NULL), ("Unsupported palette depth %d. Ignoring stream.", depth));
       
  3380 
       
  3381         gst_object_unref (stream->pad);
       
  3382         stream->pad = NULL;
       
  3383       }
       
  3384     }
       
  3385     qtdemux->n_video_streams++;
       
  3386   } else if (stream->subtype == FOURCC_soun) {
       
  3387     gchar *name = g_strdup_printf ("audio_%02d", qtdemux->n_audio_streams);
       
  3388 
       
  3389     stream->pad =
       
  3390         gst_pad_new_from_static_template (&gst_qtdemux_audiosrc_template, name);
       
  3391     g_free (name);
       
  3392     if (stream->caps) {
       
  3393       gst_caps_set_simple (stream->caps,
       
  3394           "rate", G_TYPE_INT, (int) stream->rate,
       
  3395           "channels", G_TYPE_INT, stream->n_channels, NULL);
       
  3396     }
       
  3397     qtdemux->n_audio_streams++;
       
  3398   } else if (stream->subtype == FOURCC_strm) {
       
  3399     GST_DEBUG_OBJECT (qtdemux, "stream type, not creating pad");
       
  3400   } else if (stream->subtype == FOURCC_subp) {
       
  3401     gchar *name = g_strdup_printf ("subp_%02d", qtdemux->n_subp_streams);
       
  3402 
       
  3403     stream->pad =
       
  3404         gst_pad_new_from_static_template (&gst_qtdemux_subpsrc_template, name);
       
  3405     g_free (name);
       
  3406     qtdemux->n_subp_streams++;
       
  3407   } else {
       
  3408     GST_DEBUG_OBJECT (qtdemux, "unknown stream type");
       
  3409     goto done;
       
  3410   }
       
  3411 
       
  3412   qtdemux->streams[qtdemux->n_streams] = stream;
       
  3413   qtdemux->n_streams++;
       
  3414   GST_DEBUG_OBJECT (qtdemux, "n_streams is now %d", qtdemux->n_streams);
       
  3415 
       
  3416   if (stream->pad) {
       
  3417     GST_PAD_ELEMENT_PRIVATE (stream->pad) = stream;
       
  3418 
       
  3419     gst_pad_use_fixed_caps (stream->pad);
       
  3420     gst_pad_set_event_function (stream->pad, gst_qtdemux_handle_src_event);
       
  3421     gst_pad_set_query_type_function (stream->pad,
       
  3422         gst_qtdemux_get_src_query_types);
       
  3423     gst_pad_set_query_function (stream->pad, gst_qtdemux_handle_src_query);
       
  3424 
       
  3425     GST_DEBUG_OBJECT (qtdemux, "setting caps %" GST_PTR_FORMAT, stream->caps);
       
  3426     gst_pad_set_caps (stream->pad, stream->caps);
       
  3427 
       
  3428     GST_DEBUG_OBJECT (qtdemux, "adding pad %s %p to qtdemux %p",
       
  3429         GST_OBJECT_NAME (stream->pad), stream->pad, qtdemux);
       
  3430     gst_pad_set_active (stream->pad, TRUE);
       
  3431     gst_element_add_pad (GST_ELEMENT_CAST (qtdemux), stream->pad);
       
  3432     if (list)
       
  3433       gst_element_found_tags_for_pad (GST_ELEMENT_CAST (qtdemux), stream->pad,
       
  3434           list);
       
  3435   }
       
  3436 done:
       
  3437   return TRUE;
       
  3438 
       
  3439 too_many_streams:
       
  3440   {
       
  3441     GST_ELEMENT_WARNING (qtdemux, STREAM, DECODE,
       
  3442         (_("This file contains too many streams. Only playing first %d"),
       
  3443             GST_QTDEMUX_MAX_STREAMS), (NULL));
       
  3444     return TRUE;
       
  3445   }
       
  3446 }
       
  3447 
       
  3448 /* collect all samples for @stream by reading the info from @stbl
       
  3449  */
       
  3450 static gboolean
       
  3451 qtdemux_parse_samples (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  3452     GNode * stbl)
       
  3453 {
       
  3454   GNode *stsc;
       
  3455   GNode *stsz;
       
  3456   GNode *stco;
       
  3457   GNode *co64;
       
  3458   GNode *stts;
       
  3459   GNode *stss;
       
  3460   GNode *stps;
       
  3461   GNode *ctts;
       
  3462   const guint8 *stsc_data, *stsz_data, *stco_data, *co64_data, *stts_data;
       
  3463   int sample_size;
       
  3464   int sample_index;
       
  3465   int n_samples;
       
  3466   int n_samples_per_chunk;
       
  3467   int n_sample_times;
       
  3468   QtDemuxSample *samples;
       
  3469   gint i, j, k;
       
  3470   int index;
       
  3471   guint64 timestamp, time;
       
  3472 
       
  3473   /* sample to chunk */
       
  3474   if (!(stsc = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsc)))
       
  3475     goto corrupt_file;
       
  3476   stsc_data = (const guint8 *) stsc->data;
       
  3477 
       
  3478   /* sample size */
       
  3479   if (!(stsz = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsz)))
       
  3480     goto corrupt_file;
       
  3481   stsz_data = (const guint8 *) stsz->data;
       
  3482 
       
  3483   /* chunk offsets */
       
  3484   stco = qtdemux_tree_get_child_by_type (stbl, FOURCC_stco);
       
  3485   co64 = qtdemux_tree_get_child_by_type (stbl, FOURCC_co64);
       
  3486   if (stco) {
       
  3487     stco_data = (const guint8 *) stco->data;
       
  3488     co64_data = NULL;
       
  3489   } else {
       
  3490     stco_data = NULL;
       
  3491     if (co64 == NULL)
       
  3492       goto corrupt_file;
       
  3493     co64_data = (const guint8 *) co64->data;
       
  3494   }
       
  3495   /* sample time */
       
  3496   if (!(stts = qtdemux_tree_get_child_by_type (stbl, FOURCC_stts)))
       
  3497     goto corrupt_file;
       
  3498   stts_data = (const guint8 *) stts->data;
       
  3499 
       
  3500   sample_size = QT_UINT32 (stsz_data + 12);
       
  3501   if (sample_size == 0 || stream->sampled) {
       
  3502     n_samples = QT_UINT32 (stsz_data + 16);
       
  3503 
       
  3504     if (n_samples == 0)
       
  3505       goto no_samples;
       
  3506     else if (n_samples < 0)
       
  3507       goto corrupt_file;
       
  3508 
       
  3509     GST_DEBUG_OBJECT (qtdemux, "stsz sample_size 0, allocating n_samples %d",
       
  3510         n_samples);
       
  3511 
       
  3512     samples = g_try_new0 (QtDemuxSample, n_samples);
       
  3513     if (samples == NULL)
       
  3514       goto out_of_memory;
       
  3515 
       
  3516     stream->n_samples = n_samples;
       
  3517     stream->samples = samples;
       
  3518 
       
  3519     /* set the sample sizes */
       
  3520     if (sample_size == 0) {
       
  3521       const guint8 *stsz_p = stsz_data + 20;
       
  3522       /* different sizes for each sample */
       
  3523       for (i = 0; i < n_samples; i++) {
       
  3524         samples[i].size = QT_UINT32 (stsz_p);
       
  3525         GST_LOG_OBJECT (qtdemux, "sample %d has size %d", i, samples[i].size);
       
  3526         stsz_p += 4;
       
  3527       }
       
  3528     } else {
       
  3529       /* samples have the same size */
       
  3530       GST_LOG_OBJECT (qtdemux, "all samples have size %d", sample_size);
       
  3531       for (i = 0; i < n_samples; i++)
       
  3532         samples[i].size = sample_size;
       
  3533     }
       
  3534 
       
  3535     /* set the sample offsets in the file */
       
  3536     n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
       
  3537     index = 0;
       
  3538     for (i = 0; i < n_samples_per_chunk; i++) {
       
  3539       guint32 first_chunk, last_chunk;
       
  3540       guint32 samples_per_chunk;
       
  3541 
       
  3542       first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
       
  3543       if (G_UNLIKELY (i == n_samples_per_chunk - 1)) {
       
  3544         last_chunk = G_MAXUINT32;
       
  3545       } else {
       
  3546         last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
       
  3547       }
       
  3548       samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
       
  3549 
       
  3550       for (j = first_chunk; j < last_chunk; j++) {
       
  3551         guint64 chunk_offset;
       
  3552 
       
  3553         if (stco) {
       
  3554           chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
       
  3555         } else {
       
  3556           chunk_offset = QT_UINT64 (co64_data + 16 + j * 8);
       
  3557         }
       
  3558         for (k = 0; k < samples_per_chunk; k++) {
       
  3559           GST_LOG_OBJECT (qtdemux, "Creating entry %d with offset %lld",
       
  3560               index, chunk_offset);
       
  3561           samples[index].offset = chunk_offset;
       
  3562           chunk_offset += samples[index].size;
       
  3563           index++;
       
  3564           if (G_UNLIKELY (index >= n_samples))
       
  3565             goto done2;
       
  3566         }
       
  3567       }
       
  3568     }
       
  3569   done2:
       
  3570 
       
  3571     n_sample_times = QT_UINT32 (stts_data + 12);
       
  3572     GST_LOG_OBJECT (qtdemux, "%u timestamp blocks", n_sample_times);
       
  3573     timestamp = 0;
       
  3574     stream->min_duration = 0;
       
  3575     time = 0;
       
  3576     index = 0;
       
  3577     stts_data += 16;
       
  3578     for (i = 0; i < n_sample_times; i++) {
       
  3579       guint32 n;
       
  3580       guint32 duration;
       
  3581 
       
  3582       n = QT_UINT32 (stts_data);
       
  3583       stts_data += 4;
       
  3584       duration = QT_UINT32 (stts_data);
       
  3585       stts_data += 4;
       
  3586       GST_LOG_OBJECT (qtdemux, "block %d, %u timestamps, duration %u ", i, n,
       
  3587           duration);
       
  3588 
       
  3589       /* take first duration for fps */
       
  3590       if (G_UNLIKELY (stream->min_duration == 0))
       
  3591         stream->min_duration = duration;
       
  3592 
       
  3593       for (j = 0; j < n; j++) {
       
  3594         GST_DEBUG_OBJECT (qtdemux,
       
  3595             "sample %d: index %d, timestamp %" GST_TIME_FORMAT, index, j,
       
  3596             GST_TIME_ARGS (timestamp));
       
  3597 
       
  3598         samples[index].timestamp = timestamp;
       
  3599         /* add non-scaled values to avoid rounding errors */
       
  3600         time += duration;
       
  3601         timestamp = gst_util_uint64_scale (time, GST_SECOND, stream->timescale);
       
  3602         samples[index].duration = timestamp - samples[index].timestamp;
       
  3603 
       
  3604         index++;
       
  3605         if (G_UNLIKELY (index >= n_samples))
       
  3606           goto done3;
       
  3607       }
       
  3608     }
       
  3609     /* fill up empty timestamps with the last timestamp, this can happen when
       
  3610      * the last samples do not decode and so we don't have timestamps for them.
       
  3611      * We however look at the last timestamp to estimate the track length so we
       
  3612      * need something in here. */
       
  3613     for (; index < n_samples; index++) {
       
  3614       GST_DEBUG_OBJECT (qtdemux, "fill sample %d: timestamp %" GST_TIME_FORMAT,
       
  3615           index, GST_TIME_ARGS (timestamp));
       
  3616       samples[index].timestamp = timestamp;
       
  3617       samples[index].duration = -1;
       
  3618     }
       
  3619   done3:
       
  3620 
       
  3621     /* sample sync, can be NULL */
       
  3622     stss = qtdemux_tree_get_child_by_type (stbl, FOURCC_stss);
       
  3623 
       
  3624     if (stss) {
       
  3625       /* mark keyframes */
       
  3626       guint32 n_sample_syncs;
       
  3627       const guint8 *stss_p = (guint8 *) stss->data;
       
  3628 
       
  3629       stss_p += 12;
       
  3630       n_sample_syncs = QT_UINT32 (stss_p);
       
  3631       if (n_sample_syncs == 0) {
       
  3632         stream->all_keyframe = TRUE;
       
  3633       } else {
       
  3634         for (i = 0; i < n_sample_syncs; i++) {
       
  3635           stss_p += 4;
       
  3636           /* note that the first sample is index 1, not 0 */
       
  3637           index = QT_UINT32 (stss_p);
       
  3638           if (G_LIKELY (index > 0 && index <= n_samples))
       
  3639             samples[index - 1].keyframe = TRUE;
       
  3640         }
       
  3641       }
       
  3642       stps = qtdemux_tree_get_child_by_type (stbl, FOURCC_stps);
       
  3643       if (stps) {
       
  3644         /* stps marks partial sync frames like open GOP I-Frames */
       
  3645         guint32 n_sample_syncs;
       
  3646         const guint8 *stps_p = (guint8 *) stps->data;
       
  3647 
       
  3648         stps_p += 12;
       
  3649         n_sample_syncs = QT_UINT32 (stps_p);
       
  3650         if (n_sample_syncs != 0) {
       
  3651           /* no entries, the stss table contains the real sync
       
  3652            * samples */
       
  3653         } else {
       
  3654           for (i = 0; i < n_sample_syncs; i++) {
       
  3655             stps_p += 4;
       
  3656             /* note that the first sample is index 1, not 0 */
       
  3657             index = QT_UINT32 (stps_p);
       
  3658             if (G_LIKELY (index > 0 && index <= n_samples))
       
  3659               samples[index - 1].keyframe = TRUE;
       
  3660           }
       
  3661         }
       
  3662       }
       
  3663     } else {
       
  3664       /* no stss, all samples are keyframes */
       
  3665       stream->all_keyframe = TRUE;
       
  3666     }
       
  3667   } else {
       
  3668     GST_DEBUG_OBJECT (qtdemux,
       
  3669         "stsz sample_size %d != 0, treating chunks as samples", sample_size);
       
  3670     /* treat chunks as samples */
       
  3671     if (stco) {
       
  3672       n_samples = QT_UINT32 (stco_data + 12);
       
  3673     } else {
       
  3674       n_samples = QT_UINT32 (co64_data + 12);
       
  3675     }
       
  3676 
       
  3677     if (n_samples == 0)
       
  3678       goto no_samples;
       
  3679     else if (n_samples < 0)
       
  3680       goto corrupt_file;
       
  3681 
       
  3682     GST_DEBUG_OBJECT (qtdemux, "allocating n_samples %d", n_samples);
       
  3683 
       
  3684     samples = g_try_new0 (QtDemuxSample, n_samples);
       
  3685     if (samples == NULL)
       
  3686       goto out_of_memory;
       
  3687 
       
  3688     stream->n_samples = n_samples;
       
  3689     stream->samples = samples;
       
  3690 
       
  3691     n_samples_per_chunk = QT_UINT32 (stsc_data + 12);
       
  3692     GST_DEBUG_OBJECT (qtdemux, "n_samples_per_chunk %d", n_samples_per_chunk);
       
  3693     sample_index = 0;
       
  3694     timestamp = 0;
       
  3695     for (i = 0; i < n_samples_per_chunk; i++) {
       
  3696       guint32 first_chunk, last_chunk;
       
  3697       guint32 samples_per_chunk;
       
  3698 
       
  3699       first_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 0) - 1;
       
  3700       /* the last chunk of each entry is calculated by taking the first chunk
       
  3701        * of the next entry; except if there is no next, where we fake it with
       
  3702        * INT_MAX */
       
  3703       if (i == n_samples_per_chunk - 1) {
       
  3704         last_chunk = G_MAXUINT32;
       
  3705       } else {
       
  3706         last_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 12) - 1;
       
  3707       }
       
  3708       samples_per_chunk = QT_UINT32 (stsc_data + 16 + i * 12 + 4);
       
  3709 
       
  3710       GST_LOG_OBJECT (qtdemux,
       
  3711           "entry %d has first_chunk %d, last_chunk %d, samples_per_chunk %d", i,
       
  3712           first_chunk, last_chunk, samples_per_chunk);
       
  3713 
       
  3714       for (j = first_chunk; j < last_chunk; j++) {
       
  3715         guint64 chunk_offset;
       
  3716 
       
  3717         if (j >= n_samples)
       
  3718           goto done;
       
  3719 
       
  3720         if (stco) {
       
  3721           chunk_offset = QT_UINT32 (stco_data + 16 + j * 4);
       
  3722         } else {
       
  3723           chunk_offset = QT_UINT64 (co64_data + 16 + j * 8);
       
  3724         }
       
  3725         GST_LOG_OBJECT (qtdemux,
       
  3726             "Creating entry %d with offset %" G_GUINT64_FORMAT, j,
       
  3727             chunk_offset);
       
  3728 
       
  3729         samples[j].offset = chunk_offset;
       
  3730 
       
  3731         if (stream->samples_per_frame * stream->bytes_per_frame) {
       
  3732           samples[j].size = (samples_per_chunk * stream->n_channels) /
       
  3733               stream->samples_per_frame * stream->bytes_per_frame;
       
  3734         } else {
       
  3735           samples[j].size = samples_per_chunk;
       
  3736         }
       
  3737 
       
  3738         GST_DEBUG_OBJECT (qtdemux, "sample %d: timestamp %" GST_TIME_FORMAT
       
  3739             ", size %u", j, GST_TIME_ARGS (timestamp), samples[j].size);
       
  3740 
       
  3741         samples[j].timestamp = timestamp;
       
  3742         sample_index += samples_per_chunk;
       
  3743 
       
  3744         timestamp = gst_util_uint64_scale (sample_index,
       
  3745             GST_SECOND, stream->timescale);
       
  3746         samples[j].duration = timestamp - samples[j].timestamp;
       
  3747 
       
  3748         samples[j].keyframe = TRUE;
       
  3749       }
       
  3750     }
       
  3751   }
       
  3752 
       
  3753   /* composition time to sample */
       
  3754   if ((ctts = qtdemux_tree_get_child_by_type (stbl, FOURCC_ctts))) {
       
  3755     const guint8 *ctts_data, *ctts_p;
       
  3756     guint32 n_entries;
       
  3757     guint32 count;
       
  3758     gint32 soffset;
       
  3759 
       
  3760     ctts_data = (const guint8 *) ctts->data;
       
  3761     n_entries = QT_UINT32 (ctts_data + 12);
       
  3762 
       
  3763     /* Fill in the pts_offsets */
       
  3764     index = 0;
       
  3765     ctts_p = ctts_data + 16;
       
  3766     /* FIXME: make sure we don't read beyond the atom size/boundary */
       
  3767     for (i = 0; i < n_entries; i++) {
       
  3768       count = QT_UINT32 (ctts_p);
       
  3769       ctts_p += 4;
       
  3770       soffset = QT_UINT32 (ctts_p);
       
  3771       ctts_p += 4;
       
  3772       for (j = 0; j < count; j++) {
       
  3773         /* we operate with very small soffset values here, it shouldn't overflow */
       
  3774         samples[index].pts_offset = soffset * GST_SECOND / stream->timescale;
       
  3775         index++;
       
  3776         if (G_UNLIKELY (index >= n_samples))
       
  3777           goto done;
       
  3778       }
       
  3779     }
       
  3780   }
       
  3781 done:
       
  3782   return TRUE;
       
  3783 
       
  3784 /* ERRORS */
       
  3785 corrupt_file:
       
  3786   {
       
  3787     GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
       
  3788         (_("This file is corrupt and cannot be played.")), (NULL));
       
  3789     return FALSE;
       
  3790   }
       
  3791 no_samples:
       
  3792   {
       
  3793     GST_WARNING_OBJECT (qtdemux, "stream has no samples");
       
  3794     return FALSE;
       
  3795   }
       
  3796 out_of_memory:
       
  3797   {
       
  3798     GST_WARNING_OBJECT (qtdemux, "failed to allocate %d samples", n_samples);
       
  3799     return FALSE;
       
  3800   }
       
  3801 }
       
  3802 
       
  3803 /* collect all segment info for @stream.
       
  3804  */
       
  3805 static gboolean
       
  3806 qtdemux_parse_segments (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  3807     GNode * trak)
       
  3808 {
       
  3809   GNode *edts;
       
  3810 
       
  3811   /* parse and prepare segment info from the edit list */
       
  3812   GST_DEBUG_OBJECT (qtdemux, "looking for edit list container");
       
  3813   stream->n_segments = 0;
       
  3814   stream->segments = NULL;
       
  3815   if ((edts = qtdemux_tree_get_child_by_type (trak, FOURCC_edts))) {
       
  3816     GNode *elst;
       
  3817     gint n_segments;
       
  3818     gint i, count;
       
  3819     guint64 time, stime;
       
  3820     guint8 *buffer;
       
  3821 
       
  3822     GST_DEBUG_OBJECT (qtdemux, "looking for edit list");
       
  3823     if (!(elst = qtdemux_tree_get_child_by_type (edts, FOURCC_elst)))
       
  3824       goto done;
       
  3825 
       
  3826     buffer = elst->data;
       
  3827 
       
  3828     n_segments = QT_UINT32 (buffer + 12);
       
  3829 
       
  3830     /* we might allocate a bit too much, at least allocate 1 segment */
       
  3831     stream->segments = g_new (QtDemuxSegment, MAX (n_segments, 1));
       
  3832 
       
  3833     /* segments always start from 0 */
       
  3834     time = 0;
       
  3835     stime = 0;
       
  3836     count = 0;
       
  3837     for (i = 0; i < n_segments; i++) {
       
  3838       guint64 duration;
       
  3839       guint64 media_time;
       
  3840       QtDemuxSegment *segment;
       
  3841       guint32 rate_int;
       
  3842 
       
  3843       media_time = QT_UINT32 (buffer + 20 + i * 12);
       
  3844 
       
  3845       /* -1 media time is an empty segment, just ignore it */
       
  3846       if (media_time == G_MAXUINT32)
       
  3847         continue;
       
  3848 
       
  3849       duration = QT_UINT32 (buffer + 16 + i * 12);
       
  3850 
       
  3851       segment = &stream->segments[count++];
       
  3852 
       
  3853       /* time and duration expressed in global timescale */
       
  3854       segment->time = stime;
       
  3855       /* add non scaled values so we don't cause roundoff errors */
       
  3856       time += duration;
       
  3857       stime = gst_util_uint64_scale (time, GST_SECOND, qtdemux->timescale);
       
  3858       segment->stop_time = stime;
       
  3859       segment->duration = stime - segment->time;
       
  3860       /* media_time expressed in stream timescale */
       
  3861       segment->media_start =
       
  3862           gst_util_uint64_scale (media_time, GST_SECOND, stream->timescale);
       
  3863       segment->media_stop = segment->media_start + segment->duration;
       
  3864       rate_int = GST_READ_UINT32_BE (buffer + 24 + i * 12);
       
  3865 
       
  3866       if (rate_int <= 1) {
       
  3867         /* 0 is not allowed, some programs write 1 instead of the floating point
       
  3868          * value */
       
  3869         GST_WARNING_OBJECT (qtdemux, "found suspicious rate %" G_GUINT32_FORMAT,
       
  3870             rate_int);
       
  3871         segment->rate = 1;
       
  3872       } else {
       
  3873         segment->rate = rate_int / 65536.0;
       
  3874       }
       
  3875 
       
  3876       GST_DEBUG_OBJECT (qtdemux, "created segment %d time %" GST_TIME_FORMAT
       
  3877           ", duration %" GST_TIME_FORMAT ", media_time %" GST_TIME_FORMAT
       
  3878           ", rate %g, (%d)", i, GST_TIME_ARGS (segment->time),
       
  3879           GST_TIME_ARGS (segment->duration),
       
  3880           GST_TIME_ARGS (segment->media_start), segment->rate, rate_int);
       
  3881     }
       
  3882     GST_DEBUG_OBJECT (qtdemux, "found %d non-empty segments", count);
       
  3883     stream->n_segments = count;
       
  3884   }
       
  3885 done:
       
  3886 
       
  3887   /* push based does not handle segments, so act accordingly here,
       
  3888    * and warn if applicable */
       
  3889   if (!qtdemux->pullbased) {
       
  3890     GST_WARNING_OBJECT (qtdemux, "streaming; discarding edit list segments");
       
  3891     /* remove and use default one below, we stream like it anyway */
       
  3892     g_free (stream->segments);
       
  3893     stream->segments = NULL;
       
  3894     stream->n_segments = 0;
       
  3895   }
       
  3896 
       
  3897   /* no segments, create one to play the complete trak */
       
  3898   if (stream->n_segments == 0) {
       
  3899     GstClockTime stream_duration = 0;
       
  3900 
       
  3901     if (stream->segments == NULL)
       
  3902       stream->segments = g_new (QtDemuxSegment, 1);
       
  3903 
       
  3904     /* samples know best */
       
  3905     if (stream->n_samples > 0) {
       
  3906       stream_duration =
       
  3907           stream->samples[stream->n_samples - 1].timestamp +
       
  3908           stream->samples[stream->n_samples - 1].pts_offset +
       
  3909           stream->samples[stream->n_samples - 1].duration;
       
  3910     }
       
  3911 
       
  3912     stream->segments[0].time = 0;
       
  3913     stream->segments[0].stop_time = stream_duration;
       
  3914     stream->segments[0].duration = stream_duration;
       
  3915     stream->segments[0].media_start = 0;
       
  3916     stream->segments[0].media_stop = stream_duration;
       
  3917     stream->segments[0].rate = 1.0;
       
  3918 
       
  3919     GST_DEBUG_OBJECT (qtdemux, "created dummy segment %" GST_TIME_FORMAT,
       
  3920         GST_TIME_ARGS (stream_duration));
       
  3921     stream->n_segments = 1;
       
  3922   }
       
  3923   GST_DEBUG_OBJECT (qtdemux, "using %d segments", stream->n_segments);
       
  3924 
       
  3925   return TRUE;
       
  3926 }
       
  3927 
       
  3928 /* parse the traks.
       
  3929  * With each track we associate a new QtDemuxStream that contains all the info
       
  3930  * about the trak.
       
  3931  * traks that do not decode to something (like strm traks) will not have a pad.
       
  3932  */
       
  3933 static gboolean
       
  3934 qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
       
  3935 {
       
  3936   int offset;
       
  3937   GNode *tkhd;
       
  3938   GNode *mdia;
       
  3939   GNode *mdhd;
       
  3940   GNode *hdlr;
       
  3941   GNode *minf;
       
  3942   GNode *stbl;
       
  3943   GNode *stsd;
       
  3944   GNode *mp4a;
       
  3945   GNode *mp4v;
       
  3946   GNode *wave;
       
  3947   GNode *esds;
       
  3948   GNode *pasp;
       
  3949   QtDemuxStream *stream;
       
  3950   GstTagList *list = NULL;
       
  3951   gchar *codec = NULL;
       
  3952   const guint8 *stsd_data;
       
  3953   guint32 version;
       
  3954 
       
  3955   stream = g_new0 (QtDemuxStream, 1);
       
  3956   /* new streams always need a discont */
       
  3957   stream->discont = TRUE;
       
  3958   /* we enable clipping for raw audio/video streams */
       
  3959   stream->need_clip = FALSE;
       
  3960   stream->segment_index = -1;
       
  3961   stream->time_position = 0;
       
  3962   stream->sample_index = -1;
       
  3963   stream->last_ret = GST_FLOW_OK;
       
  3964 
       
  3965   if (!(tkhd = qtdemux_tree_get_child_by_type (trak, FOURCC_tkhd)))
       
  3966     goto corrupt_file;
       
  3967 
       
  3968   GST_LOG_OBJECT (qtdemux, "track[tkhd] version/flags: 0x%08x",
       
  3969       QT_UINT32 ((guint8 *) tkhd->data + 8));
       
  3970 
       
  3971   if (!(mdia = qtdemux_tree_get_child_by_type (trak, FOURCC_mdia)))
       
  3972     goto corrupt_file;
       
  3973 
       
  3974   if (!(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mdhd))) {
       
  3975     /* be nice for some crooked mjp2 files that use mhdr for mdhd */
       
  3976     if (qtdemux->major_brand != FOURCC_mjp2 ||
       
  3977         !(mdhd = qtdemux_tree_get_child_by_type (mdia, FOURCC_mhdr)))
       
  3978       goto corrupt_file;
       
  3979   }
       
  3980 
       
  3981   version = QT_UINT32 ((guint8 *) mdhd->data + 8);
       
  3982   GST_LOG_OBJECT (qtdemux, "track version/flags: %08x", version);
       
  3983   if (version == 0x01000000) {
       
  3984     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 28);
       
  3985     stream->duration = QT_UINT64 ((guint8 *) mdhd->data + 32);
       
  3986   } else {
       
  3987     stream->timescale = QT_UINT32 ((guint8 *) mdhd->data + 20);
       
  3988     stream->duration = QT_UINT32 ((guint8 *) mdhd->data + 24);
       
  3989   }
       
  3990 
       
  3991   GST_LOG_OBJECT (qtdemux, "track timescale: %" G_GUINT32_FORMAT,
       
  3992       stream->timescale);
       
  3993   GST_LOG_OBJECT (qtdemux, "track duration: %" G_GUINT64_FORMAT,
       
  3994       stream->duration);
       
  3995 
       
  3996   if (G_UNLIKELY (stream->timescale == 0 || qtdemux->timescale == 0))
       
  3997     goto corrupt_file;
       
  3998 
       
  3999   if (qtdemux->duration != G_MAXINT32 && stream->duration != G_MAXINT32) {
       
  4000     guint64 tdur1, tdur2;
       
  4001 
       
  4002     /* don't overflow */
       
  4003     tdur1 = stream->timescale * (guint64) qtdemux->duration;
       
  4004     tdur2 = qtdemux->timescale * (guint64) stream->duration;
       
  4005 
       
  4006     /* HACK:
       
  4007      * some of those trailers, nowadays, have prologue images that are
       
  4008      * themselves vide tracks as well. I haven't really found a way to
       
  4009      * identify those yet, except for just looking at their duration. */
       
  4010     if (tdur1 != 0 && (tdur2 * 10 / tdur1) < 2) {
       
  4011       GST_WARNING_OBJECT (qtdemux,
       
  4012           "Track shorter than 20%% (%" G_GUINT64_FORMAT "/%" G_GUINT32_FORMAT
       
  4013           " vs. %" G_GUINT32_FORMAT "/%" G_GUINT32_FORMAT ") of the stream "
       
  4014           "found, assuming preview image or something; skipping track",
       
  4015           stream->duration, stream->timescale, qtdemux->duration,
       
  4016           qtdemux->timescale);
       
  4017       g_free (stream);
       
  4018       return TRUE;
       
  4019     }
       
  4020   }
       
  4021 
       
  4022   if (!(hdlr = qtdemux_tree_get_child_by_type (mdia, FOURCC_hdlr)))
       
  4023     goto corrupt_file;
       
  4024 
       
  4025   GST_LOG_OBJECT (qtdemux, "track type: %" GST_FOURCC_FORMAT,
       
  4026       GST_FOURCC_ARGS (QT_FOURCC ((guint8 *) hdlr->data + 12)));
       
  4027 
       
  4028   stream->subtype = QT_FOURCC ((guint8 *) hdlr->data + 16);
       
  4029   GST_LOG_OBJECT (qtdemux, "track subtype: %" GST_FOURCC_FORMAT,
       
  4030       GST_FOURCC_ARGS (stream->subtype));
       
  4031 
       
  4032   if (!(minf = qtdemux_tree_get_child_by_type (mdia, FOURCC_minf)))
       
  4033     goto corrupt_file;
       
  4034 
       
  4035   if (!(stbl = qtdemux_tree_get_child_by_type (minf, FOURCC_stbl)))
       
  4036     goto corrupt_file;
       
  4037 
       
  4038   /* parse stsd */
       
  4039   if (!(stsd = qtdemux_tree_get_child_by_type (stbl, FOURCC_stsd)))
       
  4040     goto corrupt_file;
       
  4041   stsd_data = (const guint8 *) stsd->data;
       
  4042 
       
  4043   if (stream->subtype == FOURCC_vide) {
       
  4044     guint32 fourcc;
       
  4045     const guint8 *tkhd_data = (const guint8 *) tkhd->data;
       
  4046 
       
  4047     stream->sampled = TRUE;
       
  4048 
       
  4049     /* version 1 uses some 64-bit ints */
       
  4050     offset = (QT_UINT8 (tkhd_data + 8) == 1) ? 96 : 84;
       
  4051     stream->display_width = (guint) QT_FP32 (tkhd_data + offset);
       
  4052     stream->display_height = (guint) QT_FP32 (tkhd_data + offset + 4);
       
  4053 
       
  4054     offset = 16;
       
  4055     stream->fourcc = fourcc = QT_FOURCC (stsd_data + offset + 4);
       
  4056     GST_LOG_OBJECT (qtdemux, "st type:          %" GST_FOURCC_FORMAT,
       
  4057         GST_FOURCC_ARGS (fourcc));
       
  4058 
       
  4059     stream->width = QT_UINT16 (stsd_data + offset + 32);
       
  4060     stream->height = QT_UINT16 (stsd_data + offset + 34);
       
  4061     stream->fps_n = 0;          /* this is filled in later */
       
  4062     stream->fps_d = 0;          /* this is filled in later */
       
  4063     stream->bits_per_sample = QT_UINT16 (stsd_data + offset + 82);
       
  4064     stream->color_table_id = QT_UINT16 (stsd_data + offset + 84);
       
  4065 
       
  4066     GST_LOG_OBJECT (qtdemux, "frame count:   %u",
       
  4067         QT_UINT16 (stsd_data + offset + 48));
       
  4068 
       
  4069     if (fourcc == FOURCC_drms)
       
  4070       goto error_encrypted;
       
  4071 
       
  4072     stream->caps =
       
  4073         qtdemux_video_caps (qtdemux, stream, fourcc, stsd_data, &codec);
       
  4074     if (codec) {
       
  4075       list = gst_tag_list_new ();
       
  4076       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  4077           GST_TAG_VIDEO_CODEC, codec, NULL);
       
  4078       g_free (codec);
       
  4079       codec = NULL;
       
  4080     }
       
  4081 
       
  4082     esds = NULL;
       
  4083     pasp = NULL;
       
  4084     mp4v = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4v);
       
  4085     if (mp4v) {
       
  4086       esds = qtdemux_tree_get_child_by_type (mp4v, FOURCC_esds);
       
  4087       pasp = qtdemux_tree_get_child_by_type (mp4v, FOURCC_pasp);
       
  4088     }
       
  4089 
       
  4090     if (pasp) {
       
  4091       const guint8 *pasp_data = (const guint8 *) pasp->data;
       
  4092 
       
  4093       stream->par_w = QT_UINT32 (pasp_data + 8);
       
  4094       stream->par_h = QT_UINT32 (pasp_data + 12);
       
  4095     } else {
       
  4096       stream->par_w = 0;
       
  4097       stream->par_h = 0;
       
  4098     }
       
  4099 
       
  4100     if (esds) {
       
  4101       gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
       
  4102     } else {
       
  4103       switch (fourcc) {
       
  4104         case FOURCC_avc1:
       
  4105         {
       
  4106           gint len = QT_UINT32 (stsd_data) - 0x66;
       
  4107           const guint8 *avc_data = stsd_data + 0x66;
       
  4108 
       
  4109           /* find avcC */
       
  4110           while (len >= 0x8 &&
       
  4111               QT_FOURCC (avc_data + 0x4) != FOURCC_avcC &&
       
  4112               QT_UINT32 (avc_data) < len) {
       
  4113             len -= QT_UINT32 (avc_data);
       
  4114             avc_data += QT_UINT32 (avc_data);
       
  4115           }
       
  4116 
       
  4117           /* parse, if found */
       
  4118           if (len > 0x8 && QT_FOURCC (avc_data + 0x4) == FOURCC_avcC) {
       
  4119             GstBuffer *buf;
       
  4120             gint size;
       
  4121 
       
  4122             if (QT_UINT32 (avc_data) < len)
       
  4123               size = QT_UINT32 (avc_data) - 0x8;
       
  4124             else
       
  4125               size = len - 0x8;
       
  4126 
       
  4127             GST_DEBUG_OBJECT (qtdemux, "found avcC codec_data in stsd");
       
  4128 
       
  4129             buf = gst_buffer_new_and_alloc (size);
       
  4130             memcpy (GST_BUFFER_DATA (buf), avc_data + 0x8, size);
       
  4131             gst_caps_set_simple (stream->caps,
       
  4132                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
       
  4133             gst_buffer_unref (buf);
       
  4134           }
       
  4135           break;
       
  4136         }
       
  4137         case FOURCC_mjp2:
       
  4138         {
       
  4139           GNode *jp2h, *colr, *mjp2, *field, *prefix;
       
  4140           const guint8 *data;
       
  4141           guint32 fourcc = 0;
       
  4142 
       
  4143           GST_DEBUG_OBJECT (qtdemux, "found mjp2");
       
  4144           /* some required atoms */
       
  4145           mjp2 = qtdemux_tree_get_child_by_type (stsd, FOURCC_mjp2);
       
  4146           if (!mjp2)
       
  4147             break;
       
  4148           jp2h = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2h);
       
  4149           if (!jp2h)
       
  4150             break;
       
  4151           colr = qtdemux_tree_get_child_by_type (jp2h, FOURCC_colr);
       
  4152           if (!colr)
       
  4153             break;
       
  4154           GST_DEBUG_OBJECT (qtdemux, "found colr");
       
  4155           /* try to extract colour space info */
       
  4156           if (QT_UINT8 ((guint8 *) colr->data + 8) == 1) {
       
  4157             switch (QT_UINT32 ((guint8 *) colr->data + 11)) {
       
  4158               case 16:
       
  4159                 fourcc = GST_MAKE_FOURCC ('s', 'R', 'G', 'B');
       
  4160                 break;
       
  4161               case 17:
       
  4162                 fourcc = GST_MAKE_FOURCC ('G', 'R', 'A', 'Y');
       
  4163                 break;
       
  4164               case 18:
       
  4165                 fourcc = GST_MAKE_FOURCC ('s', 'Y', 'U', 'V');
       
  4166                 break;
       
  4167               default:
       
  4168                 break;
       
  4169             }
       
  4170           }
       
  4171 
       
  4172           if (fourcc)
       
  4173             gst_caps_set_simple (stream->caps,
       
  4174                 "fourcc", GST_TYPE_FOURCC, fourcc, NULL);
       
  4175 
       
  4176           /* some optional atoms */
       
  4177           field = qtdemux_tree_get_child_by_type (mjp2, FOURCC_fiel);
       
  4178           prefix = qtdemux_tree_get_child_by_type (mjp2, FOURCC_jp2x);
       
  4179 
       
  4180           /* indicate possible fields in caps */
       
  4181           if (field) {
       
  4182             data = (guint8 *) field->data + 8;
       
  4183             if (*data != 1)
       
  4184               gst_caps_set_simple (stream->caps, "fields", G_TYPE_INT,
       
  4185                   (gint) * data, NULL);
       
  4186           }
       
  4187           /* add codec_data if provided */
       
  4188           if (prefix) {
       
  4189             GstBuffer *buf;
       
  4190             gint len;
       
  4191 
       
  4192             GST_DEBUG_OBJECT (qtdemux, "found prefix data in stsd");
       
  4193             data = prefix->data;
       
  4194             len = QT_UINT32 (data);
       
  4195             if (len > 0x8) {
       
  4196               len -= 0x8;
       
  4197               buf = gst_buffer_new_and_alloc (len);
       
  4198               memcpy (GST_BUFFER_DATA (buf), data + 8, len);
       
  4199               gst_caps_set_simple (stream->caps,
       
  4200                   "codec_data", GST_TYPE_BUFFER, buf, NULL);
       
  4201               gst_buffer_unref (buf);
       
  4202             }
       
  4203           }
       
  4204           break;
       
  4205         }
       
  4206         case FOURCC_SVQ3:
       
  4207         case FOURCC_VP31:
       
  4208         {
       
  4209           GstBuffer *buf;
       
  4210           gint len = QT_UINT32 (stsd_data);
       
  4211 
       
  4212           GST_DEBUG_OBJECT (qtdemux, "found codec_data in stsd");
       
  4213 
       
  4214           buf = gst_buffer_new_and_alloc (len);
       
  4215           memcpy (GST_BUFFER_DATA (buf), stsd_data, len);
       
  4216           gst_caps_set_simple (stream->caps,
       
  4217               "codec_data", GST_TYPE_BUFFER, buf, NULL);
       
  4218           gst_buffer_unref (buf);
       
  4219           break;
       
  4220         }
       
  4221         case FOURCC_rle_:
       
  4222         {
       
  4223           gst_caps_set_simple (stream->caps,
       
  4224               "depth", G_TYPE_INT, QT_UINT16 (stsd_data + offset + 82), NULL);
       
  4225           break;
       
  4226         }
       
  4227         case FOURCC_XiTh:
       
  4228         {
       
  4229           GNode *xith, *xdxt;
       
  4230 
       
  4231           GST_DEBUG_OBJECT (qtdemux, "found XiTh");
       
  4232           xith = qtdemux_tree_get_child_by_type (stsd, FOURCC_XiTh);
       
  4233           if (!xith)
       
  4234             break;
       
  4235 
       
  4236           xdxt = qtdemux_tree_get_child_by_type (xith, FOURCC_XdxT);
       
  4237           if (!xdxt)
       
  4238             break;
       
  4239 
       
  4240           GST_DEBUG_OBJECT (qtdemux, "found XdxT node");
       
  4241           /* collect the headers and store them in a stream list so that we can
       
  4242            * send them out first */
       
  4243           qtdemux_parse_theora_extension (qtdemux, stream, xdxt);
       
  4244           break;
       
  4245         }
       
  4246         default:
       
  4247           break;
       
  4248       }
       
  4249     }
       
  4250 
       
  4251     GST_INFO_OBJECT (qtdemux,
       
  4252         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
       
  4253         GST_FOURCC_ARGS (fourcc), stream->caps);
       
  4254 
       
  4255   } else if (stream->subtype == FOURCC_soun) {
       
  4256     int version, samplesize;
       
  4257     guint32 fourcc;
       
  4258     int len;
       
  4259     guint16 compression_id;
       
  4260 
       
  4261     len = QT_UINT32 (stsd_data + 16);
       
  4262     GST_LOG_OBJECT (qtdemux, "stsd len:           %d", len);
       
  4263 
       
  4264     stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
       
  4265     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
       
  4266         GST_FOURCC_ARGS (stream->fourcc));
       
  4267 
       
  4268     offset = 32;
       
  4269 
       
  4270     version = QT_UINT32 (stsd_data + offset);
       
  4271     stream->n_channels = QT_UINT16 (stsd_data + offset + 8);
       
  4272     samplesize = QT_UINT16 (stsd_data + offset + 10);
       
  4273     compression_id = QT_UINT16 (stsd_data + offset + 12);
       
  4274     stream->rate = QT_FP32 (stsd_data + offset + 16);
       
  4275 
       
  4276     GST_LOG_OBJECT (qtdemux, "version/rev:      %08x", version);
       
  4277     GST_LOG_OBJECT (qtdemux, "vendor:           %08x",
       
  4278         QT_UINT32 (stsd_data + offset + 4));
       
  4279     GST_LOG_OBJECT (qtdemux, "n_channels:       %d", stream->n_channels);
       
  4280     GST_LOG_OBJECT (qtdemux, "sample_size:      %d", samplesize);
       
  4281     GST_LOG_OBJECT (qtdemux, "compression_id:   %d", compression_id);
       
  4282     GST_LOG_OBJECT (qtdemux, "packet size:      %d",
       
  4283         QT_UINT16 (stsd_data + offset + 14));
       
  4284     GST_LOG_OBJECT (qtdemux, "sample rate:      %g", stream->rate);
       
  4285 
       
  4286     if (compression_id == 0xfffe)
       
  4287       stream->sampled = TRUE;
       
  4288 
       
  4289     /* first assume uncompressed audio */
       
  4290     stream->bytes_per_sample = samplesize / 8;
       
  4291     stream->samples_per_frame = stream->n_channels;
       
  4292     stream->bytes_per_frame = stream->n_channels * stream->bytes_per_sample;
       
  4293     stream->samples_per_packet = stream->samples_per_frame;
       
  4294     stream->bytes_per_packet = stream->bytes_per_sample;
       
  4295 
       
  4296     offset = 52;
       
  4297     switch (fourcc) {
       
  4298         /* Yes, these have to be hard-coded */
       
  4299       case FOURCC_MAC6:
       
  4300       {
       
  4301         stream->samples_per_packet = 6;
       
  4302         stream->bytes_per_packet = 1;
       
  4303         stream->bytes_per_frame = 1 * stream->n_channels;
       
  4304         stream->bytes_per_sample = 1;
       
  4305         stream->samples_per_frame = 6 * stream->n_channels;
       
  4306         break;
       
  4307       }
       
  4308       case FOURCC_MAC3:
       
  4309       {
       
  4310         stream->samples_per_packet = 3;
       
  4311         stream->bytes_per_packet = 1;
       
  4312         stream->bytes_per_frame = 1 * stream->n_channels;
       
  4313         stream->bytes_per_sample = 1;
       
  4314         stream->samples_per_frame = 3 * stream->n_channels;
       
  4315         break;
       
  4316       }
       
  4317       case FOURCC_ima4:
       
  4318       {
       
  4319         stream->samples_per_packet = 64;
       
  4320         stream->bytes_per_packet = 34;
       
  4321         stream->bytes_per_frame = 34 * stream->n_channels;
       
  4322         stream->bytes_per_sample = 2;
       
  4323         stream->samples_per_frame = 64 * stream->n_channels;
       
  4324         break;
       
  4325       }
       
  4326       case FOURCC_ulaw:
       
  4327       case FOURCC_alaw:
       
  4328       {
       
  4329         stream->samples_per_packet = 1;
       
  4330         stream->bytes_per_packet = 1;
       
  4331         stream->bytes_per_frame = 1 * stream->n_channels;
       
  4332         stream->bytes_per_sample = 1;
       
  4333         stream->samples_per_frame = 1 * stream->n_channels;
       
  4334         break;
       
  4335       }
       
  4336       case FOURCC_agsm:
       
  4337       {
       
  4338         stream->samples_per_packet = 160;
       
  4339         stream->bytes_per_packet = 33;
       
  4340         stream->bytes_per_frame = 33 * stream->n_channels;
       
  4341         stream->bytes_per_sample = 2;
       
  4342         stream->samples_per_frame = 160 * stream->n_channels;
       
  4343         break;
       
  4344       }
       
  4345       default:
       
  4346         break;
       
  4347     }
       
  4348 
       
  4349     if (version == 0x00010000) {
       
  4350       switch (fourcc) {
       
  4351         case FOURCC_twos:
       
  4352         case FOURCC_sowt:
       
  4353         case FOURCC_raw_:
       
  4354           break;
       
  4355         default:
       
  4356         {
       
  4357           /* only parse extra decoding config for non-pcm audio */
       
  4358           stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
       
  4359           stream->bytes_per_packet = QT_UINT32 (stsd_data + offset + 4);
       
  4360           stream->bytes_per_frame = QT_UINT32 (stsd_data + offset + 8);
       
  4361           stream->bytes_per_sample = QT_UINT32 (stsd_data + offset + 12);
       
  4362 
       
  4363           GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
       
  4364               stream->samples_per_packet);
       
  4365           GST_LOG_OBJECT (qtdemux, "bytes/packet:     %d",
       
  4366               stream->bytes_per_packet);
       
  4367           GST_LOG_OBJECT (qtdemux, "bytes/frame:      %d",
       
  4368               stream->bytes_per_frame);
       
  4369           GST_LOG_OBJECT (qtdemux, "bytes/sample:     %d",
       
  4370               stream->bytes_per_sample);
       
  4371 
       
  4372           if (!stream->sampled && stream->bytes_per_packet) {
       
  4373             stream->samples_per_frame = (stream->bytes_per_frame /
       
  4374                 stream->bytes_per_packet) * stream->samples_per_packet;
       
  4375             GST_LOG_OBJECT (qtdemux, "samples/frame:    %d",
       
  4376                 stream->samples_per_frame);
       
  4377           }
       
  4378           break;
       
  4379         }
       
  4380       }
       
  4381     } else if (version == 0x00020000) {
       
  4382       union
       
  4383       {
       
  4384         gdouble fp;
       
  4385         guint64 val;
       
  4386       } qtfp;
       
  4387 
       
  4388       stream->samples_per_packet = QT_UINT32 (stsd_data + offset);
       
  4389       qtfp.val = QT_UINT64 (stsd_data + offset + 4);
       
  4390       stream->rate = qtfp.fp;
       
  4391       stream->n_channels = QT_UINT32 (stsd_data + offset + 12);
       
  4392 
       
  4393       GST_LOG_OBJECT (qtdemux, "samples/packet:   %d",
       
  4394           stream->samples_per_packet);
       
  4395       GST_LOG_OBJECT (qtdemux, "sample rate:      %g", stream->rate);
       
  4396       GST_LOG_OBJECT (qtdemux, "n_channels:       %d", stream->n_channels);
       
  4397 
       
  4398     } else {
       
  4399       GST_WARNING_OBJECT (qtdemux, "unknown version %08x", version);
       
  4400     }
       
  4401 
       
  4402     if (fourcc == FOURCC_drms)
       
  4403       goto error_encrypted;
       
  4404 
       
  4405     stream->caps = qtdemux_audio_caps (qtdemux, stream, fourcc, NULL, 0,
       
  4406         &codec);
       
  4407 
       
  4408     switch (fourcc) {
       
  4409       case FOURCC_in24:
       
  4410       {
       
  4411         GNode *enda;
       
  4412         GNode *in24;
       
  4413 
       
  4414         in24 = qtdemux_tree_get_child_by_type (stsd, FOURCC_in24);
       
  4415 
       
  4416         enda = qtdemux_tree_get_child_by_type (in24, FOURCC_enda);
       
  4417         if (!enda) {
       
  4418           wave = qtdemux_tree_get_child_by_type (in24, FOURCC_wave);
       
  4419           if (wave)
       
  4420             enda = qtdemux_tree_get_child_by_type (wave, FOURCC_enda);
       
  4421         }
       
  4422         if (enda) {
       
  4423           gst_caps_set_simple (stream->caps,
       
  4424               "endianness", G_TYPE_INT, G_LITTLE_ENDIAN, NULL);
       
  4425         }
       
  4426         break;
       
  4427       }
       
  4428       default:
       
  4429         break;
       
  4430     }
       
  4431 
       
  4432     if (codec) {
       
  4433       list = gst_tag_list_new ();
       
  4434       gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  4435           GST_TAG_AUDIO_CODEC, codec, NULL);
       
  4436       g_free (codec);
       
  4437       codec = NULL;
       
  4438     }
       
  4439 
       
  4440     mp4a = qtdemux_tree_get_child_by_type (stsd, FOURCC_mp4a);
       
  4441     wave = NULL;
       
  4442     esds = NULL;
       
  4443     if (mp4a) {
       
  4444       wave = qtdemux_tree_get_child_by_type (mp4a, FOURCC_wave);
       
  4445       if (wave)
       
  4446         esds = qtdemux_tree_get_child_by_type (wave, FOURCC_esds);
       
  4447       if (!esds)
       
  4448         esds = qtdemux_tree_get_child_by_type (mp4a, FOURCC_esds);
       
  4449     }
       
  4450 
       
  4451     if (esds) {
       
  4452       gst_qtdemux_handle_esds (qtdemux, stream, esds, list);
       
  4453     } else {
       
  4454       switch (fourcc) {
       
  4455 #if 0
       
  4456           /* FIXME: what is in the chunk? */
       
  4457         case FOURCC_QDMC:
       
  4458         {
       
  4459           gint len = QT_UINT32 (stsd_data);
       
  4460 
       
  4461           /* seems to be always = 116 = 0x74 */
       
  4462           break;
       
  4463         }
       
  4464 #endif
       
  4465         case FOURCC_QDM2:
       
  4466         {
       
  4467           gint len = QT_UINT32 (stsd_data);
       
  4468 
       
  4469           if (len > 0x4C) {
       
  4470             GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x4C);
       
  4471 
       
  4472             memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x4C, len - 0x4C);
       
  4473             gst_caps_set_simple (stream->caps,
       
  4474                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
       
  4475             gst_buffer_unref (buf);
       
  4476           }
       
  4477           gst_caps_set_simple (stream->caps,
       
  4478               "samplesize", G_TYPE_INT, samplesize, NULL);
       
  4479           break;
       
  4480         }
       
  4481         case FOURCC_alac:
       
  4482         {
       
  4483           gint len = QT_UINT32 (stsd_data);
       
  4484 
       
  4485           if (len > 0x34) {
       
  4486             GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
       
  4487 
       
  4488             memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
       
  4489             gst_caps_set_simple (stream->caps,
       
  4490                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
       
  4491             gst_buffer_unref (buf);
       
  4492           }
       
  4493           gst_caps_set_simple (stream->caps,
       
  4494               "samplesize", G_TYPE_INT, samplesize, NULL);
       
  4495           break;
       
  4496         }
       
  4497         case FOURCC_samr:
       
  4498         {
       
  4499           gint len = QT_UINT32 (stsd_data);
       
  4500 
       
  4501           if (len > 0x34) {
       
  4502             GstBuffer *buf = gst_buffer_new_and_alloc (len - 0x34);
       
  4503 
       
  4504             memcpy (GST_BUFFER_DATA (buf), stsd_data + 0x34, len - 0x34);
       
  4505 
       
  4506             gst_caps_set_simple (stream->caps,
       
  4507                 "codec_data", GST_TYPE_BUFFER, buf, NULL);
       
  4508             gst_buffer_unref (buf);
       
  4509           }
       
  4510           break;
       
  4511         }
       
  4512         default:
       
  4513           break;
       
  4514       }
       
  4515     }
       
  4516     GST_INFO_OBJECT (qtdemux,
       
  4517         "type %" GST_FOURCC_FORMAT " caps %" GST_PTR_FORMAT,
       
  4518         GST_FOURCC_ARGS (fourcc), stream->caps);
       
  4519 
       
  4520   } else if (stream->subtype == FOURCC_strm) {
       
  4521     guint32 fourcc;
       
  4522 
       
  4523     stream->fourcc = fourcc = QT_FOURCC (stsd_data + 16 + 4);
       
  4524     GST_LOG_OBJECT (qtdemux, "stsd type:          %" GST_FOURCC_FORMAT,
       
  4525         GST_FOURCC_ARGS (fourcc));
       
  4526 
       
  4527     if (fourcc != FOURCC_rtsp) {
       
  4528       GST_INFO_OBJECT (qtdemux, "unhandled stream type %" GST_FOURCC_FORMAT,
       
  4529           GST_FOURCC_ARGS (fourcc));
       
  4530       goto unknown_stream;
       
  4531     }
       
  4532     stream->sampled = TRUE;
       
  4533   } else if (stream->subtype == FOURCC_subp) {
       
  4534     guint32 fourcc;
       
  4535 
       
  4536     stream->sampled = TRUE;
       
  4537 
       
  4538     offset = 16;
       
  4539     stream->fourcc = fourcc = QT_FOURCC (stsd_data + offset + 4);
       
  4540     GST_LOG_OBJECT (qtdemux, "st type:          %" GST_FOURCC_FORMAT,
       
  4541         GST_FOURCC_ARGS (fourcc));
       
  4542 
       
  4543     stream->caps =
       
  4544         qtdemux_subp_caps (qtdemux, stream, fourcc, stsd_data, &codec);
       
  4545   } else {
       
  4546     goto unknown_stream;
       
  4547   }
       
  4548 
       
  4549   /* promote to sampled format */
       
  4550   if (stream->fourcc == FOURCC_samr) {
       
  4551     /* force mono 8000 Hz for AMR */
       
  4552     stream->sampled = TRUE;
       
  4553     stream->n_channels = 1;
       
  4554     stream->rate = 8000;
       
  4555   } else if (stream->fourcc == FOURCC_sawb) {
       
  4556     /* force mono 16000 Hz for AMR-WB */
       
  4557     stream->sampled = TRUE;
       
  4558     stream->n_channels = 1;
       
  4559     stream->rate = 16000;
       
  4560   } else if (stream->fourcc == FOURCC_mp4a) {
       
  4561     stream->sampled = TRUE;
       
  4562   }
       
  4563 
       
  4564   /* collect sample information */
       
  4565   if (!qtdemux_parse_samples (qtdemux, stream, stbl))
       
  4566     goto samples_failed;
       
  4567 
       
  4568   /* configure segments */
       
  4569   if (!qtdemux_parse_segments (qtdemux, stream, trak))
       
  4570     goto segments_failed;
       
  4571 
       
  4572   /* now we are ready to add the stream */
       
  4573   gst_qtdemux_add_stream (qtdemux, stream, list);
       
  4574 
       
  4575   return TRUE;
       
  4576 
       
  4577 /* ERRORS */
       
  4578 corrupt_file:
       
  4579   {
       
  4580     GST_ELEMENT_ERROR (qtdemux, STREAM, DECODE,
       
  4581         (_("This file is corrupt and cannot be played.")), (NULL));
       
  4582     g_free (stream);
       
  4583     return FALSE;
       
  4584   }
       
  4585 error_encrypted:
       
  4586   {
       
  4587     GST_ELEMENT_ERROR (qtdemux, STREAM, DECRYPT, (NULL), (NULL));
       
  4588     g_free (stream);
       
  4589     return FALSE;
       
  4590   }
       
  4591 samples_failed:
       
  4592   {
       
  4593     /* we posted an error already */
       
  4594     g_free (stream);
       
  4595     return FALSE;
       
  4596   }
       
  4597 segments_failed:
       
  4598   {
       
  4599     /* we posted an error already */
       
  4600     g_free (stream);
       
  4601     return FALSE;
       
  4602   }
       
  4603 unknown_stream:
       
  4604   {
       
  4605     GST_INFO_OBJECT (qtdemux, "unknown subtype %" GST_FOURCC_FORMAT,
       
  4606         GST_FOURCC_ARGS (stream->subtype));
       
  4607     g_free (stream);
       
  4608     return TRUE;
       
  4609   }
       
  4610 }
       
  4611 
       
  4612 static inline gboolean
       
  4613 qtdemux_is_string_3gp (GstQTDemux * qtdemux, guint32 fourcc)
       
  4614 {
       
  4615   /* Detect if the tag must be handled as 3gpp - i18n metadata. The first
       
  4616    * check is for catching all the possible brands, e.g. 3gp4,3gp5,3gg6,.. and
       
  4617    * handling properly the tags present in more than one brand.*/
       
  4618   return ((qtdemux->major_brand & GST_MAKE_FOURCC (255, 255, 0, 0)) ==
       
  4619       GST_MAKE_FOURCC ('3', 'g', 0, 0)
       
  4620       && (fourcc == FOURCC_cprt || fourcc == FOURCC_gnre
       
  4621           || fourcc == FOURCC_kywd)) || fourcc == FOURCC_titl
       
  4622       || fourcc == FOURCC_dscp || fourcc == FOURCC_perf || fourcc == FOURCC_auth
       
  4623       || fourcc == FOURCC_albm;
       
  4624 }
       
  4625 
       
  4626 static void
       
  4627 qtdemux_tag_add_location (GstQTDemux * qtdemux, const char *tag,
       
  4628     const char *dummy, GNode * node)
       
  4629 {
       
  4630   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
       
  4631   int offset;
       
  4632   char *name;
       
  4633   gchar *data;
       
  4634   gdouble longitude, latitude, altitude;
       
  4635 
       
  4636   data = node->data;
       
  4637   offset = 14;
       
  4638 
       
  4639   /* TODO: language code skipped */
       
  4640 
       
  4641   name = gst_tag_freeform_string_to_utf8 (data + offset, -1, env_vars);
       
  4642 
       
  4643   if (!name) {
       
  4644     /* do not alarm in trivial case, but bail out otherwise */
       
  4645     if (*(data + offset) != 0) {
       
  4646       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8, "
       
  4647           "giving up", tag);
       
  4648     }
       
  4649   } else {
       
  4650     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
       
  4651         GST_TAG_GEO_LOCATION_NAME, name, NULL);
       
  4652     offset += strlen (name);
       
  4653     g_free (name);
       
  4654   }
       
  4655 
       
  4656   /* +1 +1 = skip null-terminator and location role byte */
       
  4657   offset += 1 + 1;
       
  4658   longitude = QT_FP32 (data + offset);
       
  4659 
       
  4660   offset += 4;
       
  4661   latitude = QT_FP32 (data + offset);
       
  4662 
       
  4663   offset += 4;
       
  4664   altitude = QT_FP32 (data + offset);
       
  4665 
       
  4666   /* one invalid means all are invalid */
       
  4667   if (longitude >= -180.0 && longitude <= 180.0 &&
       
  4668       latitude >= -90.0 && latitude <= 90.0) {
       
  4669     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
       
  4670         GST_TAG_GEO_LOCATION_LATITUDE, latitude,
       
  4671         GST_TAG_GEO_LOCATION_LONGITUDE, longitude,
       
  4672         GST_TAG_GEO_LOCATION_ELEVATION, altitude, NULL);
       
  4673   }
       
  4674 
       
  4675   /* TODO: no GST_TAG_, so astronomical body and additional notes skipped */
       
  4676 }
       
  4677 
       
  4678 
       
  4679 static void
       
  4680 qtdemux_tag_add_year (GstQTDemux * qtdemux, const char *tag, const char *dummy,
       
  4681     GNode * node)
       
  4682 {
       
  4683   guint16 y;
       
  4684   GDate *date;
       
  4685 
       
  4686   y = QT_UINT16 ((guint8 *) node->data + 12);
       
  4687   GST_DEBUG_OBJECT (qtdemux, "year: %u", y);
       
  4688 
       
  4689   date = g_date_new_dmy (1, 1, y);
       
  4690   gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, date, NULL);
       
  4691   g_date_free (date);
       
  4692 }
       
  4693 
       
  4694 static void
       
  4695 qtdemux_tag_add_classification (GstQTDemux * qtdemux, const char *tag,
       
  4696     const char *dummy, GNode * node)
       
  4697 {
       
  4698   int offset;
       
  4699   char *tag_str = NULL;
       
  4700   guint8 *entity;
       
  4701   guint16 table;
       
  4702 
       
  4703 
       
  4704   offset = 12;
       
  4705   entity = (guint8 *) node->data + offset;
       
  4706 
       
  4707   offset += 4;
       
  4708   table = QT_UINT16 ((guint8 *) node->data + offset);
       
  4709 
       
  4710   /* Language code skipped */
       
  4711 
       
  4712   offset += 4;
       
  4713 
       
  4714   /* Tag format: "XXXX://Y[YYYY]/classification info string"
       
  4715    * XXXX: classification entity, fixed length 4 chars.
       
  4716    * Y[YYYY]: classification table, max 5 chars.
       
  4717    */
       
  4718   tag_str = g_strdup_printf ("----://%u/%s",
       
  4719       table, (char *) node->data + offset);
       
  4720 
       
  4721   /* memcpy To be sure we're preserving byte order */
       
  4722   memcpy (tag_str, entity, 4);
       
  4723   GST_DEBUG_OBJECT (qtdemux, "classification info: %s", tag_str);
       
  4724 
       
  4725   gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_APPEND, tag,
       
  4726       tag_str, NULL);
       
  4727 
       
  4728   g_free (tag_str);
       
  4729 }
       
  4730 
       
  4731 static void
       
  4732 qtdemux_tag_add_str (GstQTDemux * qtdemux, const char *tag, const char *dummy,
       
  4733     GNode * node)
       
  4734 {
       
  4735   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
       
  4736   GNode *data;
       
  4737   char *s;
       
  4738   int len;
       
  4739   guint32 type;
       
  4740   int offset;
       
  4741 
       
  4742   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
       
  4743   if (data) {
       
  4744     len = QT_UINT32 (data->data);
       
  4745     type = QT_UINT32 ((guint8 *) data->data + 8);
       
  4746     if (type == 0x00000001) {
       
  4747       s = gst_tag_freeform_string_to_utf8 ((char *) data->data + 16, len - 16,
       
  4748           env_vars);
       
  4749       if (s) {
       
  4750         GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
       
  4751         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s,
       
  4752             NULL);
       
  4753         g_free (s);
       
  4754       } else {
       
  4755         GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
       
  4756       }
       
  4757     }
       
  4758   } else {
       
  4759     len = QT_UINT32 (node->data);
       
  4760     type = QT_UINT32 ((guint8 *) node->data + 4);
       
  4761     if ((type >> 24) == 0xa9) {
       
  4762       /* Type starts with the (C) symbol, so the next 32 bits are
       
  4763        * the language code, which we ignore */
       
  4764       offset = 12;
       
  4765       GST_DEBUG_OBJECT (qtdemux, "found international text tag");
       
  4766     } else if (qtdemux_is_string_3gp (qtdemux,
       
  4767             QT_FOURCC ((guint8 *) node->data + 4))) {
       
  4768       offset = 14;
       
  4769       /* 16-bit Language code is ignored here as well */
       
  4770       GST_DEBUG_OBJECT (qtdemux, "found 3gpp text tag");
       
  4771     } else {
       
  4772       offset = 8;
       
  4773       GST_DEBUG_OBJECT (qtdemux, "found normal text tag");
       
  4774     }
       
  4775     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
       
  4776         len - offset, env_vars);
       
  4777     if (s) {
       
  4778       GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (s));
       
  4779       gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, s, NULL);
       
  4780       g_free (s);
       
  4781     } else {
       
  4782       GST_DEBUG_OBJECT (qtdemux, "failed to convert %s tag to UTF-8", tag);
       
  4783     }
       
  4784   }
       
  4785 }
       
  4786 
       
  4787 static void
       
  4788 qtdemux_tag_add_keywords (GstQTDemux * qtdemux, const char *tag,
       
  4789     const char *dummy, GNode * node)
       
  4790 {
       
  4791   const gchar *env_vars[] = { "GST_QT_TAG_ENCODING", "GST_TAG_ENCODING", NULL };
       
  4792   guint8 *data;
       
  4793   char *s, *t, *k = NULL;
       
  4794   int len;
       
  4795   int offset;
       
  4796   int count;
       
  4797 
       
  4798   /* re-route to normal string tag if not 3GP */
       
  4799   if (!qtdemux_is_string_3gp (qtdemux, FOURCC_kywd))
       
  4800     return qtdemux_tag_add_str (qtdemux, tag, dummy, node);
       
  4801 
       
  4802   GST_DEBUG_OBJECT (qtdemux, "found 3gpp keyword tag");
       
  4803 
       
  4804   data = node->data;
       
  4805 
       
  4806   len = QT_UINT32 (data);
       
  4807   if (len < 15)
       
  4808     goto short_read;
       
  4809 
       
  4810   count = QT_UINT8 (data + 14);
       
  4811   offset = 15;
       
  4812   for (; count; count--) {
       
  4813     gint slen;
       
  4814 
       
  4815     if (offset + 1 > len)
       
  4816       goto short_read;
       
  4817     slen = QT_UINT8 (data + offset);
       
  4818     offset += 1;
       
  4819     if (offset + slen > len)
       
  4820       goto short_read;
       
  4821     s = gst_tag_freeform_string_to_utf8 ((char *) node->data + offset,
       
  4822         slen, env_vars);
       
  4823     if (s) {
       
  4824       GST_DEBUG_OBJECT (qtdemux, "adding keyword %s", GST_STR_NULL (s));
       
  4825       if (k) {
       
  4826         t = g_strjoin (",", k, s, NULL);
       
  4827         g_free (s);
       
  4828         g_free (k);
       
  4829         k = t;
       
  4830       } else {
       
  4831         k = s;
       
  4832       }
       
  4833     } else {
       
  4834       GST_DEBUG_OBJECT (qtdemux, "failed to convert keyword to UTF-8");
       
  4835     }
       
  4836     offset += slen;
       
  4837   }
       
  4838 
       
  4839 done:
       
  4840   if (k) {
       
  4841     GST_DEBUG_OBJECT (qtdemux, "adding tag %s", GST_STR_NULL (k));
       
  4842     gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag, k, NULL);
       
  4843   }
       
  4844   g_free (k);
       
  4845 
       
  4846   return;
       
  4847 
       
  4848   /* ERRORS */
       
  4849 short_read:
       
  4850   {
       
  4851     GST_DEBUG_OBJECT (qtdemux, "short read parsing 3GP keywords");
       
  4852     goto done;
       
  4853   }
       
  4854 }
       
  4855 
       
  4856 static void
       
  4857 qtdemux_tag_add_num (GstQTDemux * qtdemux, const char *tag1,
       
  4858     const char *tag2, GNode * node)
       
  4859 {
       
  4860   GNode *data;
       
  4861   int len;
       
  4862   int type;
       
  4863   int n1, n2;
       
  4864 
       
  4865   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
       
  4866   if (data) {
       
  4867     len = QT_UINT32 (data->data);
       
  4868     type = QT_UINT32 ((guint8 *) data->data + 8);
       
  4869     if (type == 0x00000000 && len >= 22) {
       
  4870       n1 = QT_UINT16 ((guint8 *) data->data + 18);
       
  4871       n2 = QT_UINT16 ((guint8 *) data->data + 20);
       
  4872       if (n1 > 0) {
       
  4873         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag1, n1);
       
  4874         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
       
  4875             tag1, n1, NULL);
       
  4876       }
       
  4877       if (n2 > 0) {
       
  4878         GST_DEBUG_OBJECT (qtdemux, "adding tag %s=%d", tag2, n2);
       
  4879         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
       
  4880             tag2, n2, NULL);
       
  4881       }
       
  4882     }
       
  4883   }
       
  4884 }
       
  4885 
       
  4886 static void
       
  4887 qtdemux_tag_add_tmpo (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
       
  4888     GNode * node)
       
  4889 {
       
  4890   GNode *data;
       
  4891   int len;
       
  4892   int type;
       
  4893   int n1;
       
  4894 
       
  4895   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
       
  4896   if (data) {
       
  4897     len = QT_UINT32 (data->data);
       
  4898     type = QT_UINT32 ((guint8 *) data->data + 8);
       
  4899     GST_DEBUG_OBJECT (qtdemux, "have tempo tag, type=%d,len=%d", type, len);
       
  4900     /* some files wrongly have a type 0x0f=15, but it should be 0x15 */
       
  4901     if ((type == 0x00000015 || type == 0x0000000f) && len >= 18) {
       
  4902       n1 = QT_UINT16 ((guint8 *) data->data + 16);
       
  4903       if (n1) {
       
  4904         /* do not add bpm=0 */
       
  4905         GST_DEBUG_OBJECT (qtdemux, "adding tag %d", n1);
       
  4906         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
       
  4907             tag1, (gdouble) n1, NULL);
       
  4908       }
       
  4909     }
       
  4910   }
       
  4911 }
       
  4912 
       
  4913 static void
       
  4914 qtdemux_tag_add_covr (GstQTDemux * qtdemux, const char *tag1, const char *dummy,
       
  4915     GNode * node)
       
  4916 {
       
  4917   GNode *data;
       
  4918   int len;
       
  4919   int type;
       
  4920   GstBuffer *buf;
       
  4921 
       
  4922   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
       
  4923   if (data) {
       
  4924     len = QT_UINT32 (data->data);
       
  4925     type = QT_UINT32 ((guint8 *) data->data + 8);
       
  4926     GST_DEBUG_OBJECT (qtdemux, "have covr tag, type=%d,len=%d", type, len);
       
  4927     if ((type == 0x0000000d || type == 0x0000000e) && len > 16) {
       
  4928       if ((buf = gst_tag_image_data_to_image_buffer ((guint8 *) data->data + 16,
       
  4929                   len - 16, GST_TAG_IMAGE_TYPE_NONE))) {
       
  4930         GST_DEBUG_OBJECT (qtdemux, "adding tag size %d", len - 16);
       
  4931         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
       
  4932             tag1, buf, NULL);
       
  4933         gst_buffer_unref (buf);
       
  4934       }
       
  4935     }
       
  4936   }
       
  4937 }
       
  4938 
       
  4939 static void
       
  4940 qtdemux_tag_add_date (GstQTDemux * qtdemux, const char *tag, const char *dummy,
       
  4941     GNode * node)
       
  4942 {
       
  4943   GNode *data;
       
  4944   char *s;
       
  4945   int len;
       
  4946   int type;
       
  4947 
       
  4948   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
       
  4949   if (data) {
       
  4950     len = QT_UINT32 (data->data);
       
  4951     type = QT_UINT32 ((guint8 *) data->data + 8);
       
  4952     if (type == 0x00000001) {
       
  4953       guint y, m = 1, d = 1;
       
  4954       gint ret;
       
  4955 
       
  4956       s = g_strndup ((char *) data->data + 16, len - 16);
       
  4957       GST_DEBUG_OBJECT (qtdemux, "adding date '%s'", s);
       
  4958       ret = sscanf (s, "%u-%u-%u", &y, &m, &d);
       
  4959       if (ret >= 1 && y > 1500 && y < 3000) {
       
  4960         GDate *date;
       
  4961 
       
  4962         date = g_date_new_dmy (d, m, y);
       
  4963         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE, tag,
       
  4964             date, NULL);
       
  4965         g_date_free (date);
       
  4966       } else {
       
  4967         GST_DEBUG_OBJECT (qtdemux, "could not parse date string '%s'", s);
       
  4968       }
       
  4969       g_free (s);
       
  4970     }
       
  4971   }
       
  4972 }
       
  4973 
       
  4974 static void
       
  4975 qtdemux_tag_add_gnre (GstQTDemux * qtdemux, const char *tag, const char *dummy,
       
  4976     GNode * node)
       
  4977 {
       
  4978   static const gchar *genres[] = {
       
  4979     "N/A", "Blues", "Classic Rock", "Country", "Dance", "Disco",
       
  4980     "Funk", "Grunge", "Hip-Hop", "Jazz", "Metal", "New Age", "Oldies",
       
  4981     "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
       
  4982     "Industrial", "Alternative", "Ska", "Death Metal", "Pranks",
       
  4983     "Soundtrack", "Euro-Techno", "Ambient", "Trip-Hop", "Vocal",
       
  4984     "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
       
  4985     "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise",
       
  4986     "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative",
       
  4987     "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic",
       
  4988     "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk",
       
  4989     "Eurodance", "Dream", "Southern Rock", "Comedy", "Cult", "Gangsta",
       
  4990     "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
       
  4991     "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes",
       
  4992     "Trailer", "Lo-Fi", "Tribal", "Acid Punk", "Acid Jazz", "Polka",
       
  4993     "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
       
  4994     "Folk/Rock", "National Folk", "Swing", "Fast-Fusion", "Bebob",
       
  4995     "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde",
       
  4996     "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
       
  4997     "Symphonic Rock", "Slow Rock", "Big Band", "Chorus",
       
  4998     "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson",
       
  4999     "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass",
       
  5000     "Primus", "Porn Groove", "Satire", "Slow Jam", "Club", "Tango",
       
  5001     "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul",
       
  5002     "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella",
       
  5003     "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House",
       
  5004     "Hardcore", "Terror", "Indie", "BritPop", "NegerPunk",
       
  5005     "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal",
       
  5006     "Black Metal", "Crossover", "Contemporary C", "Christian Rock",
       
  5007     "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop"
       
  5008   };
       
  5009   GNode *data;
       
  5010   int len;
       
  5011   int type;
       
  5012   int n;
       
  5013 
       
  5014   /* re-route to normal string tag if 3GP */
       
  5015   if (qtdemux_is_string_3gp (qtdemux, FOURCC_gnre))
       
  5016     return qtdemux_tag_add_str (qtdemux, tag, dummy, node);
       
  5017 
       
  5018   data = qtdemux_tree_get_child_by_type (node, FOURCC_data);
       
  5019   if (data) {
       
  5020     len = QT_UINT32 (data->data);
       
  5021     type = QT_UINT32 ((guint8 *) data->data + 8);
       
  5022     if (type == 0x00000000 && len >= 18) {
       
  5023       n = QT_UINT16 ((guint8 *) data->data + 16);
       
  5024       if (n > 0 && n < sizeof (genres) / sizeof (char *)) {
       
  5025         GST_DEBUG_OBJECT (qtdemux, "adding %d [%s]", n, genres[n]);
       
  5026         gst_tag_list_add (qtdemux->tag_list, GST_TAG_MERGE_REPLACE,
       
  5027             tag, genres[n], NULL);
       
  5028       }
       
  5029     }
       
  5030   }
       
  5031 }
       
  5032 
       
  5033 typedef void (*GstQTDemuxAddTagFunc) (GstQTDemux * demux,
       
  5034     const char *tag, const char *tag_bis, GNode * node);
       
  5035 
       
  5036 static const struct
       
  5037 {
       
  5038   guint32 fourcc;
       
  5039   const gchar *gst_tag;
       
  5040   const gchar *gst_tag_bis;
       
  5041   const GstQTDemuxAddTagFunc func;
       
  5042 } add_funcs[] = {
       
  5043   {
       
  5044   FOURCC__nam, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
       
  5045   FOURCC_titl, GST_TAG_TITLE, NULL, qtdemux_tag_add_str}, {
       
  5046   FOURCC__grp, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
       
  5047   FOURCC__wrt, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
       
  5048   FOURCC__ART, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
       
  5049   FOURCC_perf, GST_TAG_ARTIST, NULL, qtdemux_tag_add_str}, {
       
  5050   FOURCC_auth, GST_TAG_COMPOSER, NULL, qtdemux_tag_add_str}, {
       
  5051   FOURCC__alb, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
       
  5052   FOURCC_albm, GST_TAG_ALBUM, NULL, qtdemux_tag_add_str}, {
       
  5053   FOURCC_cprt, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
       
  5054   FOURCC__cpy, GST_TAG_COPYRIGHT, NULL, qtdemux_tag_add_str}, {
       
  5055   FOURCC__cmt, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
       
  5056   FOURCC__des, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
       
  5057   FOURCC_dscp, GST_TAG_DESCRIPTION, NULL, qtdemux_tag_add_str}, {
       
  5058   FOURCC__day, GST_TAG_DATE, NULL, qtdemux_tag_add_date}, {
       
  5059   FOURCC_yrrc, GST_TAG_DATE, NULL, qtdemux_tag_add_year}, {
       
  5060   FOURCC__too, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
       
  5061   FOURCC__inf, GST_TAG_COMMENT, NULL, qtdemux_tag_add_str}, {
       
  5062   FOURCC_trkn, GST_TAG_TRACK_NUMBER, GST_TAG_TRACK_COUNT, qtdemux_tag_add_num}, {
       
  5063   FOURCC_disk, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
       
  5064         qtdemux_tag_add_num}, {
       
  5065   FOURCC_disc, GST_TAG_ALBUM_VOLUME_NUMBER, GST_TAG_ALBUM_VOLUME_COUNT,
       
  5066         qtdemux_tag_add_num}, {
       
  5067   FOURCC__gen, GST_TAG_GENRE, NULL, qtdemux_tag_add_str}, {
       
  5068   FOURCC_gnre, GST_TAG_GENRE, NULL, qtdemux_tag_add_gnre}, {
       
  5069   FOURCC_tmpo, GST_TAG_BEATS_PER_MINUTE, NULL, qtdemux_tag_add_tmpo}, {
       
  5070   FOURCC_covr, GST_TAG_PREVIEW_IMAGE, NULL, qtdemux_tag_add_covr}, {
       
  5071   FOURCC_kywd, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_keywords}, {
       
  5072   FOURCC_keyw, GST_TAG_KEYWORDS, NULL, qtdemux_tag_add_str}, {
       
  5073   FOURCC__enc, GST_TAG_ENCODER, NULL, qtdemux_tag_add_str}, {
       
  5074   FOURCC_loci, GST_TAG_GEO_LOCATION_NAME, NULL, qtdemux_tag_add_location}, {
       
  5075   FOURCC_clsf, GST_QT_DEMUX_CLASSIFICATION_TAG, NULL,
       
  5076         qtdemux_tag_add_classification}
       
  5077 };
       
  5078 
       
  5079 static void
       
  5080 qtdemux_tag_add_blob (GNode * node, GstQTDemux * demux)
       
  5081 {
       
  5082   gint len;
       
  5083   guint8 *data;
       
  5084   GstBuffer *buf;
       
  5085   gchar *media_type, *style;
       
  5086   GstCaps *caps;
       
  5087   guint i;
       
  5088   guint8 ndata[4];
       
  5089 
       
  5090   data = node->data;
       
  5091   len = QT_UINT32 (data);
       
  5092   buf = gst_buffer_new_and_alloc (len);
       
  5093   memcpy (GST_BUFFER_DATA (buf), data, len);
       
  5094 
       
  5095   /* heuristic to determine style of tag */
       
  5096   if (QT_FOURCC (data + 4) == FOURCC_____ ||
       
  5097       (len > 8 + 12 && QT_FOURCC (data + 12) == FOURCC_data))
       
  5098     style = "itunes";
       
  5099   else if (demux->major_brand == FOURCC_qt__)
       
  5100     style = "quicktime";
       
  5101   /* fall back to assuming iso/3gp tag style */
       
  5102   else
       
  5103     style = "iso";
       
  5104 
       
  5105   /* santize the name for the caps. */
       
  5106   for (i = 0; i < 4; i++) {
       
  5107     guint8 d = data[4 + i];
       
  5108     if (g_ascii_isalnum (d))
       
  5109       ndata[i] = g_ascii_tolower (d);
       
  5110     else
       
  5111       ndata[i] = '_';
       
  5112   }
       
  5113 
       
  5114   media_type = g_strdup_printf ("application/x-gst-qt-%c%c%c%c-tag",
       
  5115       ndata[0], ndata[1], ndata[2], ndata[3]);
       
  5116   GST_DEBUG_OBJECT (demux, "media type %s", media_type);
       
  5117 
       
  5118   caps = gst_caps_new_simple (media_type, "style", G_TYPE_STRING, style, NULL);
       
  5119   gst_buffer_set_caps (buf, caps);
       
  5120   gst_caps_unref (caps);
       
  5121   g_free (media_type);
       
  5122 
       
  5123   GST_DEBUG_OBJECT (demux, "adding private tag; size %d, caps %" GST_PTR_FORMAT,
       
  5124       GST_BUFFER_SIZE (buf), caps);
       
  5125 
       
  5126   gst_tag_list_add (demux->tag_list, GST_TAG_MERGE_APPEND,
       
  5127       GST_QT_DEMUX_PRIVATE_TAG, buf, NULL);
       
  5128   gst_buffer_unref (buf);
       
  5129 }
       
  5130 
       
  5131 static void
       
  5132 qtdemux_parse_udta (GstQTDemux * qtdemux, GNode * udta)
       
  5133 {
       
  5134   GNode *meta;
       
  5135   GNode *ilst;
       
  5136   GNode *node;
       
  5137   gint i;
       
  5138 
       
  5139   meta = qtdemux_tree_get_child_by_type (udta, FOURCC_meta);
       
  5140   if (meta != NULL) {
       
  5141     ilst = qtdemux_tree_get_child_by_type (meta, FOURCC_ilst);
       
  5142     if (ilst == NULL) {
       
  5143       GST_LOG_OBJECT (qtdemux, "no ilst");
       
  5144       return;
       
  5145     }
       
  5146   } else {
       
  5147     ilst = udta;
       
  5148     GST_LOG_OBJECT (qtdemux, "no meta so using udta itself");
       
  5149   }
       
  5150 
       
  5151   GST_DEBUG_OBJECT (qtdemux, "new tag list");
       
  5152   qtdemux->tag_list = gst_tag_list_new ();
       
  5153 
       
  5154   for (i = 0; i < G_N_ELEMENTS (add_funcs); ++i) {
       
  5155     node = qtdemux_tree_get_child_by_type (ilst, add_funcs[i].fourcc);
       
  5156     if (node) {
       
  5157       add_funcs[i].func (qtdemux, add_funcs[i].gst_tag,
       
  5158           add_funcs[i].gst_tag_bis, node);
       
  5159       g_node_destroy (node);
       
  5160     }
       
  5161   }
       
  5162 
       
  5163   /* parsed nodes have been removed, pass along remainder as blob */
       
  5164   g_node_children_foreach (ilst, G_TRAVERSE_ALL,
       
  5165       (GNodeForeachFunc) qtdemux_tag_add_blob, qtdemux);
       
  5166 
       
  5167 }
       
  5168 
       
  5169 typedef struct
       
  5170 {
       
  5171   GstStructure *structure;      /* helper for sort function */
       
  5172   gchar *location;
       
  5173   guint min_req_bitrate;
       
  5174   guint min_req_qt_version;
       
  5175 } GstQtReference;
       
  5176 
       
  5177 static gint
       
  5178 qtdemux_redirects_sort_func (gconstpointer a, gconstpointer b)
       
  5179 {
       
  5180   GstQtReference *ref_a = (GstQtReference *) a;
       
  5181   GstQtReference *ref_b = (GstQtReference *) b;
       
  5182 
       
  5183   if (ref_b->min_req_qt_version != ref_a->min_req_qt_version)
       
  5184     return ref_b->min_req_qt_version - ref_a->min_req_qt_version;
       
  5185 
       
  5186   /* known bitrates go before unknown; higher bitrates go first */
       
  5187   return ref_b->min_req_bitrate - ref_a->min_req_bitrate;
       
  5188 }
       
  5189 
       
  5190 /* sort the redirects and post a message for the application.
       
  5191  */
       
  5192 static void
       
  5193 qtdemux_process_redirects (GstQTDemux * qtdemux, GList * references)
       
  5194 {
       
  5195   GstQtReference *best;
       
  5196   GstStructure *s;
       
  5197   GstMessage *msg;
       
  5198   GValue list_val = { 0, };
       
  5199   GList *l;
       
  5200 
       
  5201   g_assert (references != NULL);
       
  5202 
       
  5203   references = g_list_sort (references, qtdemux_redirects_sort_func);
       
  5204 
       
  5205   best = (GstQtReference *) references->data;
       
  5206 
       
  5207   g_value_init (&list_val, GST_TYPE_LIST);
       
  5208 
       
  5209   for (l = references; l != NULL; l = l->next) {
       
  5210     GstQtReference *ref = (GstQtReference *) l->data;
       
  5211     GValue struct_val = { 0, };
       
  5212 
       
  5213     ref->structure = gst_structure_new ("redirect",
       
  5214         "new-location", G_TYPE_STRING, ref->location, NULL);
       
  5215 
       
  5216     if (ref->min_req_bitrate > 0) {
       
  5217       gst_structure_set (ref->structure, "minimum-bitrate", G_TYPE_INT,
       
  5218           ref->min_req_bitrate, NULL);
       
  5219     }
       
  5220 
       
  5221     g_value_init (&struct_val, GST_TYPE_STRUCTURE);
       
  5222     g_value_set_boxed (&struct_val, ref->structure);
       
  5223     gst_value_list_append_value (&list_val, &struct_val);
       
  5224     g_value_unset (&struct_val);
       
  5225     /* don't free anything here yet, since we need best->structure below */
       
  5226   }
       
  5227 
       
  5228   g_assert (best != NULL);
       
  5229   s = gst_structure_copy (best->structure);
       
  5230 
       
  5231   if (g_list_length (references) > 1) {
       
  5232     gst_structure_set_value (s, "locations", &list_val);
       
  5233   }
       
  5234 
       
  5235   g_value_unset (&list_val);
       
  5236 
       
  5237   for (l = references; l != NULL; l = l->next) {
       
  5238     GstQtReference *ref = (GstQtReference *) l->data;
       
  5239 
       
  5240     gst_structure_free (ref->structure);
       
  5241     g_free (ref->location);
       
  5242     g_free (ref);
       
  5243   }
       
  5244   g_list_free (references);
       
  5245 
       
  5246   GST_INFO_OBJECT (qtdemux, "posting redirect message: %" GST_PTR_FORMAT, s);
       
  5247   msg = gst_message_new_element (GST_OBJECT_CAST (qtdemux), s);
       
  5248   gst_element_post_message (GST_ELEMENT_CAST (qtdemux), msg);
       
  5249 }
       
  5250 
       
  5251 /* look for redirect nodes, collect all redirect information and
       
  5252  * process it.
       
  5253  */
       
  5254 static gboolean
       
  5255 qtdemux_parse_redirects (GstQTDemux * qtdemux)
       
  5256 {
       
  5257   GNode *rmra, *rmda, *rdrf;
       
  5258 
       
  5259   rmra = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_rmra);
       
  5260   if (rmra) {
       
  5261     GList *redirects = NULL;
       
  5262 
       
  5263     rmda = qtdemux_tree_get_child_by_type (rmra, FOURCC_rmda);
       
  5264     while (rmda) {
       
  5265       GstQtReference ref = { NULL, NULL, 0, 0 };
       
  5266       GNode *rmdr, *rmvc;
       
  5267 
       
  5268       if ((rmdr = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmdr))) {
       
  5269         ref.min_req_bitrate = QT_UINT32 ((guint8 *) rmdr->data + 12);
       
  5270         GST_LOG_OBJECT (qtdemux, "data rate atom, required bitrate = %u",
       
  5271             ref.min_req_bitrate);
       
  5272       }
       
  5273 
       
  5274       if ((rmvc = qtdemux_tree_get_child_by_type (rmda, FOURCC_rmvc))) {
       
  5275         guint32 package = QT_FOURCC ((guint8 *) rmvc->data + 12);
       
  5276         guint version = QT_UINT32 ((guint8 *) rmvc->data + 16);
       
  5277 
       
  5278 #ifndef GST_DISABLE_GST_DEBUG
       
  5279         guint bitmask = QT_UINT32 ((guint8 *) rmvc->data + 20);
       
  5280 #endif
       
  5281         guint check_type = QT_UINT16 ((guint8 *) rmvc->data + 24);
       
  5282 
       
  5283         GST_LOG_OBJECT (qtdemux,
       
  5284             "version check atom [%" GST_FOURCC_FORMAT "], version=0x%08x"
       
  5285             ", mask=%08x, check_type=%u", GST_FOURCC_ARGS (package), version,
       
  5286             bitmask, check_type);
       
  5287         if (package == FOURCC_qtim && check_type == 0) {
       
  5288           ref.min_req_qt_version = version;
       
  5289         }
       
  5290       }
       
  5291 
       
  5292       rdrf = qtdemux_tree_get_child_by_type (rmda, FOURCC_rdrf);
       
  5293       if (rdrf) {
       
  5294         guint32 ref_type;
       
  5295         guint8 *ref_data;
       
  5296 
       
  5297         ref_type = QT_FOURCC ((guint8 *) rdrf->data + 12);
       
  5298         ref_data = (guint8 *) rdrf->data + 20;
       
  5299         if (ref_type == FOURCC_alis) {
       
  5300           guint record_len, record_version, fn_len;
       
  5301 
       
  5302           /* MacOSX alias record, google for alias-layout.txt */
       
  5303           record_len = QT_UINT16 (ref_data + 4);
       
  5304           record_version = QT_UINT16 (ref_data + 4 + 2);
       
  5305           fn_len = QT_UINT8 (ref_data + 50);
       
  5306           if (record_len > 50 && record_version == 2 && fn_len > 0) {
       
  5307             ref.location = g_strndup ((gchar *) ref_data + 51, fn_len);
       
  5308           }
       
  5309         } else if (ref_type == FOURCC_url_) {
       
  5310           ref.location = g_strdup ((gchar *) ref_data);
       
  5311         } else {
       
  5312           GST_DEBUG_OBJECT (qtdemux,
       
  5313               "unknown rdrf reference type %" GST_FOURCC_FORMAT,
       
  5314               GST_FOURCC_ARGS (ref_type));
       
  5315         }
       
  5316         if (ref.location != NULL) {
       
  5317           GST_INFO_OBJECT (qtdemux, "New location: %s", ref.location);
       
  5318           redirects = g_list_prepend (redirects, g_memdup (&ref, sizeof (ref)));
       
  5319         } else {
       
  5320           GST_WARNING_OBJECT (qtdemux,
       
  5321               "Failed to extract redirect location from rdrf atom");
       
  5322         }
       
  5323       }
       
  5324 
       
  5325       /* look for others */
       
  5326       rmda = qtdemux_tree_get_sibling_by_type (rmda, FOURCC_rmda);
       
  5327     }
       
  5328 
       
  5329     if (redirects != NULL) {
       
  5330       qtdemux_process_redirects (qtdemux, redirects);
       
  5331     }
       
  5332   }
       
  5333   return TRUE;
       
  5334 }
       
  5335 
       
  5336 static GstTagList *
       
  5337 qtdemux_add_container_format (GstQTDemux * qtdemux, GstTagList * tags)
       
  5338 {
       
  5339   const gchar *fmt;
       
  5340 
       
  5341   if (tags == NULL)
       
  5342     tags = gst_tag_list_new ();
       
  5343 
       
  5344   if (qtdemux->major_brand == FOURCC_mjp2)
       
  5345     fmt = "Motion JPEG 2000";
       
  5346   else if ((qtdemux->major_brand & 0xffff) == GST_MAKE_FOURCC ('3', 'g', 0, 0))
       
  5347     fmt = "3GP";
       
  5348   else if (qtdemux->major_brand == FOURCC_qt__)
       
  5349     fmt = "Quicktime";
       
  5350   else
       
  5351     fmt = "ISO MP4/M4A";
       
  5352 
       
  5353   GST_LOG_OBJECT (qtdemux, "mapped %" GST_FOURCC_FORMAT " to '%s'",
       
  5354       GST_FOURCC_ARGS (qtdemux->major_brand), fmt);
       
  5355 
       
  5356   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CONTAINER_FORMAT,
       
  5357       fmt, NULL);
       
  5358 
       
  5359   return tags;
       
  5360 }
       
  5361 
       
  5362 /* we have read th complete moov node now.
       
  5363  * This function parses all of the relevant info, creates the traks and
       
  5364  * prepares all data structures for playback
       
  5365  */
       
  5366 static gboolean
       
  5367 qtdemux_parse_tree (GstQTDemux * qtdemux)
       
  5368 {
       
  5369   GNode *mvhd;
       
  5370   GNode *trak;
       
  5371   GNode *udta;
       
  5372   gint64 duration;
       
  5373 
       
  5374   mvhd = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_mvhd);
       
  5375   if (mvhd == NULL) {
       
  5376     GST_LOG_OBJECT (qtdemux, "No mvhd node found, looking for redirects.");
       
  5377     return qtdemux_parse_redirects (qtdemux);
       
  5378   }
       
  5379 
       
  5380   qtdemux->timescale = QT_UINT32 ((guint8 *) mvhd->data + 20);
       
  5381   qtdemux->duration = QT_UINT32 ((guint8 *) mvhd->data + 24);
       
  5382 
       
  5383   GST_INFO_OBJECT (qtdemux, "timescale: %u", qtdemux->timescale);
       
  5384   GST_INFO_OBJECT (qtdemux, "duration: %u", qtdemux->duration);
       
  5385 
       
  5386   /* set duration in the segment info */
       
  5387   gst_qtdemux_get_duration (qtdemux, &duration);
       
  5388   gst_segment_set_duration (&qtdemux->segment, GST_FORMAT_TIME, duration);
       
  5389 
       
  5390   /* parse all traks */
       
  5391   trak = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_trak);
       
  5392   while (trak) {
       
  5393     qtdemux_parse_trak (qtdemux, trak);
       
  5394     /* iterate all siblings */
       
  5395     trak = qtdemux_tree_get_sibling_by_type (trak, FOURCC_trak);
       
  5396   }
       
  5397   gst_element_no_more_pads (GST_ELEMENT_CAST (qtdemux));
       
  5398 
       
  5399   /* find and push tags, we do this after adding the pads so we can push the
       
  5400    * tags downstream as well. */
       
  5401   udta = qtdemux_tree_get_child_by_type (qtdemux->moov_node, FOURCC_udta);
       
  5402   if (udta) {
       
  5403     qtdemux_parse_udta (qtdemux, udta);
       
  5404   } else {
       
  5405     GST_LOG_OBJECT (qtdemux, "No udta node found.");
       
  5406   }
       
  5407 
       
  5408   /* FIXME: tags must be pushed after the initial newsegment event */
       
  5409   qtdemux->tag_list = qtdemux_add_container_format (qtdemux, qtdemux->tag_list);
       
  5410   GST_INFO_OBJECT (qtdemux, "global tags: %" GST_PTR_FORMAT, qtdemux->tag_list);
       
  5411   gst_element_found_tags (GST_ELEMENT_CAST (qtdemux), qtdemux->tag_list);
       
  5412   qtdemux->tag_list = NULL;
       
  5413 
       
  5414   return TRUE;
       
  5415 }
       
  5416 
       
  5417 /* taken from ffmpeg */
       
  5418 static unsigned int
       
  5419 get_size (guint8 * ptr, guint8 ** end)
       
  5420 {
       
  5421   int count = 4;
       
  5422   int len = 0;
       
  5423 
       
  5424   while (count--) {
       
  5425     int c = *ptr;
       
  5426 
       
  5427     ptr++;
       
  5428     len = (len << 7) | (c & 0x7f);
       
  5429     if (!(c & 0x80))
       
  5430       break;
       
  5431   }
       
  5432   if (end)
       
  5433     *end = ptr;
       
  5434   return len;
       
  5435 }
       
  5436 
       
  5437 /* this can change the codec originally present in @list */
       
  5438 static void
       
  5439 gst_qtdemux_handle_esds (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  5440     GNode * esds, GstTagList * list)
       
  5441 {
       
  5442   int len = QT_UINT32 (esds->data);
       
  5443   guint8 *ptr = esds->data;
       
  5444   guint8 *end = ptr + len;
       
  5445   int tag;
       
  5446   guint8 *data_ptr = NULL;
       
  5447   int data_len = 0;
       
  5448   guint8 object_type_id = 0;
       
  5449   char *codec_name = NULL;
       
  5450   GstCaps *caps = NULL;
       
  5451 
       
  5452   GST_MEMDUMP_OBJECT (qtdemux, "esds", ptr, len);
       
  5453   ptr += 8;
       
  5454   GST_DEBUG_OBJECT (qtdemux, "version/flags = %08x", QT_UINT32 (ptr));
       
  5455   ptr += 4;
       
  5456   while (ptr < end) {
       
  5457     tag = QT_UINT8 (ptr);
       
  5458     GST_DEBUG_OBJECT (qtdemux, "tag = %02x", tag);
       
  5459     ptr++;
       
  5460     len = get_size (ptr, &ptr);
       
  5461     GST_DEBUG_OBJECT (qtdemux, "len = %d", len);
       
  5462 
       
  5463     switch (tag) {
       
  5464       case 0x03:
       
  5465         GST_DEBUG_OBJECT (qtdemux, "ID %04x", QT_UINT16 (ptr));
       
  5466         GST_DEBUG_OBJECT (qtdemux, "priority %04x", QT_UINT8 (ptr + 2));
       
  5467         ptr += 3;
       
  5468         break;
       
  5469       case 0x04:
       
  5470         object_type_id = QT_UINT8 (ptr);
       
  5471         GST_DEBUG_OBJECT (qtdemux, "object_type_id %02x", object_type_id);
       
  5472         GST_DEBUG_OBJECT (qtdemux, "stream_type %02x", QT_UINT8 (ptr + 1));
       
  5473         GST_DEBUG_OBJECT (qtdemux, "buffer_size_db %02x", QT_UINT24 (ptr + 2));
       
  5474         GST_DEBUG_OBJECT (qtdemux, "max bitrate %d", QT_UINT32 (ptr + 5));
       
  5475         GST_DEBUG_OBJECT (qtdemux, "avg bitrate %d", QT_UINT32 (ptr + 9));
       
  5476         ptr += 13;
       
  5477         break;
       
  5478       case 0x05:
       
  5479         GST_MEMDUMP_OBJECT (qtdemux, "data", ptr, len);
       
  5480         data_ptr = ptr;
       
  5481         data_len = len;
       
  5482         ptr += len;
       
  5483         break;
       
  5484       case 0x06:
       
  5485         GST_DEBUG_OBJECT (qtdemux, "data %02x", QT_UINT8 (ptr));
       
  5486         ptr += 1;
       
  5487         break;
       
  5488       default:
       
  5489         GST_ERROR_OBJECT (qtdemux, "parse error");
       
  5490         break;
       
  5491     }
       
  5492   }
       
  5493 
       
  5494   /* object_type_id in the esds atom in mp4a and mp4v tells us which codec is
       
  5495    * in use, and should also be used to override some other parameters for some
       
  5496    * codecs. */
       
  5497   switch (object_type_id) {
       
  5498     case 0x20:                 /* MPEG-4 */
       
  5499       break;                    /* Nothing special needed here */
       
  5500     case 0x21:                 /* H.264 */
       
  5501       codec_name = "H.264 / AVC";
       
  5502       caps = gst_caps_new_simple ("video/x-h264", NULL);
       
  5503       break;
       
  5504     case 0x40:                 /* AAC (any) */
       
  5505     case 0x66:                 /* AAC Main */
       
  5506     case 0x67:                 /* AAC LC */
       
  5507     case 0x68:                 /* AAC SSR */
       
  5508       /* Override channels and rate based on the codec_data, as it's often
       
  5509        * wrong. */
       
  5510       if (data_ptr && data_len >= 2) {
       
  5511         guint channels, rateindex;
       
  5512         int rates[] = { 96000, 88200, 64000, 48000, 44100, 32000,
       
  5513           24000, 22050, 16000, 12000, 11025, 8000
       
  5514         };
       
  5515 
       
  5516         channels = (data_ptr[1] & 0x7f) >> 3;
       
  5517         if (channels <= 7) {
       
  5518           stream->n_channels = channels;
       
  5519         }
       
  5520 
       
  5521         rateindex = ((data_ptr[0] & 0x7) << 1) | ((data_ptr[1] & 0x80) >> 7);
       
  5522         if (rateindex < sizeof (rates) / sizeof (*rates)) {
       
  5523           stream->rate = rates[rateindex];
       
  5524         }
       
  5525       }
       
  5526       break;
       
  5527     case 0x60:                 /* MPEG-2, various profiles */
       
  5528     case 0x61:
       
  5529     case 0x62:
       
  5530     case 0x63:
       
  5531     case 0x64:
       
  5532     case 0x65:
       
  5533       codec_name = "MPEG-2 video";
       
  5534 
       
  5535       gst_caps_unref (stream->caps);
       
  5536       stream->caps = gst_caps_new_simple ("video/mpeg",
       
  5537           "mpegversion", G_TYPE_INT, 2,
       
  5538           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5539       break;
       
  5540     case 0x69:                 /* MP3 has two different values, accept either */
       
  5541     case 0x6B:
       
  5542       /* change to mpeg1 layer 3 audio */
       
  5543       gst_caps_set_simple (stream->caps, "layer", G_TYPE_INT, 3,
       
  5544           "mpegversion", G_TYPE_INT, 1, NULL);
       
  5545       codec_name = "MPEG-1 layer 3";
       
  5546       break;
       
  5547     case 0x6A:                 /* MPEG-1 */
       
  5548       codec_name = "MPEG-1 video";
       
  5549 
       
  5550       gst_caps_unref (stream->caps);
       
  5551       stream->caps = gst_caps_new_simple ("video/mpeg",
       
  5552           "mpegversion", G_TYPE_INT, 1,
       
  5553           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5554       break;
       
  5555     case 0x6C:                 /* MJPEG */
       
  5556       caps = gst_caps_new_simple ("image/jpeg", NULL);
       
  5557       codec_name = "Motion-JPEG";
       
  5558       break;
       
  5559     case 0x6D:                 /* PNG */
       
  5560       caps = gst_caps_new_simple ("image/png", NULL);
       
  5561       codec_name = "PNG still images";
       
  5562       break;
       
  5563     case 0x6E:                 /* JPEG2000 */
       
  5564       codec_name = "JPEG-2000";
       
  5565       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
       
  5566       break;
       
  5567     case 0xA4:                 /* Dirac */
       
  5568       codec_name = "Dirac";
       
  5569       caps = gst_caps_new_simple ("video/x-dirac", NULL);
       
  5570       break;
       
  5571     case 0xA5:                 /* AC3 */
       
  5572       codec_name = "AC-3 audio";
       
  5573       caps = gst_caps_new_simple ("audio/x-ac3", NULL);
       
  5574       break;
       
  5575     case 0xE1:                 /* QCELP */
       
  5576       /* QCELP, the codec_data is a riff tag (little endian) with
       
  5577        * 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). */
       
  5578       caps = gst_caps_new_simple ("audio/qcelp", NULL);
       
  5579       codec_name = "QCELP";
       
  5580       break;
       
  5581     default:
       
  5582       break;
       
  5583   }
       
  5584 
       
  5585   /* If we have a replacement caps, then change our caps for this stream */
       
  5586   if (caps) {
       
  5587     gst_caps_unref (stream->caps);
       
  5588     stream->caps = caps;
       
  5589   }
       
  5590 
       
  5591   if (codec_name && list)
       
  5592     gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
       
  5593         GST_TAG_AUDIO_CODEC, codec_name, NULL);
       
  5594 
       
  5595   /* Add the codec_data attribute to caps, if we have it */
       
  5596   if (data_ptr) {
       
  5597     GstBuffer *buffer;
       
  5598 
       
  5599     buffer = gst_buffer_new_and_alloc (data_len);
       
  5600     memcpy (GST_BUFFER_DATA (buffer), data_ptr, data_len);
       
  5601 
       
  5602     GST_DEBUG_OBJECT (qtdemux, "setting codec_data from esds");
       
  5603     GST_MEMDUMP_OBJECT (qtdemux, "codec_data from esds", data_ptr, data_len);
       
  5604 
       
  5605     gst_caps_set_simple (stream->caps, "codec_data", GST_TYPE_BUFFER,
       
  5606         buffer, NULL);
       
  5607     gst_buffer_unref (buffer);
       
  5608   }
       
  5609 
       
  5610 }
       
  5611 
       
  5612 #define _codec(name) \
       
  5613   do { \
       
  5614     if (codec_name) { \
       
  5615       *codec_name = g_strdup (name); \
       
  5616     } \
       
  5617   } while (0)
       
  5618 
       
  5619 static GstCaps *
       
  5620 qtdemux_video_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  5621     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
       
  5622 {
       
  5623   GstCaps *caps;
       
  5624   const GstStructure *s;
       
  5625   const gchar *name;
       
  5626 
       
  5627   switch (fourcc) {
       
  5628     case GST_MAKE_FOURCC ('p', 'n', 'g', ' '):
       
  5629       _codec ("PNG still images");
       
  5630       caps = gst_caps_new_simple ("image/png", NULL);
       
  5631       break;
       
  5632     case GST_MAKE_FOURCC ('j', 'p', 'e', 'g'):
       
  5633       _codec ("JPEG still images");
       
  5634       caps = gst_caps_new_simple ("image/jpeg", NULL);
       
  5635       break;
       
  5636     case GST_MAKE_FOURCC ('m', 'j', 'p', 'a'):
       
  5637     case GST_MAKE_FOURCC ('A', 'V', 'D', 'J'):
       
  5638     case GST_MAKE_FOURCC ('M', 'J', 'P', 'G'):
       
  5639       _codec ("Motion-JPEG");
       
  5640       caps = gst_caps_new_simple ("image/jpeg", NULL);
       
  5641       break;
       
  5642     case GST_MAKE_FOURCC ('m', 'j', 'p', 'b'):
       
  5643       _codec ("Motion-JPEG format B");
       
  5644       caps = gst_caps_new_simple ("video/x-mjpeg-b", NULL);
       
  5645       break;
       
  5646     case GST_MAKE_FOURCC ('m', 'j', 'p', '2'):
       
  5647       _codec ("JPEG-2000");
       
  5648       /* override to what it should be according to spec, avoid palette_data */
       
  5649       stream->bits_per_sample = 24;
       
  5650       caps = gst_caps_new_simple ("image/x-j2c", "fields", G_TYPE_INT, 1, NULL);
       
  5651       break;
       
  5652     case GST_MAKE_FOURCC ('S', 'V', 'Q', '3'):
       
  5653       _codec ("Sorensen video v.3");
       
  5654       caps = gst_caps_new_simple ("video/x-svq",
       
  5655           "svqversion", G_TYPE_INT, 3, NULL);
       
  5656       break;
       
  5657     case GST_MAKE_FOURCC ('s', 'v', 'q', 'i'):
       
  5658     case GST_MAKE_FOURCC ('S', 'V', 'Q', '1'):
       
  5659       _codec ("Sorensen video v.1");
       
  5660       caps = gst_caps_new_simple ("video/x-svq",
       
  5661           "svqversion", G_TYPE_INT, 1, NULL);
       
  5662       break;
       
  5663     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
       
  5664     {
       
  5665       guint16 bps;
       
  5666 
       
  5667       _codec ("Raw RGB video");
       
  5668       bps = QT_UINT16 (stsd_data + 98);
       
  5669       /* set common stuff */
       
  5670       caps = gst_caps_new_simple ("video/x-raw-rgb",
       
  5671           "endianness", G_TYPE_INT, G_BYTE_ORDER, "depth", G_TYPE_INT, bps,
       
  5672           NULL);
       
  5673 
       
  5674       switch (bps) {
       
  5675         case 15:
       
  5676           gst_caps_set_simple (caps,
       
  5677               "bpp", G_TYPE_INT, 16,
       
  5678               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
       
  5679               "red_mask", G_TYPE_INT, 0x7c00,
       
  5680               "green_mask", G_TYPE_INT, 0x03e0,
       
  5681               "blue_mask", G_TYPE_INT, 0x001f, NULL);
       
  5682           break;
       
  5683         case 16:
       
  5684           gst_caps_set_simple (caps,
       
  5685               "bpp", G_TYPE_INT, 16,
       
  5686               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
       
  5687               "red_mask", G_TYPE_INT, 0xf800,
       
  5688               "green_mask", G_TYPE_INT, 0x07e0,
       
  5689               "blue_mask", G_TYPE_INT, 0x001f, NULL);
       
  5690           break;
       
  5691         case 24:
       
  5692           gst_caps_set_simple (caps,
       
  5693               "bpp", G_TYPE_INT, 24,
       
  5694               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
       
  5695               "red_mask", G_TYPE_INT, 0xff0000,
       
  5696               "green_mask", G_TYPE_INT, 0x00ff00,
       
  5697               "blue_mask", G_TYPE_INT, 0x0000ff, NULL);
       
  5698           break;
       
  5699         case 32:
       
  5700           gst_caps_set_simple (caps,
       
  5701               "bpp", G_TYPE_INT, 32,
       
  5702               "endianness", G_TYPE_INT, G_BIG_ENDIAN,
       
  5703               "alpha_mask", G_TYPE_INT, 0xff000000,
       
  5704               "red_mask", G_TYPE_INT, 0x00ff0000,
       
  5705               "green_mask", G_TYPE_INT, 0x0000ff00,
       
  5706               "blue_mask", G_TYPE_INT, 0x000000ff, NULL);
       
  5707           break;
       
  5708         default:
       
  5709           /* unknown */
       
  5710           break;
       
  5711       }
       
  5712       break;
       
  5713     }
       
  5714     case GST_MAKE_FOURCC ('y', 'v', '1', '2'):
       
  5715       _codec ("Raw planar YUV 4:2:0");
       
  5716       caps = gst_caps_new_simple ("video/x-raw-yuv",
       
  5717           "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'),
       
  5718           NULL);
       
  5719       break;
       
  5720     case GST_MAKE_FOURCC ('y', 'u', 'v', '2'):
       
  5721     case GST_MAKE_FOURCC ('Y', 'u', 'v', '2'):
       
  5722       _codec ("Raw packed YUV 4:2:2");
       
  5723       caps = gst_caps_new_simple ("video/x-raw-yuv",
       
  5724           "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'),
       
  5725           NULL);
       
  5726       break;
       
  5727     case GST_MAKE_FOURCC ('2', 'v', 'u', 'y'):
       
  5728       _codec ("Raw packed YUV 4:2:0");
       
  5729       caps = gst_caps_new_simple ("video/x-raw-yuv",
       
  5730           "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'),
       
  5731           NULL);
       
  5732       break;
       
  5733     case GST_MAKE_FOURCC ('v', '2', '1', '0'):
       
  5734       _codec ("Raw packed YUV 10-bit 4:2:2");
       
  5735       caps = gst_caps_new_simple ("video/x-raw-yuv",
       
  5736           "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('v', '2', '1', '0'),
       
  5737           NULL);
       
  5738       break;
       
  5739     case GST_MAKE_FOURCC ('m', 'p', 'e', 'g'):
       
  5740     case GST_MAKE_FOURCC ('m', 'p', 'g', '1'):
       
  5741       _codec ("MPEG-1 video");
       
  5742       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 1,
       
  5743           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5744       break;
       
  5745     case GST_MAKE_FOURCC ('h', 'd', 'v', '1'): // HDV 720p30
       
  5746     case GST_MAKE_FOURCC ('h', 'd', 'v', '2'): // HDV 1080i60
       
  5747     case GST_MAKE_FOURCC ('h', 'd', 'v', '3'): // HDV 1080i50
       
  5748     case GST_MAKE_FOURCC ('h', 'd', 'v', '5'): // HDV 720p25
       
  5749     case GST_MAKE_FOURCC ('h', 'd', 'v', '6'): // HDV 1080i60
       
  5750     case GST_MAKE_FOURCC ('m', 'x', '5', 'n'): // MPEG2 IMX NTSC 525/60 50mb/s produced by FCP
       
  5751     case GST_MAKE_FOURCC ('m', 'x', '5', 'p'): // MPEG2 IMX PAL 625/60 50mb/s produced by FCP
       
  5752     case GST_MAKE_FOURCC ('m', 'x', '4', 'n'): // MPEG2 IMX NTSC 525/60 40mb/s produced by FCP
       
  5753     case GST_MAKE_FOURCC ('m', 'x', '4', 'p'): // MPEG2 IMX PAL 625/60 40mb/s produced by FCP
       
  5754     case GST_MAKE_FOURCC ('m', 'x', '3', 'n'): // MPEG2 IMX NTSC 525/60 30mb/s produced by FCP
       
  5755     case GST_MAKE_FOURCC ('m', 'x', '3', 'p'): // MPEG2 IMX PAL 625/50 30mb/s produced by FCP
       
  5756     case GST_MAKE_FOURCC ('x', 'd', 'v', '2'): // XDCAM HD 1080i60
       
  5757     case GST_MAKE_FOURCC ('A', 'V', 'm', 'p'): // AVID IMX PAL
       
  5758     case GST_MAKE_FOURCC ('m', 'p', 'g', '2'): // AVID IMX PAL
       
  5759       _codec ("MPEG-2 video");
       
  5760       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 2,
       
  5761           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5762       break;
       
  5763     case GST_MAKE_FOURCC ('g', 'i', 'f', ' '):
       
  5764       _codec ("GIF still images");
       
  5765       caps = gst_caps_new_simple ("image/gif", NULL);
       
  5766       break;
       
  5767     case GST_MAKE_FOURCC ('h', '2', '6', '3'):
       
  5768     case GST_MAKE_FOURCC ('H', '2', '6', '3'):
       
  5769     case GST_MAKE_FOURCC ('s', '2', '6', '3'):
       
  5770     case GST_MAKE_FOURCC ('U', '2', '6', '3'):
       
  5771       _codec ("H.263");
       
  5772       /* ffmpeg uses the height/width props, don't know why */
       
  5773       caps = gst_caps_new_simple ("video/x-h263", NULL);
       
  5774       break;
       
  5775     case GST_MAKE_FOURCC ('m', 'p', '4', 'v'):
       
  5776       _codec ("MPEG-4 video");
       
  5777       caps = gst_caps_new_simple ("video/mpeg", "mpegversion", G_TYPE_INT, 4,
       
  5778           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5779       break;
       
  5780     case GST_MAKE_FOURCC ('3', 'i', 'v', 'd'):
       
  5781     case GST_MAKE_FOURCC ('3', 'I', 'V', 'D'):
       
  5782       _codec ("Microsoft MPEG-4 4.3");  /* FIXME? */
       
  5783       caps = gst_caps_new_simple ("video/x-msmpeg",
       
  5784           "msmpegversion", G_TYPE_INT, 43, NULL);
       
  5785       break;
       
  5786     case GST_MAKE_FOURCC ('3', 'I', 'V', '1'):
       
  5787     case GST_MAKE_FOURCC ('3', 'I', 'V', '2'):
       
  5788       _codec ("3ivX video");
       
  5789       caps = gst_caps_new_simple ("video/x-3ivx", NULL);
       
  5790       break;
       
  5791     case GST_MAKE_FOURCC ('D', 'I', 'V', '3'):
       
  5792       _codec ("DivX 3");
       
  5793       caps = gst_caps_new_simple ("video/x-divx",
       
  5794           "divxversion", G_TYPE_INT, 3, NULL);
       
  5795       break;
       
  5796     case GST_MAKE_FOURCC ('D', 'I', 'V', 'X'):
       
  5797     case GST_MAKE_FOURCC ('d', 'i', 'v', 'x'):
       
  5798       _codec ("DivX 4");
       
  5799       caps = gst_caps_new_simple ("video/x-divx",
       
  5800           "divxversion", G_TYPE_INT, 4, NULL);
       
  5801       break;
       
  5802     case GST_MAKE_FOURCC ('D', 'X', '5', '0'):
       
  5803       _codec ("DivX 5");
       
  5804       caps = gst_caps_new_simple ("video/x-divx",
       
  5805           "divxversion", G_TYPE_INT, 5, NULL);
       
  5806       break;
       
  5807     case GST_MAKE_FOURCC ('X', 'V', 'I', 'D'):
       
  5808     case GST_MAKE_FOURCC ('x', 'v', 'i', 'd'):
       
  5809       _codec ("XVID MPEG-4");
       
  5810       caps = gst_caps_new_simple ("video/x-xvid", NULL);
       
  5811       break;
       
  5812 
       
  5813     case GST_MAKE_FOURCC ('F', 'M', 'P', '4'):
       
  5814     case GST_MAKE_FOURCC ('U', 'M', 'P', '4'):
       
  5815       caps = gst_caps_new_simple ("video/mpeg",
       
  5816           "mpegversion", G_TYPE_INT, 4, NULL);
       
  5817       if (codec_name)
       
  5818         *codec_name = g_strdup ("FFmpeg MPEG-4");
       
  5819       break;
       
  5820 
       
  5821     case GST_MAKE_FOURCC ('c', 'v', 'i', 'd'):
       
  5822       _codec ("Cinepak");
       
  5823       caps = gst_caps_new_simple ("video/x-cinepak", NULL);
       
  5824       break;
       
  5825     case GST_MAKE_FOURCC ('q', 'd', 'r', 'w'):
       
  5826       _codec ("Apple QuickDraw");
       
  5827       caps = gst_caps_new_simple ("video/x-qdrw", NULL);
       
  5828       break;
       
  5829     case GST_MAKE_FOURCC ('r', 'p', 'z', 'a'):
       
  5830       _codec ("Apple video");
       
  5831       caps = gst_caps_new_simple ("video/x-apple-video", NULL);
       
  5832       break;
       
  5833     case GST_MAKE_FOURCC ('a', 'v', 'c', '1'):
       
  5834       _codec ("H.264 / AVC");
       
  5835       caps = gst_caps_new_simple ("video/x-h264", NULL);
       
  5836       break;
       
  5837     case GST_MAKE_FOURCC ('r', 'l', 'e', ' '):
       
  5838       _codec ("Run-length encoding");
       
  5839       caps = gst_caps_new_simple ("video/x-rle",
       
  5840           "layout", G_TYPE_STRING, "quicktime", NULL);
       
  5841       break;
       
  5842     case GST_MAKE_FOURCC ('i', 'v', '3', '2'):
       
  5843       _codec ("Indeo Video 3");
       
  5844       caps = gst_caps_new_simple ("video/x-indeo",
       
  5845           "indeoversion", G_TYPE_INT, 3, NULL);
       
  5846       break;
       
  5847     case GST_MAKE_FOURCC ('I', 'V', '4', '1'):
       
  5848     case GST_MAKE_FOURCC ('i', 'v', '4', '1'):
       
  5849       _codec ("Intel Video 4");
       
  5850       caps = gst_caps_new_simple ("video/x-indeo",
       
  5851           "indeoversion", G_TYPE_INT, 4, NULL);
       
  5852       break;
       
  5853     case GST_MAKE_FOURCC ('d', 'v', 'c', 'p'):
       
  5854     case GST_MAKE_FOURCC ('d', 'v', 'c', ' '):
       
  5855     case GST_MAKE_FOURCC ('d', 'v', 's', 'd'):
       
  5856     case GST_MAKE_FOURCC ('D', 'V', 'S', 'D'):
       
  5857     case GST_MAKE_FOURCC ('d', 'v', 'c', 's'):
       
  5858     case GST_MAKE_FOURCC ('D', 'V', 'C', 'S'):
       
  5859     case GST_MAKE_FOURCC ('d', 'v', '2', '5'):
       
  5860     case GST_MAKE_FOURCC ('d', 'v', 'p', 'p'):
       
  5861       _codec ("DV Video");
       
  5862       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 25,
       
  5863           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5864       break;
       
  5865     case GST_MAKE_FOURCC ('d', 'v', '5', 'n'): //DVCPRO50 NTSC
       
  5866     case GST_MAKE_FOURCC ('d', 'v', '5', 'p'): //DVCPRO50 PAL
       
  5867       _codec ("DVCPro50 Video");
       
  5868       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 50,
       
  5869           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5870       break;
       
  5871     case GST_MAKE_FOURCC ('d', 'v', 'h', '5'): //DVCPRO HD 50i produced by FCP
       
  5872     case GST_MAKE_FOURCC ('d', 'v', 'h', '6'): //DVCPRO HD 60i produced by FCP
       
  5873       _codec ("DVCProHD Video");
       
  5874       caps = gst_caps_new_simple ("video/x-dv", "dvversion", G_TYPE_INT, 100,
       
  5875           "systemstream", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5876       break;
       
  5877     case GST_MAKE_FOURCC ('s', 'm', 'c', ' '):
       
  5878       _codec ("Apple Graphics (SMC)");
       
  5879       caps = gst_caps_new_simple ("video/x-smc", NULL);
       
  5880       break;
       
  5881     case GST_MAKE_FOURCC ('V', 'P', '3', '1'):
       
  5882       _codec ("VP3");
       
  5883       caps = gst_caps_new_simple ("video/x-vp3", NULL);
       
  5884       break;
       
  5885     case GST_MAKE_FOURCC ('X', 'i', 'T', 'h'):
       
  5886       _codec ("Theora");
       
  5887       caps = gst_caps_new_simple ("video/x-theora", NULL);
       
  5888       /* theora uses one byte of padding in the data stream because it does not
       
  5889        * allow 0 sized packets while theora does */
       
  5890       stream->padding = 1;
       
  5891       break;
       
  5892     case GST_MAKE_FOURCC ('d', 'r', 'a', 'c'):
       
  5893       _codec ("Dirac");
       
  5894       caps = gst_caps_new_simple ("video/x-dirac", NULL);
       
  5895       break;
       
  5896     case GST_MAKE_FOURCC ('t', 'i', 'f', 'f'):
       
  5897       _codec ("TIFF still images");
       
  5898       caps = gst_caps_new_simple ("image/tiff", NULL);
       
  5899       break;
       
  5900     case GST_MAKE_FOURCC ('i', 'c', 'o', 'd'):
       
  5901       _codec ("Apple Intermediate Codec");
       
  5902       caps = gst_caps_from_string ("video/x-apple-intermediate-codec");
       
  5903       break;
       
  5904     case GST_MAKE_FOURCC ('A', 'V', 'd', 'n'):
       
  5905       _codec ("AVID DNxHD");
       
  5906       caps = gst_caps_from_string ("video/x-dnxhd");
       
  5907       break;
       
  5908     case GST_MAKE_FOURCC ('k', 'p', 'c', 'd'):
       
  5909     default:
       
  5910     {
       
  5911       char *s;
       
  5912 
       
  5913       s = g_strdup_printf ("video/x-gst-fourcc-%" GST_FOURCC_FORMAT,
       
  5914           GST_FOURCC_ARGS (fourcc));
       
  5915       caps = gst_caps_new_simple (s, NULL);
       
  5916       break;
       
  5917     }
       
  5918   }
       
  5919 
       
  5920   /* enable clipping for raw video streams */
       
  5921   s = gst_caps_get_structure (caps, 0);
       
  5922   name = gst_structure_get_name (s);
       
  5923   if (g_str_has_prefix (name, "video/x-raw-")) {
       
  5924     stream->need_clip = TRUE;
       
  5925   }
       
  5926   return caps;
       
  5927 }
       
  5928 
       
  5929 static GstCaps *
       
  5930 qtdemux_audio_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  5931     guint32 fourcc, const guint8 * data, int len, gchar ** codec_name)
       
  5932 {
       
  5933   GstCaps *caps;
       
  5934   const GstStructure *s;
       
  5935   const gchar *name;
       
  5936   gint endian = 0;
       
  5937 
       
  5938   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
       
  5939 
       
  5940   switch (fourcc) {
       
  5941     case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
       
  5942     case GST_MAKE_FOURCC ('r', 'a', 'w', ' '):
       
  5943       _codec ("Raw 8-bit PCM audio");
       
  5944       caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 8,
       
  5945           "depth", G_TYPE_INT, 8, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
       
  5946       break;
       
  5947     case GST_MAKE_FOURCC ('t', 'w', 'o', 's'):
       
  5948       endian = G_BIG_ENDIAN;
       
  5949       /* fall-through */
       
  5950     case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
       
  5951     {
       
  5952       gchar *str;
       
  5953       gint depth;
       
  5954 
       
  5955       if (!endian)
       
  5956         endian = G_LITTLE_ENDIAN;
       
  5957 
       
  5958       depth = stream->bytes_per_packet * 8;
       
  5959       str = g_strdup_printf ("Raw %d-bit PCM audio", depth);
       
  5960       _codec (str);
       
  5961       g_free (str);
       
  5962       caps = gst_caps_new_simple ("audio/x-raw-int",
       
  5963           "width", G_TYPE_INT, depth, "depth", G_TYPE_INT, depth,
       
  5964           "endianness", G_TYPE_INT, endian,
       
  5965           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
       
  5966       break;
       
  5967     }
       
  5968     case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
       
  5969       _codec ("Raw 64-bit floating-point audio");
       
  5970       caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 64,
       
  5971           "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
       
  5972       break;
       
  5973     case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
       
  5974       _codec ("Raw 32-bit floating-point audio");
       
  5975       caps = gst_caps_new_simple ("audio/x-raw-float", "width", G_TYPE_INT, 32,
       
  5976           "endianness", G_TYPE_INT, G_BIG_ENDIAN, NULL);
       
  5977       break;
       
  5978     case FOURCC_in24:
       
  5979       _codec ("Raw 24-bit PCM audio");
       
  5980       /* we assume BIG ENDIAN, an enda box will tell us to change this to little
       
  5981        * endian later */
       
  5982       caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 24,
       
  5983           "depth", G_TYPE_INT, 24,
       
  5984           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
       
  5985           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
       
  5986       break;
       
  5987     case GST_MAKE_FOURCC ('i', 'n', '3', '2'):
       
  5988       _codec ("Raw 32-bit PCM audio");
       
  5989       caps = gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, 32,
       
  5990           "depth", G_TYPE_INT, 32,
       
  5991           "endianness", G_TYPE_INT, G_BIG_ENDIAN,
       
  5992           "signed", G_TYPE_BOOLEAN, TRUE, NULL);
       
  5993       break;
       
  5994     case GST_MAKE_FOURCC ('u', 'l', 'a', 'w'):
       
  5995       _codec ("Mu-law audio");
       
  5996       caps = gst_caps_new_simple ("audio/x-mulaw", NULL);
       
  5997       break;
       
  5998     case GST_MAKE_FOURCC ('a', 'l', 'a', 'w'):
       
  5999       _codec ("A-law audio");
       
  6000       caps = gst_caps_new_simple ("audio/x-alaw", NULL);
       
  6001       break;
       
  6002     case 0x0200736d:
       
  6003     case 0x6d730002:
       
  6004       _codec ("Microsoft ADPCM");
       
  6005       /* Microsoft ADPCM-ACM code 2 */
       
  6006       caps = gst_caps_new_simple ("audio/x-adpcm",
       
  6007           "layout", G_TYPE_STRING, "microsoft", NULL);
       
  6008       break;
       
  6009     case 0x1100736d:
       
  6010     case 0x6d730011:
       
  6011       _codec ("IMA Loki SDL MJPEG ADPCM");
       
  6012       /* Loki ADPCM, See #550288 for a file that only decodes
       
  6013        * with the smjpeg variant of the ADPCM decoder. */
       
  6014       caps = gst_caps_new_simple ("audio/x-adpcm",
       
  6015           "layout", G_TYPE_STRING, "smjpeg", NULL);
       
  6016       break;
       
  6017     case 0x1700736d:
       
  6018     case 0x6d730017:
       
  6019       _codec ("DVI/Intel IMA ADPCM");
       
  6020       /* FIXME DVI/Intel IMA ADPCM/ACM code 17 */
       
  6021       caps = gst_caps_new_simple ("audio/x-adpcm",
       
  6022           "layout", G_TYPE_STRING, "quicktime", NULL);
       
  6023       break;
       
  6024     case 0x5500736d:
       
  6025     case 0x6d730055:
       
  6026       /* MPEG layer 3, CBR only (pre QT4.1) */
       
  6027     case GST_MAKE_FOURCC ('.', 'm', 'p', '3'):
       
  6028       _codec ("MPEG-1 layer 3");
       
  6029       /* MPEG layer 3, CBR & VBR (QT4.1 and later) */
       
  6030       caps = gst_caps_new_simple ("audio/mpeg", "layer", G_TYPE_INT, 3,
       
  6031           "mpegversion", G_TYPE_INT, 1, NULL);
       
  6032       break;
       
  6033     case 0x20736d:
       
  6034     case GST_MAKE_FOURCC ('a', 'c', '-', '3'):
       
  6035       _codec ("AC-3 audio");
       
  6036       caps = gst_caps_new_simple ("audio/x-ac3", NULL);
       
  6037       stream->sampled = TRUE;
       
  6038       break;
       
  6039     case GST_MAKE_FOURCC ('M', 'A', 'C', '3'):
       
  6040       _codec ("MACE-3");
       
  6041       caps = gst_caps_new_simple ("audio/x-mace",
       
  6042           "maceversion", G_TYPE_INT, 3, NULL);
       
  6043       break;
       
  6044     case GST_MAKE_FOURCC ('M', 'A', 'C', '6'):
       
  6045       _codec ("MACE-6");
       
  6046       caps = gst_caps_new_simple ("audio/x-mace",
       
  6047           "maceversion", G_TYPE_INT, 6, NULL);
       
  6048       break;
       
  6049     case GST_MAKE_FOURCC ('O', 'g', 'g', 'V'):
       
  6050       /* ogg/vorbis */
       
  6051       caps = gst_caps_new_simple ("application/ogg", NULL);
       
  6052       break;
       
  6053     case GST_MAKE_FOURCC ('d', 'v', 'c', 'a'):
       
  6054       _codec ("DV audio");
       
  6055       caps = gst_caps_new_simple ("audio/x-dv", NULL);
       
  6056       break;
       
  6057     case GST_MAKE_FOURCC ('m', 'p', '4', 'a'):
       
  6058       _codec ("MPEG-4 AAC audio");
       
  6059       caps = gst_caps_new_simple ("audio/mpeg",
       
  6060           "mpegversion", G_TYPE_INT, 4, "framed", G_TYPE_BOOLEAN, TRUE, NULL);
       
  6061       break;
       
  6062     case GST_MAKE_FOURCC ('Q', 'D', 'M', 'C'):
       
  6063       _codec ("QDesign Music");
       
  6064       caps = gst_caps_new_simple ("audio/x-qdm", NULL);
       
  6065       break;
       
  6066     case GST_MAKE_FOURCC ('Q', 'D', 'M', '2'):
       
  6067       _codec ("QDesign Music v.2");
       
  6068       /* FIXME: QDesign music version 2 (no constant) */
       
  6069       if (data) {
       
  6070         caps = gst_caps_new_simple ("audio/x-qdm2",
       
  6071             "framesize", G_TYPE_INT, QT_UINT32 (data + 52),
       
  6072             "bitrate", G_TYPE_INT, QT_UINT32 (data + 40),
       
  6073             "blocksize", G_TYPE_INT, QT_UINT32 (data + 44), NULL);
       
  6074       } else {
       
  6075         caps = gst_caps_new_simple ("audio/x-qdm2", NULL);
       
  6076       }
       
  6077       break;
       
  6078     case GST_MAKE_FOURCC ('a', 'g', 's', 'm'):
       
  6079       _codec ("GSM audio");
       
  6080       caps = gst_caps_new_simple ("audio/x-gsm", NULL);
       
  6081       break;
       
  6082     case GST_MAKE_FOURCC ('s', 'a', 'm', 'r'):
       
  6083       _codec ("AMR audio");
       
  6084       caps = gst_caps_new_simple ("audio/AMR", NULL);
       
  6085       break;
       
  6086     case GST_MAKE_FOURCC ('s', 'a', 'w', 'b'):
       
  6087       _codec ("AMR-WB audio");
       
  6088       caps = gst_caps_new_simple ("audio/AMR-WB", NULL);
       
  6089       break;
       
  6090     case GST_MAKE_FOURCC ('i', 'm', 'a', '4'):
       
  6091       _codec ("Quicktime IMA ADPCM");
       
  6092       caps = gst_caps_new_simple ("audio/x-adpcm",
       
  6093           "layout", G_TYPE_STRING, "quicktime", NULL);
       
  6094       break;
       
  6095     case GST_MAKE_FOURCC ('a', 'l', 'a', 'c'):
       
  6096       _codec ("Apple lossless audio");
       
  6097       caps = gst_caps_new_simple ("audio/x-alac", NULL);
       
  6098       break;
       
  6099     case GST_MAKE_FOURCC ('q', 't', 'v', 'r'):
       
  6100       /* ? */
       
  6101     case GST_MAKE_FOURCC ('Q', 'c', 'l', 'p'):
       
  6102       /* QUALCOMM PureVoice */
       
  6103     default:
       
  6104     {
       
  6105       char *s;
       
  6106 
       
  6107       s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
       
  6108           GST_FOURCC_ARGS (fourcc));
       
  6109       caps = gst_caps_new_simple (s, NULL);
       
  6110       break;
       
  6111     }
       
  6112   }
       
  6113 
       
  6114   /* enable clipping for raw audio streams */
       
  6115   s = gst_caps_get_structure (caps, 0);
       
  6116   name = gst_structure_get_name (s);
       
  6117   if (g_str_has_prefix (name, "audio/x-raw-")) {
       
  6118     stream->need_clip = TRUE;
       
  6119   }
       
  6120   return caps;
       
  6121 }
       
  6122 
       
  6123 static GstCaps *
       
  6124 qtdemux_subp_caps (GstQTDemux * qtdemux, QtDemuxStream * stream,
       
  6125     guint32 fourcc, const guint8 * stsd_data, gchar ** codec_name)
       
  6126 {
       
  6127   GstCaps *caps;
       
  6128 
       
  6129   GST_DEBUG_OBJECT (qtdemux, "resolve fourcc %08x", fourcc);
       
  6130 
       
  6131   switch (fourcc) {
       
  6132     case GST_MAKE_FOURCC ('m', 'p', '4', 's'):
       
  6133       _codec ("DVD subtitle");
       
  6134       caps = gst_caps_new_simple ("video/x-dvd-subpicture", NULL);
       
  6135       break;
       
  6136     default:
       
  6137     {
       
  6138       char *s;
       
  6139 
       
  6140       s = g_strdup_printf ("audio/x-gst-fourcc-%" GST_FOURCC_FORMAT,
       
  6141           GST_FOURCC_ARGS (fourcc));
       
  6142       caps = gst_caps_new_simple (s, NULL);
       
  6143       break;
       
  6144     }
       
  6145   }
       
  6146   return caps;
       
  6147 }