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