gst_plugins_good/gst/avi/gstavimux.c
author hgs
Fri, 09 Jul 2010 16:26:45 -0500
changeset 24 bc39b352897e
parent 16 8e837d1bf446
permissions -rw-r--r--
201027
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16
hgs
parents:
diff changeset
     1
/* AVI muxer plugin for GStreamer
hgs
parents:
diff changeset
     2
 * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
hgs
parents:
diff changeset
     3
 *           (C) 2006 Mark Nauwelaerts <manauw@skynet.be>
hgs
parents:
diff changeset
     4
 *
hgs
parents:
diff changeset
     5
 * This library is free software; you can redistribute it and/or
hgs
parents:
diff changeset
     6
 * modify it under the terms of the GNU Library General Public
hgs
parents:
diff changeset
     7
 * License as published by the Free Software Foundation; either
hgs
parents:
diff changeset
     8
 * version 2 of the License, or (at your option) any later version.
hgs
parents:
diff changeset
     9
 *
hgs
parents:
diff changeset
    10
 * This library is distributed in the hope that it will be useful,
hgs
parents:
diff changeset
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
hgs
parents:
diff changeset
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
hgs
parents:
diff changeset
    13
 * Library General Public License for more details.
hgs
parents:
diff changeset
    14
 *
hgs
parents:
diff changeset
    15
 * You should have received a copy of the GNU Library General Public
hgs
parents:
diff changeset
    16
 * License along with this library; if not, write to the
hgs
parents:
diff changeset
    17
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
hgs
parents:
diff changeset
    18
 * Boston, MA 02111-1307, USA.
hgs
parents:
diff changeset
    19
 */
hgs
parents:
diff changeset
    20
hgs
parents:
diff changeset
    21
/* based on:
hgs
parents:
diff changeset
    22
 * - the old avimuxer (by Wim Taymans)
hgs
parents:
diff changeset
    23
 * - xawtv's aviwriter (by Gerd Knorr)
hgs
parents:
diff changeset
    24
 * - mjpegtools' avilib (by Rainer Johanni)
hgs
parents:
diff changeset
    25
 * - openDML large-AVI docs
hgs
parents:
diff changeset
    26
 */
hgs
parents:
diff changeset
    27
hgs
parents:
diff changeset
    28
/**
hgs
parents:
diff changeset
    29
 * SECTION:element-avimux
hgs
parents:
diff changeset
    30
 *
hgs
parents:
diff changeset
    31
 * Muxes raw or compressed audio and/or video streams into an AVI file.
hgs
parents:
diff changeset
    32
 *
hgs
parents:
diff changeset
    33
 * <refsect2>
hgs
parents:
diff changeset
    34
 * <title>Example launch lines</title>
hgs
parents:
diff changeset
    35
 * <para>(write everything in one line, without the backslash characters)</para>
hgs
parents:
diff changeset
    36
 * |[
hgs
parents:
diff changeset
    37
 * gst-launch videotestsrc num-buffers=250 \
hgs
parents:
diff changeset
    38
 * ! 'video/x-raw-yuv,format=(fourcc)I420,width=320,height=240,framerate=(fraction)25/1' \
hgs
parents:
diff changeset
    39
 * ! queue ! mux. \
hgs
parents:
diff changeset
    40
 * audiotestsrc num-buffers=440 ! audioconvert \
hgs
parents:
diff changeset
    41
 * ! 'audio/x-raw-int,rate=44100,channels=2' ! queue ! mux. \
hgs
parents:
diff changeset
    42
 * avimux name=mux ! filesink location=test.avi
hgs
parents:
diff changeset
    43
 * ]| This will create an .AVI file containing an uncompressed video stream
hgs
parents:
diff changeset
    44
 * with a test picture and an uncompressed audio stream containing a 
hgs
parents:
diff changeset
    45
 * test sound.
hgs
parents:
diff changeset
    46
 * |[
hgs
parents:
diff changeset
    47
 * gst-launch videotestsrc num-buffers=250 \
hgs
parents:
diff changeset
    48
 * ! 'video/x-raw-yuv,format=(fourcc)I420,width=320,height=240,framerate=(fraction)25/1' \
hgs
parents:
diff changeset
    49
 * ! xvidenc ! queue ! mux. \
hgs
parents:
diff changeset
    50
 * audiotestsrc num-buffers=440 ! audioconvert ! 'audio/x-raw-int,rate=44100,channels=2' \
hgs
parents:
diff changeset
    51
 * ! lame ! queue ! mux. \
hgs
parents:
diff changeset
    52
 * avimux name=mux ! filesink location=test.avi
hgs
parents:
diff changeset
    53
 * ]| This will create an .AVI file containing the same test video and sound
hgs
parents:
diff changeset
    54
 * as above, only that both streams will be compressed this time. This will
hgs
parents:
diff changeset
    55
 * only work if you have the necessary encoder elements installed of course.
hgs
parents:
diff changeset
    56
 * </refsect2>
hgs
parents:
diff changeset
    57
 */
hgs
parents:
diff changeset
    58
hgs
parents:
diff changeset
    59
#ifdef HAVE_CONFIG_H
hgs
parents:
diff changeset
    60
#include "config.h"
hgs
parents:
diff changeset
    61
#endif
hgs
parents:
diff changeset
    62
hgs
parents:
diff changeset
    63
#include "gst/gst-i18n-plugin.h"
hgs
parents:
diff changeset
    64
#include <stdlib.h>
hgs
parents:
diff changeset
    65
#include <string.h>
hgs
parents:
diff changeset
    66
hgs
parents:
diff changeset
    67
#include <gst/video/video.h>
hgs
parents:
diff changeset
    68
hgs
parents:
diff changeset
    69
#include "gstavimux.h"
hgs
parents:
diff changeset
    70
hgs
parents:
diff changeset
    71
GST_DEBUG_CATEGORY_STATIC (avimux_debug);
hgs
parents:
diff changeset
    72
#define GST_CAT_DEFAULT avimux_debug
hgs
parents:
diff changeset
    73
hgs
parents:
diff changeset
    74
enum
hgs
parents:
diff changeset
    75
{
hgs
parents:
diff changeset
    76
  ARG_0,
hgs
parents:
diff changeset
    77
  ARG_BIGFILE
hgs
parents:
diff changeset
    78
};
hgs
parents:
diff changeset
    79
hgs
parents:
diff changeset
    80
#define DEFAULT_BIGFILE TRUE
hgs
parents:
diff changeset
    81
hgs
parents:
diff changeset
    82
static const GstElementDetails gst_avi_mux_details =
hgs
parents:
diff changeset
    83
GST_ELEMENT_DETAILS ("Avi muxer",
hgs
parents:
diff changeset
    84
    "Codec/Muxer",
hgs
parents:
diff changeset
    85
    "Muxes audio and video into an avi stream",
hgs
parents:
diff changeset
    86
    "Ronald Bultje <rbultje@ronald.bitfreak.net>");
hgs
parents:
diff changeset
    87
hgs
parents:
diff changeset
    88
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
hgs
parents:
diff changeset
    89
    GST_PAD_SRC,
hgs
parents:
diff changeset
    90
    GST_PAD_ALWAYS,
hgs
parents:
diff changeset
    91
    GST_STATIC_CAPS ("video/x-msvideo")
hgs
parents:
diff changeset
    92
    );
hgs
parents:
diff changeset
    93
hgs
parents:
diff changeset
    94
static GstStaticPadTemplate video_sink_factory =
hgs
parents:
diff changeset
    95
    GST_STATIC_PAD_TEMPLATE ("video_%d",
hgs
parents:
diff changeset
    96
    GST_PAD_SINK,
hgs
parents:
diff changeset
    97
    GST_PAD_REQUEST,
hgs
parents:
diff changeset
    98
    GST_STATIC_CAPS ("video/x-raw-yuv, "
hgs
parents:
diff changeset
    99
        "format = (fourcc) { YUY2, I420 }, "
hgs
parents:
diff changeset
   100
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   101
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   102
        "framerate = (fraction) [ 0, MAX ]; "
hgs
parents:
diff changeset
   103
        "image/jpeg, "
hgs
parents:
diff changeset
   104
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   105
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   106
        "framerate = (fraction) [ 0, MAX ]; "
hgs
parents:
diff changeset
   107
        "video/x-divx, "
hgs
parents:
diff changeset
   108
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   109
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   110
        "framerate = (fraction) [ 0, MAX ], "
hgs
parents:
diff changeset
   111
        "divxversion = (int) [ 3, 5 ]; "
hgs
parents:
diff changeset
   112
        "video/x-xvid, "
hgs
parents:
diff changeset
   113
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   114
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   115
        "framerate = (fraction) [ 0, MAX ]; "
hgs
parents:
diff changeset
   116
        "video/x-3ivx, "
hgs
parents:
diff changeset
   117
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   118
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   119
        "framerate = (fraction) [ 0, MAX ]; "
hgs
parents:
diff changeset
   120
        "video/x-msmpeg, "
hgs
parents:
diff changeset
   121
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   122
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   123
        "framerate = (fraction) [ 0, MAX ], "
hgs
parents:
diff changeset
   124
        "msmpegversion = (int) [ 41, 43 ]; "
hgs
parents:
diff changeset
   125
        "video/mpeg, "
hgs
parents:
diff changeset
   126
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   127
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   128
        "framerate = (fraction) [ 0, MAX ], "
hgs
parents:
diff changeset
   129
        "mpegversion = (int) { 1, 2, 4}, "
hgs
parents:
diff changeset
   130
        "systemstream = (boolean) FALSE; "
hgs
parents:
diff changeset
   131
        "video/x-h263, "
hgs
parents:
diff changeset
   132
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   133
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   134
        "framerate = (fraction) [ 0, MAX ]; "
hgs
parents:
diff changeset
   135
        "video/x-h264, "
hgs
parents:
diff changeset
   136
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   137
        "height = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   138
        "framerate = (fraction) [ 0, MAX ]; "
hgs
parents:
diff changeset
   139
        "video/x-dv, "
hgs
parents:
diff changeset
   140
        "width = (int) 720, "
hgs
parents:
diff changeset
   141
        "height = (int) { 576, 480 }, "
hgs
parents:
diff changeset
   142
        "framerate = (fraction) [ 0, MAX ], "
hgs
parents:
diff changeset
   143
        "systemstream = (boolean) FALSE; "
hgs
parents:
diff changeset
   144
        "video/x-huffyuv, "
hgs
parents:
diff changeset
   145
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   146
        "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ];"
hgs
parents:
diff changeset
   147
        "video/x-dirac, "
hgs
parents:
diff changeset
   148
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   149
        "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ];"
hgs
parents:
diff changeset
   150
        "video/x-wmv, "
hgs
parents:
diff changeset
   151
        "width = (int) [ 16, 4096 ], "
hgs
parents:
diff changeset
   152
        "height = (int) [ 16, 4096 ], " "framerate = (fraction) [ 0, MAX ], "
hgs
parents:
diff changeset
   153
        "wmvversion = (int) [ 1, 3]")
hgs
parents:
diff changeset
   154
    );
hgs
parents:
diff changeset
   155
hgs
parents:
diff changeset
   156
static GstStaticPadTemplate audio_sink_factory =
hgs
parents:
diff changeset
   157
    GST_STATIC_PAD_TEMPLATE ("audio_%d",
hgs
parents:
diff changeset
   158
    GST_PAD_SINK,
hgs
parents:
diff changeset
   159
    GST_PAD_REQUEST,
hgs
parents:
diff changeset
   160
    GST_STATIC_CAPS ("audio/x-raw-int, "
hgs
parents:
diff changeset
   161
        "endianness = (int) LITTLE_ENDIAN, "
hgs
parents:
diff changeset
   162
        "signed = (boolean) { TRUE, FALSE }, "
hgs
parents:
diff changeset
   163
        "width = (int) { 8, 16 }, "
hgs
parents:
diff changeset
   164
        "depth = (int) { 8, 16 }, "
hgs
parents:
diff changeset
   165
        "rate = (int) [ 1000, 96000 ], "
hgs
parents:
diff changeset
   166
        "channels = (int) [ 1, 2 ]; "
hgs
parents:
diff changeset
   167
        "audio/mpeg, "
hgs
parents:
diff changeset
   168
        "mpegversion = (int) 1, "
hgs
parents:
diff changeset
   169
        "layer = (int) [ 1, 3 ], "
hgs
parents:
diff changeset
   170
        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; "
hgs
parents:
diff changeset
   171
        "audio/mpeg, "
hgs
parents:
diff changeset
   172
        "mpegversion = (int) 4, "
hgs
parents:
diff changeset
   173
        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; "
hgs
parents:
diff changeset
   174
/*#if 0 VC6 doesn't support #if here ...
hgs
parents:
diff changeset
   175
        "audio/x-vorbis, "
hgs
parents:
diff changeset
   176
        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; "
hgs
parents:
diff changeset
   177
#endif*/
hgs
parents:
diff changeset
   178
        "audio/x-ac3, "
hgs
parents:
diff changeset
   179
        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ]; "
hgs
parents:
diff changeset
   180
        "audio/x-alaw, "
hgs
parents:
diff changeset
   181
        "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]; "
hgs
parents:
diff changeset
   182
        "audio/x-mulaw, "
hgs
parents:
diff changeset
   183
        "rate = (int) [ 1000, 48000 ], " "channels = (int) [ 1, 2 ]; "
hgs
parents:
diff changeset
   184
        "audio/x-wma, "
hgs
parents:
diff changeset
   185
        "rate = (int) [ 1000, 96000 ], " "channels = (int) [ 1, 2 ], "
hgs
parents:
diff changeset
   186
        "wmaversion = (int) [ 1, 2 ] ")
hgs
parents:
diff changeset
   187
    );
hgs
parents:
diff changeset
   188
hgs
parents:
diff changeset
   189
static void gst_avi_mux_base_init (gpointer g_class);
hgs
parents:
diff changeset
   190
static void gst_avi_mux_class_init (GstAviMuxClass * klass);
hgs
parents:
diff changeset
   191
static void gst_avi_mux_init (GstAviMux * avimux);
hgs
parents:
diff changeset
   192
static void gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free);
hgs
parents:
diff changeset
   193
hgs
parents:
diff changeset
   194
static GstFlowReturn gst_avi_mux_collect_pads (GstCollectPads * pads,
hgs
parents:
diff changeset
   195
    GstAviMux * avimux);
hgs
parents:
diff changeset
   196
static gboolean gst_avi_mux_handle_event (GstPad * pad, GstEvent * event);
hgs
parents:
diff changeset
   197
static GstPad *gst_avi_mux_request_new_pad (GstElement * element,
hgs
parents:
diff changeset
   198
    GstPadTemplate * templ, const gchar * name);
hgs
parents:
diff changeset
   199
static void gst_avi_mux_release_pad (GstElement * element, GstPad * pad);
hgs
parents:
diff changeset
   200
static void gst_avi_mux_set_property (GObject * object,
hgs
parents:
diff changeset
   201
    guint prop_id, const GValue * value, GParamSpec * pspec);
hgs
parents:
diff changeset
   202
static void gst_avi_mux_get_property (GObject * object,
hgs
parents:
diff changeset
   203
    guint prop_id, GValue * value, GParamSpec * pspec);
hgs
parents:
diff changeset
   204
static GstStateChangeReturn gst_avi_mux_change_state (GstElement * element,
hgs
parents:
diff changeset
   205
    GstStateChange transition);
hgs
parents:
diff changeset
   206
hgs
parents:
diff changeset
   207
static GstElementClass *parent_class = NULL;
hgs
parents:
diff changeset
   208
hgs
parents:
diff changeset
   209
GType
hgs
parents:
diff changeset
   210
gst_avi_mux_get_type (void)
hgs
parents:
diff changeset
   211
{
hgs
parents:
diff changeset
   212
  static GType avimux_type = 0;
hgs
parents:
diff changeset
   213
hgs
parents:
diff changeset
   214
  if (!avimux_type) {
hgs
parents:
diff changeset
   215
    static const GTypeInfo avimux_info = {
hgs
parents:
diff changeset
   216
      sizeof (GstAviMuxClass),
hgs
parents:
diff changeset
   217
      gst_avi_mux_base_init,
hgs
parents:
diff changeset
   218
      NULL,
hgs
parents:
diff changeset
   219
      (GClassInitFunc) gst_avi_mux_class_init,
hgs
parents:
diff changeset
   220
      NULL,
hgs
parents:
diff changeset
   221
      NULL,
hgs
parents:
diff changeset
   222
      sizeof (GstAviMux),
hgs
parents:
diff changeset
   223
      0,
hgs
parents:
diff changeset
   224
      (GInstanceInitFunc) gst_avi_mux_init,
hgs
parents:
diff changeset
   225
    };
hgs
parents:
diff changeset
   226
    static const GInterfaceInfo tag_setter_info = {
hgs
parents:
diff changeset
   227
      NULL,
hgs
parents:
diff changeset
   228
      NULL,
hgs
parents:
diff changeset
   229
      NULL
hgs
parents:
diff changeset
   230
    };
hgs
parents:
diff changeset
   231
hgs
parents:
diff changeset
   232
    avimux_type =
hgs
parents:
diff changeset
   233
        g_type_register_static (GST_TYPE_ELEMENT, "GstAviMux", &avimux_info, 0);
hgs
parents:
diff changeset
   234
    g_type_add_interface_static (avimux_type, GST_TYPE_TAG_SETTER,
hgs
parents:
diff changeset
   235
        &tag_setter_info);
hgs
parents:
diff changeset
   236
  }
hgs
parents:
diff changeset
   237
  return avimux_type;
hgs
parents:
diff changeset
   238
}
hgs
parents:
diff changeset
   239
hgs
parents:
diff changeset
   240
static void
hgs
parents:
diff changeset
   241
gst_avi_mux_base_init (gpointer g_class)
hgs
parents:
diff changeset
   242
{
hgs
parents:
diff changeset
   243
  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
hgs
parents:
diff changeset
   244
hgs
parents:
diff changeset
   245
  gst_element_class_add_pad_template (element_class,
hgs
parents:
diff changeset
   246
      gst_static_pad_template_get (&src_factory));
hgs
parents:
diff changeset
   247
  gst_element_class_add_pad_template (element_class,
hgs
parents:
diff changeset
   248
      gst_static_pad_template_get (&audio_sink_factory));
hgs
parents:
diff changeset
   249
  gst_element_class_add_pad_template (element_class,
hgs
parents:
diff changeset
   250
      gst_static_pad_template_get (&video_sink_factory));
hgs
parents:
diff changeset
   251
hgs
parents:
diff changeset
   252
  gst_element_class_set_details (element_class, &gst_avi_mux_details);
hgs
parents:
diff changeset
   253
hgs
parents:
diff changeset
   254
  GST_DEBUG_CATEGORY_INIT (avimux_debug, "avimux", 0, "Muxer for AVI streams");
hgs
parents:
diff changeset
   255
}
hgs
parents:
diff changeset
   256
hgs
parents:
diff changeset
   257
static void
hgs
parents:
diff changeset
   258
gst_avi_mux_finalize (GObject * object)
hgs
parents:
diff changeset
   259
{
hgs
parents:
diff changeset
   260
  GstAviMux *mux = GST_AVI_MUX (object);
hgs
parents:
diff changeset
   261
  GSList *node;
hgs
parents:
diff changeset
   262
hgs
parents:
diff changeset
   263
  /* completely free each sinkpad */
hgs
parents:
diff changeset
   264
  node = mux->sinkpads;
hgs
parents:
diff changeset
   265
  while (node) {
hgs
parents:
diff changeset
   266
    GstAviPad *avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
   267
hgs
parents:
diff changeset
   268
    node = node->next;
hgs
parents:
diff changeset
   269
hgs
parents:
diff changeset
   270
    gst_avi_mux_pad_reset (avipad, TRUE);
hgs
parents:
diff changeset
   271
    g_free (avipad);
hgs
parents:
diff changeset
   272
  }
hgs
parents:
diff changeset
   273
  g_slist_free (mux->sinkpads);
hgs
parents:
diff changeset
   274
  mux->sinkpads = NULL;
hgs
parents:
diff changeset
   275
hgs
parents:
diff changeset
   276
  g_free (mux->idx);
hgs
parents:
diff changeset
   277
  mux->idx = NULL;
hgs
parents:
diff changeset
   278
hgs
parents:
diff changeset
   279
  gst_object_unref (mux->collect);
hgs
parents:
diff changeset
   280
hgs
parents:
diff changeset
   281
  G_OBJECT_CLASS (parent_class)->finalize (object);
hgs
parents:
diff changeset
   282
}
hgs
parents:
diff changeset
   283
hgs
parents:
diff changeset
   284
static void
hgs
parents:
diff changeset
   285
gst_avi_mux_class_init (GstAviMuxClass * klass)
hgs
parents:
diff changeset
   286
{
hgs
parents:
diff changeset
   287
  GObjectClass *gobject_class;
hgs
parents:
diff changeset
   288
  GstElementClass *gstelement_class;
hgs
parents:
diff changeset
   289
hgs
parents:
diff changeset
   290
  gobject_class = (GObjectClass *) klass;
hgs
parents:
diff changeset
   291
  gstelement_class = (GstElementClass *) klass;
hgs
parents:
diff changeset
   292
hgs
parents:
diff changeset
   293
  parent_class = g_type_class_peek_parent (klass);
hgs
parents:
diff changeset
   294
hgs
parents:
diff changeset
   295
  gobject_class->get_property = gst_avi_mux_get_property;
hgs
parents:
diff changeset
   296
  gobject_class->set_property = gst_avi_mux_set_property;
hgs
parents:
diff changeset
   297
  gobject_class->finalize = gst_avi_mux_finalize;
hgs
parents:
diff changeset
   298
hgs
parents:
diff changeset
   299
  g_object_class_install_property (gobject_class, ARG_BIGFILE,
hgs
parents:
diff changeset
   300
      g_param_spec_boolean ("bigfile", "Bigfile Support (>2GB)",
hgs
parents:
diff changeset
   301
          "Support for openDML-2.0 (big) AVI files", DEFAULT_BIGFILE,
hgs
parents:
diff changeset
   302
          G_PARAM_READWRITE));
hgs
parents:
diff changeset
   303
hgs
parents:
diff changeset
   304
  gstelement_class->request_new_pad =
hgs
parents:
diff changeset
   305
      GST_DEBUG_FUNCPTR (gst_avi_mux_request_new_pad);
hgs
parents:
diff changeset
   306
  gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_avi_mux_release_pad);
hgs
parents:
diff changeset
   307
  gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_avi_mux_change_state);
hgs
parents:
diff changeset
   308
}
hgs
parents:
diff changeset
   309
hgs
parents:
diff changeset
   310
/* reset pad to initial state
hgs
parents:
diff changeset
   311
 * free - if true, release all, not only stream related, data */
hgs
parents:
diff changeset
   312
static void
hgs
parents:
diff changeset
   313
gst_avi_mux_pad_reset (GstAviPad * avipad, gboolean free)
hgs
parents:
diff changeset
   314
{
hgs
parents:
diff changeset
   315
  /* generic part */
hgs
parents:
diff changeset
   316
  memset (&(avipad->hdr), 0, sizeof (gst_riff_strh));
hgs
parents:
diff changeset
   317
hgs
parents:
diff changeset
   318
  memset (&(avipad->idx[0]), 0, sizeof (avipad->idx));
hgs
parents:
diff changeset
   319
hgs
parents:
diff changeset
   320
  if (free) {
hgs
parents:
diff changeset
   321
    g_free (avipad->tag);
hgs
parents:
diff changeset
   322
    avipad->tag = NULL;
hgs
parents:
diff changeset
   323
    g_free (avipad->idx_tag);
hgs
parents:
diff changeset
   324
    avipad->idx_tag = NULL;
hgs
parents:
diff changeset
   325
  }
hgs
parents:
diff changeset
   326
hgs
parents:
diff changeset
   327
  if (avipad->is_video) {
hgs
parents:
diff changeset
   328
    GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
hgs
parents:
diff changeset
   329
hgs
parents:
diff changeset
   330
    avipad->hdr.type = GST_MAKE_FOURCC ('v', 'i', 'd', 's');
hgs
parents:
diff changeset
   331
    if (vidpad->vids_codec_data) {
hgs
parents:
diff changeset
   332
      gst_buffer_unref (vidpad->vids_codec_data);
hgs
parents:
diff changeset
   333
      vidpad->vids_codec_data = NULL;
hgs
parents:
diff changeset
   334
    }
hgs
parents:
diff changeset
   335
hgs
parents:
diff changeset
   336
    memset (&(vidpad->vids), 0, sizeof (gst_riff_strf_vids));
hgs
parents:
diff changeset
   337
    memset (&(vidpad->vprp), 0, sizeof (gst_riff_vprp));
hgs
parents:
diff changeset
   338
  } else {
hgs
parents:
diff changeset
   339
    GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
hgs
parents:
diff changeset
   340
hgs
parents:
diff changeset
   341
    avipad->hdr.type = GST_MAKE_FOURCC ('a', 'u', 'd', 's');
hgs
parents:
diff changeset
   342
    if (audpad->auds_codec_data) {
hgs
parents:
diff changeset
   343
      gst_buffer_unref (audpad->auds_codec_data);
hgs
parents:
diff changeset
   344
      audpad->auds_codec_data = NULL;
hgs
parents:
diff changeset
   345
    }
hgs
parents:
diff changeset
   346
hgs
parents:
diff changeset
   347
    memset (&(audpad->auds), 0, sizeof (gst_riff_strf_auds));
hgs
parents:
diff changeset
   348
  }
hgs
parents:
diff changeset
   349
}
hgs
parents:
diff changeset
   350
hgs
parents:
diff changeset
   351
static void
hgs
parents:
diff changeset
   352
gst_avi_mux_reset (GstAviMux * avimux)
hgs
parents:
diff changeset
   353
{
hgs
parents:
diff changeset
   354
  GSList *node, *newlist = NULL;
hgs
parents:
diff changeset
   355
hgs
parents:
diff changeset
   356
  /* free and reset each sinkpad */
hgs
parents:
diff changeset
   357
  node = avimux->sinkpads;
hgs
parents:
diff changeset
   358
  while (node) {
hgs
parents:
diff changeset
   359
    GstAviPad *avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
   360
hgs
parents:
diff changeset
   361
    node = node->next;
hgs
parents:
diff changeset
   362
hgs
parents:
diff changeset
   363
    gst_avi_mux_pad_reset (avipad, FALSE);
hgs
parents:
diff changeset
   364
    /* if this pad has collectdata, keep it, otherwise dump it completely */
hgs
parents:
diff changeset
   365
    if (avipad->collect)
hgs
parents:
diff changeset
   366
      newlist = g_slist_append (newlist, avipad);
hgs
parents:
diff changeset
   367
    else {
hgs
parents:
diff changeset
   368
      gst_avi_mux_pad_reset (avipad, TRUE);
hgs
parents:
diff changeset
   369
      g_free (avipad);
hgs
parents:
diff changeset
   370
    }
hgs
parents:
diff changeset
   371
  }
hgs
parents:
diff changeset
   372
hgs
parents:
diff changeset
   373
  /* free the old list of sinkpads, only keep the real collecting ones */
hgs
parents:
diff changeset
   374
  g_slist_free (avimux->sinkpads);
hgs
parents:
diff changeset
   375
  avimux->sinkpads = newlist;
hgs
parents:
diff changeset
   376
hgs
parents:
diff changeset
   377
  /* avi data */
hgs
parents:
diff changeset
   378
  avimux->num_frames = 0;
hgs
parents:
diff changeset
   379
  memset (&(avimux->avi_hdr), 0, sizeof (gst_riff_avih));
hgs
parents:
diff changeset
   380
  avimux->avi_hdr.max_bps = 10000000;
hgs
parents:
diff changeset
   381
  avimux->codec_data_size = 0;
hgs
parents:
diff changeset
   382
hgs
parents:
diff changeset
   383
  if (avimux->tags_snap) {
hgs
parents:
diff changeset
   384
    gst_tag_list_free (avimux->tags_snap);
hgs
parents:
diff changeset
   385
    avimux->tags_snap = NULL;
hgs
parents:
diff changeset
   386
  }
hgs
parents:
diff changeset
   387
hgs
parents:
diff changeset
   388
  g_free (avimux->idx);
hgs
parents:
diff changeset
   389
  avimux->idx = NULL;
hgs
parents:
diff changeset
   390
hgs
parents:
diff changeset
   391
  /* state info */
hgs
parents:
diff changeset
   392
  avimux->write_header = TRUE;
hgs
parents:
diff changeset
   393
hgs
parents:
diff changeset
   394
  /* tags */
hgs
parents:
diff changeset
   395
  gst_tag_setter_reset_tags (GST_TAG_SETTER (avimux));
hgs
parents:
diff changeset
   396
}
hgs
parents:
diff changeset
   397
hgs
parents:
diff changeset
   398
static void
hgs
parents:
diff changeset
   399
gst_avi_mux_init (GstAviMux * avimux)
hgs
parents:
diff changeset
   400
{
hgs
parents:
diff changeset
   401
  avimux->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
hgs
parents:
diff changeset
   402
  gst_pad_use_fixed_caps (avimux->srcpad);
hgs
parents:
diff changeset
   403
  gst_element_add_pad (GST_ELEMENT (avimux), avimux->srcpad);
hgs
parents:
diff changeset
   404
hgs
parents:
diff changeset
   405
  /* property */
hgs
parents:
diff changeset
   406
  avimux->enable_large_avi = DEFAULT_BIGFILE;
hgs
parents:
diff changeset
   407
hgs
parents:
diff changeset
   408
  avimux->collect = gst_collect_pads_new ();
hgs
parents:
diff changeset
   409
  gst_collect_pads_set_function (avimux->collect,
hgs
parents:
diff changeset
   410
      (GstCollectPadsFunction) (GST_DEBUG_FUNCPTR (gst_avi_mux_collect_pads)),
hgs
parents:
diff changeset
   411
      avimux);
hgs
parents:
diff changeset
   412
hgs
parents:
diff changeset
   413
  /* set to clean state */
hgs
parents:
diff changeset
   414
  gst_avi_mux_reset (avimux);
hgs
parents:
diff changeset
   415
}
hgs
parents:
diff changeset
   416
hgs
parents:
diff changeset
   417
static gboolean
hgs
parents:
diff changeset
   418
gst_avi_mux_vidsink_set_caps (GstPad * pad, GstCaps * vscaps)
hgs
parents:
diff changeset
   419
{
hgs
parents:
diff changeset
   420
  GstAviMux *avimux;
hgs
parents:
diff changeset
   421
  GstAviVideoPad *avipad;
hgs
parents:
diff changeset
   422
  GstAviCollectData *collect_pad;
hgs
parents:
diff changeset
   423
  GstStructure *structure;
hgs
parents:
diff changeset
   424
  const gchar *mimetype;
hgs
parents:
diff changeset
   425
  const GValue *fps, *par;
hgs
parents:
diff changeset
   426
  const GValue *codec_data;
hgs
parents:
diff changeset
   427
  gint width, height;
hgs
parents:
diff changeset
   428
  gint par_n, par_d;
hgs
parents:
diff changeset
   429
hgs
parents:
diff changeset
   430
  avimux = GST_AVI_MUX (gst_pad_get_parent (pad));
hgs
parents:
diff changeset
   431
hgs
parents:
diff changeset
   432
  /* find stream data */
hgs
parents:
diff changeset
   433
  collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad);
hgs
parents:
diff changeset
   434
  g_assert (collect_pad);
hgs
parents:
diff changeset
   435
  avipad = (GstAviVideoPad *) collect_pad->avipad;
hgs
parents:
diff changeset
   436
  g_assert (avipad);
hgs
parents:
diff changeset
   437
  g_assert (avipad->parent.is_video);
hgs
parents:
diff changeset
   438
  g_assert (avipad->parent.hdr.type == GST_MAKE_FOURCC ('v', 'i', 'd', 's'));
hgs
parents:
diff changeset
   439
hgs
parents:
diff changeset
   440
  GST_DEBUG_OBJECT (avimux, "%s:%s, caps=%" GST_PTR_FORMAT,
hgs
parents:
diff changeset
   441
      GST_DEBUG_PAD_NAME (pad), vscaps);
hgs
parents:
diff changeset
   442
hgs
parents:
diff changeset
   443
  structure = gst_caps_get_structure (vscaps, 0);
hgs
parents:
diff changeset
   444
  mimetype = gst_structure_get_name (structure);
hgs
parents:
diff changeset
   445
hgs
parents:
diff changeset
   446
  /* global */
hgs
parents:
diff changeset
   447
  avipad->vids.size = sizeof (gst_riff_strf_vids);
hgs
parents:
diff changeset
   448
  avipad->vids.planes = 1;
hgs
parents:
diff changeset
   449
  if (!gst_structure_get_int (structure, "width", &width) ||
hgs
parents:
diff changeset
   450
      !gst_structure_get_int (structure, "height", &height)) {
hgs
parents:
diff changeset
   451
    goto refuse_caps;
hgs
parents:
diff changeset
   452
  }
hgs
parents:
diff changeset
   453
hgs
parents:
diff changeset
   454
  avipad->vids.width = width;
hgs
parents:
diff changeset
   455
  avipad->vids.height = height;
hgs
parents:
diff changeset
   456
hgs
parents:
diff changeset
   457
  fps = gst_structure_get_value (structure, "framerate");
hgs
parents:
diff changeset
   458
  if (fps == NULL || !GST_VALUE_HOLDS_FRACTION (fps))
hgs
parents:
diff changeset
   459
    goto refuse_caps;
hgs
parents:
diff changeset
   460
hgs
parents:
diff changeset
   461
  avipad->parent.hdr.rate = gst_value_get_fraction_numerator (fps);
hgs
parents:
diff changeset
   462
  avipad->parent.hdr.scale = gst_value_get_fraction_denominator (fps);
hgs
parents:
diff changeset
   463
hgs
parents:
diff changeset
   464
  /* (pixel) aspect ratio data, if any */
hgs
parents:
diff changeset
   465
  par = gst_structure_get_value (structure, "pixel-aspect-ratio");
hgs
parents:
diff changeset
   466
  /* only use video properties header if there is non-trivial aspect info */
hgs
parents:
diff changeset
   467
  if (par && GST_VALUE_HOLDS_FRACTION (par) &&
hgs
parents:
diff changeset
   468
      ((par_n = gst_value_get_fraction_numerator (par)) !=
hgs
parents:
diff changeset
   469
          (par_d = gst_value_get_fraction_denominator (par)))) {
hgs
parents:
diff changeset
   470
    GValue to_ratio = { 0, };
hgs
parents:
diff changeset
   471
    guint ratio_n, ratio_d;
hgs
parents:
diff changeset
   472
hgs
parents:
diff changeset
   473
    /* some fraction voodoo to obtain simplest possible ratio */
hgs
parents:
diff changeset
   474
    g_value_init (&to_ratio, GST_TYPE_FRACTION);
hgs
parents:
diff changeset
   475
    gst_value_set_fraction (&to_ratio, width * par_n, height * par_d);
hgs
parents:
diff changeset
   476
    ratio_n = gst_value_get_fraction_numerator (&to_ratio);
hgs
parents:
diff changeset
   477
    ratio_d = gst_value_get_fraction_denominator (&to_ratio);
hgs
parents:
diff changeset
   478
    GST_DEBUG_OBJECT (avimux, "generating vprp data with aspect ratio %d/%d",
hgs
parents:
diff changeset
   479
        ratio_n, ratio_d);
hgs
parents:
diff changeset
   480
    /* simply fill in */
hgs
parents:
diff changeset
   481
    avipad->vprp.vert_rate = avipad->parent.hdr.rate / avipad->parent.hdr.scale;
hgs
parents:
diff changeset
   482
    avipad->vprp.hor_t_total = width;
hgs
parents:
diff changeset
   483
    avipad->vprp.vert_lines = height;
hgs
parents:
diff changeset
   484
    avipad->vprp.aspect = (ratio_n) << 16 | (ratio_d & 0xffff);
hgs
parents:
diff changeset
   485
    avipad->vprp.width = width;
hgs
parents:
diff changeset
   486
    avipad->vprp.height = height;
hgs
parents:
diff changeset
   487
    avipad->vprp.fields = 1;
hgs
parents:
diff changeset
   488
    avipad->vprp.field_info[0].compressed_bm_height = height;
hgs
parents:
diff changeset
   489
    avipad->vprp.field_info[0].compressed_bm_width = width;
hgs
parents:
diff changeset
   490
    avipad->vprp.field_info[0].valid_bm_height = height;
hgs
parents:
diff changeset
   491
    avipad->vprp.field_info[0].valid_bm_width = width;
hgs
parents:
diff changeset
   492
  }
hgs
parents:
diff changeset
   493
hgs
parents:
diff changeset
   494
  /* codec initialization data, if any */
hgs
parents:
diff changeset
   495
  codec_data = gst_structure_get_value (structure, "codec_data");
hgs
parents:
diff changeset
   496
  if (codec_data) {
hgs
parents:
diff changeset
   497
    avipad->vids_codec_data = gst_value_get_buffer (codec_data);
hgs
parents:
diff changeset
   498
    gst_buffer_ref (avipad->vids_codec_data);
hgs
parents:
diff changeset
   499
    /* keep global track of size */
hgs
parents:
diff changeset
   500
    avimux->codec_data_size += GST_BUFFER_SIZE (avipad->vids_codec_data);
hgs
parents:
diff changeset
   501
  }
hgs
parents:
diff changeset
   502
hgs
parents:
diff changeset
   503
  if (!strcmp (mimetype, "video/x-raw-yuv")) {
hgs
parents:
diff changeset
   504
    guint32 format;
hgs
parents:
diff changeset
   505
hgs
parents:
diff changeset
   506
    gst_structure_get_fourcc (structure, "format", &format);
hgs
parents:
diff changeset
   507
    avipad->vids.compression = format;
hgs
parents:
diff changeset
   508
    switch (format) {
hgs
parents:
diff changeset
   509
      case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
hgs
parents:
diff changeset
   510
        avipad->vids.bit_cnt = 16;
hgs
parents:
diff changeset
   511
        break;
hgs
parents:
diff changeset
   512
      case GST_MAKE_FOURCC ('I', '4', '2', '0'):
hgs
parents:
diff changeset
   513
        avipad->vids.bit_cnt = 12;
hgs
parents:
diff changeset
   514
        break;
hgs
parents:
diff changeset
   515
    }
hgs
parents:
diff changeset
   516
  } else {
hgs
parents:
diff changeset
   517
    avipad->vids.bit_cnt = 24;
hgs
parents:
diff changeset
   518
    avipad->vids.compression = 0;
hgs
parents:
diff changeset
   519
hgs
parents:
diff changeset
   520
    /* find format */
hgs
parents:
diff changeset
   521
    if (!strcmp (mimetype, "video/x-huffyuv")) {
hgs
parents:
diff changeset
   522
      avipad->vids.compression = GST_MAKE_FOURCC ('H', 'F', 'Y', 'U');
hgs
parents:
diff changeset
   523
    } else if (!strcmp (mimetype, "image/jpeg")) {
hgs
parents:
diff changeset
   524
      avipad->vids.compression = GST_MAKE_FOURCC ('M', 'J', 'P', 'G');
hgs
parents:
diff changeset
   525
    } else if (!strcmp (mimetype, "video/x-divx")) {
hgs
parents:
diff changeset
   526
      gint divxversion;
hgs
parents:
diff changeset
   527
hgs
parents:
diff changeset
   528
      gst_structure_get_int (structure, "divxversion", &divxversion);
hgs
parents:
diff changeset
   529
      switch (divxversion) {
hgs
parents:
diff changeset
   530
        case 3:
hgs
parents:
diff changeset
   531
          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', '3');
hgs
parents:
diff changeset
   532
          break;
hgs
parents:
diff changeset
   533
        case 4:
hgs
parents:
diff changeset
   534
          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
hgs
parents:
diff changeset
   535
          break;
hgs
parents:
diff changeset
   536
        case 5:
hgs
parents:
diff changeset
   537
          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'X', '5', '0');
hgs
parents:
diff changeset
   538
          break;
hgs
parents:
diff changeset
   539
      }
hgs
parents:
diff changeset
   540
    } else if (!strcmp (mimetype, "video/x-xvid")) {
hgs
parents:
diff changeset
   541
      avipad->vids.compression = GST_MAKE_FOURCC ('X', 'V', 'I', 'D');
hgs
parents:
diff changeset
   542
    } else if (!strcmp (mimetype, "video/x-3ivx")) {
hgs
parents:
diff changeset
   543
      avipad->vids.compression = GST_MAKE_FOURCC ('3', 'I', 'V', '2');
hgs
parents:
diff changeset
   544
    } else if (gst_structure_has_name (structure, "video/x-msmpeg")) {
hgs
parents:
diff changeset
   545
      gint msmpegversion;
hgs
parents:
diff changeset
   546
hgs
parents:
diff changeset
   547
      gst_structure_get_int (structure, "msmpegversion", &msmpegversion);
hgs
parents:
diff changeset
   548
      switch (msmpegversion) {
hgs
parents:
diff changeset
   549
        case 41:
hgs
parents:
diff changeset
   550
          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'G', '4');
hgs
parents:
diff changeset
   551
          break;
hgs
parents:
diff changeset
   552
        case 42:
hgs
parents:
diff changeset
   553
          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '2');
hgs
parents:
diff changeset
   554
          break;
hgs
parents:
diff changeset
   555
        case 43:
hgs
parents:
diff changeset
   556
          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', '4', '3');
hgs
parents:
diff changeset
   557
          break;
hgs
parents:
diff changeset
   558
        default:
hgs
parents:
diff changeset
   559
          GST_INFO ("unhandled msmpegversion : %d, fall back to fourcc=MPEG",
hgs
parents:
diff changeset
   560
              msmpegversion);
hgs
parents:
diff changeset
   561
          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'E', 'G');
hgs
parents:
diff changeset
   562
          break;
hgs
parents:
diff changeset
   563
      }
hgs
parents:
diff changeset
   564
    } else if (!strcmp (mimetype, "video/x-dv")) {
hgs
parents:
diff changeset
   565
      avipad->vids.compression = GST_MAKE_FOURCC ('D', 'V', 'S', 'D');
hgs
parents:
diff changeset
   566
    } else if (!strcmp (mimetype, "video/x-h263")) {
hgs
parents:
diff changeset
   567
      avipad->vids.compression = GST_MAKE_FOURCC ('H', '2', '6', '3');
hgs
parents:
diff changeset
   568
    } else if (!strcmp (mimetype, "video/x-h264")) {
hgs
parents:
diff changeset
   569
      avipad->vids.compression = GST_MAKE_FOURCC ('H', '2', '6', '4');
hgs
parents:
diff changeset
   570
    } else if (!strcmp (mimetype, "video/mpeg")) {
hgs
parents:
diff changeset
   571
      gint mpegversion;
hgs
parents:
diff changeset
   572
hgs
parents:
diff changeset
   573
      gst_structure_get_int (structure, "mpegversion", &mpegversion);
hgs
parents:
diff changeset
   574
hgs
parents:
diff changeset
   575
      switch (mpegversion) {
hgs
parents:
diff changeset
   576
        case 2:
hgs
parents:
diff changeset
   577
          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'G', '2');
hgs
parents:
diff changeset
   578
          break;
hgs
parents:
diff changeset
   579
        case 4:
hgs
parents:
diff changeset
   580
          /* mplayer/ffmpeg might not work with DIVX, but with FMP4 */
hgs
parents:
diff changeset
   581
          avipad->vids.compression = GST_MAKE_FOURCC ('D', 'I', 'V', 'X');
hgs
parents:
diff changeset
   582
          break;
hgs
parents:
diff changeset
   583
        default:
hgs
parents:
diff changeset
   584
          GST_INFO ("unhandled mpegversion : %d, fall back to fourcc=MPEG",
hgs
parents:
diff changeset
   585
              mpegversion);
hgs
parents:
diff changeset
   586
          avipad->vids.compression = GST_MAKE_FOURCC ('M', 'P', 'E', 'G');
hgs
parents:
diff changeset
   587
          break;
hgs
parents:
diff changeset
   588
      }
hgs
parents:
diff changeset
   589
    } else if (!strcmp (mimetype, "video/x-dirac")) {
hgs
parents:
diff changeset
   590
      avipad->vids.compression = GST_MAKE_FOURCC ('d', 'r', 'a', 'c');
hgs
parents:
diff changeset
   591
    } else if (!strcmp (mimetype, "video/x-wmv")) {
hgs
parents:
diff changeset
   592
      gint wmvversion;
hgs
parents:
diff changeset
   593
hgs
parents:
diff changeset
   594
      if (gst_structure_get_int (structure, "wmvversion", &wmvversion)) {
hgs
parents:
diff changeset
   595
        switch (wmvversion) {
hgs
parents:
diff changeset
   596
          case 1:
hgs
parents:
diff changeset
   597
            avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '1');
hgs
parents:
diff changeset
   598
            break;
hgs
parents:
diff changeset
   599
          case 2:
hgs
parents:
diff changeset
   600
            avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '2');
hgs
parents:
diff changeset
   601
            break;
hgs
parents:
diff changeset
   602
          case 3:
hgs
parents:
diff changeset
   603
            avipad->vids.compression = GST_MAKE_FOURCC ('W', 'M', 'V', '3');
hgs
parents:
diff changeset
   604
          default:
hgs
parents:
diff changeset
   605
            break;
hgs
parents:
diff changeset
   606
        }
hgs
parents:
diff changeset
   607
      }
hgs
parents:
diff changeset
   608
    }
hgs
parents:
diff changeset
   609
hgs
parents:
diff changeset
   610
    if (!avipad->vids.compression)
hgs
parents:
diff changeset
   611
      goto refuse_caps;
hgs
parents:
diff changeset
   612
  }
hgs
parents:
diff changeset
   613
hgs
parents:
diff changeset
   614
  avipad->parent.hdr.fcc_handler = avipad->vids.compression;
hgs
parents:
diff changeset
   615
  avipad->vids.image_size = avipad->vids.height * avipad->vids.width;
hgs
parents:
diff changeset
   616
  /* hm, maybe why avi only handles one stream well ... */
hgs
parents:
diff changeset
   617
  avimux->avi_hdr.width = avipad->vids.width;
hgs
parents:
diff changeset
   618
  avimux->avi_hdr.height = avipad->vids.height;
hgs
parents:
diff changeset
   619
  avimux->avi_hdr.us_frame = 1000000. * avipad->parent.hdr.scale /
hgs
parents:
diff changeset
   620
      avipad->parent.hdr.rate;
hgs
parents:
diff changeset
   621
hgs
parents:
diff changeset
   622
  gst_object_unref (avimux);
hgs
parents:
diff changeset
   623
  return TRUE;
hgs
parents:
diff changeset
   624
hgs
parents:
diff changeset
   625
refuse_caps:
hgs
parents:
diff changeset
   626
  {
hgs
parents:
diff changeset
   627
    GST_WARNING_OBJECT (avimux, "refused caps %" GST_PTR_FORMAT, vscaps);
hgs
parents:
diff changeset
   628
    gst_object_unref (avimux);
hgs
parents:
diff changeset
   629
    return FALSE;
hgs
parents:
diff changeset
   630
  }
hgs
parents:
diff changeset
   631
}
hgs
parents:
diff changeset
   632
hgs
parents:
diff changeset
   633
static gboolean
hgs
parents:
diff changeset
   634
gst_avi_mux_audsink_set_caps (GstPad * pad, GstCaps * vscaps)
hgs
parents:
diff changeset
   635
{
hgs
parents:
diff changeset
   636
  GstAviMux *avimux;
hgs
parents:
diff changeset
   637
  GstAviAudioPad *avipad;
hgs
parents:
diff changeset
   638
  GstAviCollectData *collect_pad;
hgs
parents:
diff changeset
   639
  GstStructure *structure;
hgs
parents:
diff changeset
   640
  const gchar *mimetype;
hgs
parents:
diff changeset
   641
  const GValue *codec_data;
hgs
parents:
diff changeset
   642
  gint channels, rate;
hgs
parents:
diff changeset
   643
hgs
parents:
diff changeset
   644
  avimux = GST_AVI_MUX (gst_pad_get_parent (pad));
hgs
parents:
diff changeset
   645
hgs
parents:
diff changeset
   646
  /* find stream data */
hgs
parents:
diff changeset
   647
  collect_pad = (GstAviCollectData *) gst_pad_get_element_private (pad);
hgs
parents:
diff changeset
   648
  g_assert (collect_pad);
hgs
parents:
diff changeset
   649
  avipad = (GstAviAudioPad *) collect_pad->avipad;
hgs
parents:
diff changeset
   650
  g_assert (avipad);
hgs
parents:
diff changeset
   651
  g_assert (!avipad->parent.is_video);
hgs
parents:
diff changeset
   652
  g_assert (avipad->parent.hdr.type == GST_MAKE_FOURCC ('a', 'u', 'd', 's'));
hgs
parents:
diff changeset
   653
hgs
parents:
diff changeset
   654
  GST_DEBUG_OBJECT (avimux, "%s:%s, caps=%" GST_PTR_FORMAT,
hgs
parents:
diff changeset
   655
      GST_DEBUG_PAD_NAME (pad), vscaps);
hgs
parents:
diff changeset
   656
hgs
parents:
diff changeset
   657
  structure = gst_caps_get_structure (vscaps, 0);
hgs
parents:
diff changeset
   658
  mimetype = gst_structure_get_name (structure);
hgs
parents:
diff changeset
   659
hgs
parents:
diff changeset
   660
  /* we want these for all */
hgs
parents:
diff changeset
   661
  if (!gst_structure_get_int (structure, "channels", &channels) ||
hgs
parents:
diff changeset
   662
      !gst_structure_get_int (structure, "rate", &rate)) {
hgs
parents:
diff changeset
   663
    goto refuse_caps;
hgs
parents:
diff changeset
   664
  }
hgs
parents:
diff changeset
   665
hgs
parents:
diff changeset
   666
  avipad->auds.channels = channels;
hgs
parents:
diff changeset
   667
  avipad->auds.rate = rate;
hgs
parents:
diff changeset
   668
hgs
parents:
diff changeset
   669
  /* codec initialization data, if any */
hgs
parents:
diff changeset
   670
  codec_data = gst_structure_get_value (structure, "codec_data");
hgs
parents:
diff changeset
   671
  if (codec_data) {
hgs
parents:
diff changeset
   672
    avipad->auds_codec_data = gst_value_get_buffer (codec_data);
hgs
parents:
diff changeset
   673
    gst_buffer_ref (avipad->auds_codec_data);
hgs
parents:
diff changeset
   674
    /* keep global track of size */
hgs
parents:
diff changeset
   675
    avimux->codec_data_size += GST_BUFFER_SIZE (avipad->auds_codec_data);
hgs
parents:
diff changeset
   676
  }
hgs
parents:
diff changeset
   677
hgs
parents:
diff changeset
   678
  if (!strcmp (mimetype, "audio/x-raw-int")) {
hgs
parents:
diff changeset
   679
    gint width, depth;
hgs
parents:
diff changeset
   680
    gboolean signedness;
hgs
parents:
diff changeset
   681
hgs
parents:
diff changeset
   682
    avipad->auds.format = GST_RIFF_WAVE_FORMAT_PCM;
hgs
parents:
diff changeset
   683
hgs
parents:
diff changeset
   684
    if (!gst_structure_get_int (structure, "width", &width) ||
hgs
parents:
diff changeset
   685
        !gst_structure_get_int (structure, "depth", &depth) ||
hgs
parents:
diff changeset
   686
        !gst_structure_get_boolean (structure, "signed", &signedness)) {
hgs
parents:
diff changeset
   687
      GST_DEBUG_OBJECT (avimux,
hgs
parents:
diff changeset
   688
          "broken caps, width/depth/signed field missing");
hgs
parents:
diff changeset
   689
      goto refuse_caps;
hgs
parents:
diff changeset
   690
    }
hgs
parents:
diff changeset
   691
hgs
parents:
diff changeset
   692
    /* no clear place to put different values for these while keeping to spec */
hgs
parents:
diff changeset
   693
    if (width != depth) {
hgs
parents:
diff changeset
   694
      GST_DEBUG_OBJECT (avimux, "width must be same as depth!");
hgs
parents:
diff changeset
   695
      goto refuse_caps;
hgs
parents:
diff changeset
   696
    }
hgs
parents:
diff changeset
   697
hgs
parents:
diff changeset
   698
    /* because that's the way the caps will be recreated from riff data */
hgs
parents:
diff changeset
   699
    if ((width == 8 && signedness) || (width == 16 && !signedness)) {
hgs
parents:
diff changeset
   700
      GST_DEBUG_OBJECT (avimux,
hgs
parents:
diff changeset
   701
          "8-bit PCM must be unsigned, 16-bit PCM signed");
hgs
parents:
diff changeset
   702
      goto refuse_caps;
hgs
parents:
diff changeset
   703
    }
hgs
parents:
diff changeset
   704
hgs
parents:
diff changeset
   705
    avipad->auds.blockalign = width;
hgs
parents:
diff changeset
   706
    avipad->auds.size = (width == 8) ? 8 : depth;
hgs
parents:
diff changeset
   707
hgs
parents:
diff changeset
   708
    /* set some more info straight */
hgs
parents:
diff changeset
   709
    avipad->auds.blockalign /= 8;
hgs
parents:
diff changeset
   710
    avipad->auds.blockalign *= avipad->auds.channels;
hgs
parents:
diff changeset
   711
    avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
hgs
parents:
diff changeset
   712
  } else {
hgs
parents:
diff changeset
   713
    avipad->auds.format = 0;
hgs
parents:
diff changeset
   714
    /* set some defaults */
hgs
parents:
diff changeset
   715
    avipad->auds.blockalign = 1;
hgs
parents:
diff changeset
   716
    avipad->auds.av_bps = 0;
hgs
parents:
diff changeset
   717
    avipad->auds.size = 16;
hgs
parents:
diff changeset
   718
hgs
parents:
diff changeset
   719
    if (!strcmp (mimetype, "audio/mpeg")) {
hgs
parents:
diff changeset
   720
      gint mpegversion;
hgs
parents:
diff changeset
   721
hgs
parents:
diff changeset
   722
      gst_structure_get_int (structure, "mpegversion", &mpegversion);
hgs
parents:
diff changeset
   723
      switch (mpegversion) {
hgs
parents:
diff changeset
   724
        case 1:{
hgs
parents:
diff changeset
   725
          gint layer = 3;
hgs
parents:
diff changeset
   726
hgs
parents:
diff changeset
   727
          gst_structure_get_int (structure, "layer", &layer);
hgs
parents:
diff changeset
   728
          switch (layer) {
hgs
parents:
diff changeset
   729
            case 3:
hgs
parents:
diff changeset
   730
              avipad->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL3;
hgs
parents:
diff changeset
   731
              break;
hgs
parents:
diff changeset
   732
            case 1:
hgs
parents:
diff changeset
   733
            case 2:
hgs
parents:
diff changeset
   734
              avipad->auds.format = GST_RIFF_WAVE_FORMAT_MPEGL12;
hgs
parents:
diff changeset
   735
              break;
hgs
parents:
diff changeset
   736
          }
hgs
parents:
diff changeset
   737
          break;
hgs
parents:
diff changeset
   738
        }
hgs
parents:
diff changeset
   739
        case 4:
hgs
parents:
diff changeset
   740
          GST_WARNING ("AAC");
hgs
parents:
diff changeset
   741
          avipad->auds.format = GST_RIFF_WAVE_FORMAT_AAC;
hgs
parents:
diff changeset
   742
          break;
hgs
parents:
diff changeset
   743
      }
hgs
parents:
diff changeset
   744
    } else if (!strcmp (mimetype, "audio/x-vorbis")) {
hgs
parents:
diff changeset
   745
      avipad->auds.format = GST_RIFF_WAVE_FORMAT_VORBIS3;
hgs
parents:
diff changeset
   746
    } else if (!strcmp (mimetype, "audio/x-ac3")) {
hgs
parents:
diff changeset
   747
      avipad->auds.format = GST_RIFF_WAVE_FORMAT_A52;
hgs
parents:
diff changeset
   748
    } else if (!strcmp (mimetype, "audio/x-alaw")) {
hgs
parents:
diff changeset
   749
      avipad->auds.format = GST_RIFF_WAVE_FORMAT_ALAW;
hgs
parents:
diff changeset
   750
      avipad->auds.size = 8;
hgs
parents:
diff changeset
   751
      avipad->auds.blockalign = avipad->auds.channels;
hgs
parents:
diff changeset
   752
      avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
hgs
parents:
diff changeset
   753
    } else if (!strcmp (mimetype, "audio/x-mulaw")) {
hgs
parents:
diff changeset
   754
      avipad->auds.format = GST_RIFF_WAVE_FORMAT_MULAW;
hgs
parents:
diff changeset
   755
      avipad->auds.size = 8;
hgs
parents:
diff changeset
   756
      avipad->auds.blockalign = avipad->auds.channels;
hgs
parents:
diff changeset
   757
      avipad->auds.av_bps = avipad->auds.blockalign * avipad->auds.rate;
hgs
parents:
diff changeset
   758
    } else if (!strcmp (mimetype, "audio/x-wma")) {
hgs
parents:
diff changeset
   759
      gint version;
hgs
parents:
diff changeset
   760
      gint bitrate;
hgs
parents:
diff changeset
   761
      gint block_align;
hgs
parents:
diff changeset
   762
hgs
parents:
diff changeset
   763
      if (gst_structure_get_int (structure, "wmaversion", &version)) {
hgs
parents:
diff changeset
   764
        switch (version) {
hgs
parents:
diff changeset
   765
          case 1:
hgs
parents:
diff changeset
   766
            avipad->auds.format = GST_RIFF_WAVE_FORMAT_WMAV1;
hgs
parents:
diff changeset
   767
            break;
hgs
parents:
diff changeset
   768
          case 2:
hgs
parents:
diff changeset
   769
            avipad->auds.format = GST_RIFF_WAVE_FORMAT_WMAV2;
hgs
parents:
diff changeset
   770
            break;
hgs
parents:
diff changeset
   771
          default:
hgs
parents:
diff changeset
   772
            break;
hgs
parents:
diff changeset
   773
        }
hgs
parents:
diff changeset
   774
      }
hgs
parents:
diff changeset
   775
hgs
parents:
diff changeset
   776
      if (avipad->auds.format != 0) {
hgs
parents:
diff changeset
   777
        if (gst_structure_get_int (structure, "block_align", &block_align)) {
hgs
parents:
diff changeset
   778
          avipad->auds.blockalign = block_align;
hgs
parents:
diff changeset
   779
        }
hgs
parents:
diff changeset
   780
        if (gst_structure_get_int (structure, "bitrate", &bitrate)) {
hgs
parents:
diff changeset
   781
          avipad->auds.av_bps = bitrate / 8;
hgs
parents:
diff changeset
   782
        }
hgs
parents:
diff changeset
   783
      }
hgs
parents:
diff changeset
   784
    }
hgs
parents:
diff changeset
   785
  }
hgs
parents:
diff changeset
   786
hgs
parents:
diff changeset
   787
  if (!avipad->auds.format)
hgs
parents:
diff changeset
   788
    goto refuse_caps;
hgs
parents:
diff changeset
   789
hgs
parents:
diff changeset
   790
  /* by spec, hdr.rate is av_bps related, is calculated that way in stop_file,
hgs
parents:
diff changeset
   791
   * and reduces to sample rate in PCM like cases */
hgs
parents:
diff changeset
   792
  avipad->parent.hdr.rate = avipad->auds.av_bps / avipad->auds.blockalign;
hgs
parents:
diff changeset
   793
  avipad->parent.hdr.samplesize = avipad->auds.blockalign;
hgs
parents:
diff changeset
   794
  avipad->parent.hdr.scale = 1;
hgs
parents:
diff changeset
   795
hgs
parents:
diff changeset
   796
  gst_object_unref (avimux);
hgs
parents:
diff changeset
   797
  return TRUE;
hgs
parents:
diff changeset
   798
hgs
parents:
diff changeset
   799
refuse_caps:
hgs
parents:
diff changeset
   800
  {
hgs
parents:
diff changeset
   801
    GST_WARNING_OBJECT (avimux, "refused caps %" GST_PTR_FORMAT, vscaps);
hgs
parents:
diff changeset
   802
    gst_object_unref (avimux);
hgs
parents:
diff changeset
   803
    return FALSE;
hgs
parents:
diff changeset
   804
  }
hgs
parents:
diff changeset
   805
}
hgs
parents:
diff changeset
   806
hgs
parents:
diff changeset
   807
hgs
parents:
diff changeset
   808
static GstPad *
hgs
parents:
diff changeset
   809
gst_avi_mux_request_new_pad (GstElement * element,
hgs
parents:
diff changeset
   810
    GstPadTemplate * templ, const gchar * req_name)
hgs
parents:
diff changeset
   811
{
hgs
parents:
diff changeset
   812
  GstAviMux *avimux;
hgs
parents:
diff changeset
   813
  GstPad *newpad;
hgs
parents:
diff changeset
   814
  GstAviPad *avipad;
hgs
parents:
diff changeset
   815
  GstElementClass *klass;
hgs
parents:
diff changeset
   816
hgs
parents:
diff changeset
   817
  g_return_val_if_fail (templ != NULL, NULL);
hgs
parents:
diff changeset
   818
hgs
parents:
diff changeset
   819
  if (templ->direction != GST_PAD_SINK)
hgs
parents:
diff changeset
   820
    goto wrong_direction;
hgs
parents:
diff changeset
   821
hgs
parents:
diff changeset
   822
  g_return_val_if_fail (GST_IS_AVI_MUX (element), NULL);
hgs
parents:
diff changeset
   823
  avimux = GST_AVI_MUX (element);
hgs
parents:
diff changeset
   824
hgs
parents:
diff changeset
   825
  if (!avimux->write_header)
hgs
parents:
diff changeset
   826
    goto too_late;
hgs
parents:
diff changeset
   827
hgs
parents:
diff changeset
   828
  klass = GST_ELEMENT_GET_CLASS (element);
hgs
parents:
diff changeset
   829
hgs
parents:
diff changeset
   830
  if (templ == gst_element_class_get_pad_template (klass, "audio_%d")) {
hgs
parents:
diff changeset
   831
    gchar *name;
hgs
parents:
diff changeset
   832
hgs
parents:
diff changeset
   833
    /* setup pad */
hgs
parents:
diff changeset
   834
    name = g_strdup_printf ("audio_%02d", avimux->audio_pads);
hgs
parents:
diff changeset
   835
    GST_DEBUG_OBJECT (avimux, "adding new pad: %s", name);
hgs
parents:
diff changeset
   836
    newpad = gst_pad_new_from_template (templ, name);
hgs
parents:
diff changeset
   837
    g_free (name);
hgs
parents:
diff changeset
   838
    gst_pad_set_setcaps_function (newpad,
hgs
parents:
diff changeset
   839
        GST_DEBUG_FUNCPTR (gst_avi_mux_audsink_set_caps));
hgs
parents:
diff changeset
   840
hgs
parents:
diff changeset
   841
    /* init pad specific data */
hgs
parents:
diff changeset
   842
    avipad = g_malloc0 (sizeof (GstAviAudioPad));
hgs
parents:
diff changeset
   843
    avipad->is_video = FALSE;
hgs
parents:
diff changeset
   844
    avipad->hdr.type = GST_MAKE_FOURCC ('a', 'u', 'd', 's');
hgs
parents:
diff changeset
   845
    avimux->audio_pads++;
hgs
parents:
diff changeset
   846
    /* audio goes last */
hgs
parents:
diff changeset
   847
    avimux->sinkpads = g_slist_append (avimux->sinkpads, avipad);
hgs
parents:
diff changeset
   848
  } else if (templ == gst_element_class_get_pad_template (klass, "video_%d")) {
hgs
parents:
diff changeset
   849
    /* though streams are pretty generic and relatively self-contained,
hgs
parents:
diff changeset
   850
     * some video info goes in a single avi header -and therefore mux struct-
hgs
parents:
diff changeset
   851
     * so video restricted to one stream */
hgs
parents:
diff changeset
   852
    if (avimux->video_pads > 0)
hgs
parents:
diff changeset
   853
      return NULL;
hgs
parents:
diff changeset
   854
    /* setup pad */
hgs
parents:
diff changeset
   855
    GST_DEBUG_OBJECT (avimux, "adding new pad: video_00");
hgs
parents:
diff changeset
   856
    newpad = gst_pad_new_from_template (templ, "video_00");
hgs
parents:
diff changeset
   857
    gst_pad_set_setcaps_function (newpad,
hgs
parents:
diff changeset
   858
        GST_DEBUG_FUNCPTR (gst_avi_mux_vidsink_set_caps));
hgs
parents:
diff changeset
   859
    avipad = g_malloc0 (sizeof (GstAviVideoPad));
hgs
parents:
diff changeset
   860
hgs
parents:
diff changeset
   861
    /* init pad specific data */
hgs
parents:
diff changeset
   862
    avipad->is_video = TRUE;
hgs
parents:
diff changeset
   863
    avipad->hdr.type = GST_MAKE_FOURCC ('v', 'i', 'd', 's');
hgs
parents:
diff changeset
   864
    avimux->video_pads++;
hgs
parents:
diff changeset
   865
    /* video goes first */
hgs
parents:
diff changeset
   866
    avimux->sinkpads = g_slist_prepend (avimux->sinkpads, avipad);
hgs
parents:
diff changeset
   867
  } else
hgs
parents:
diff changeset
   868
    goto wrong_template;
hgs
parents:
diff changeset
   869
hgs
parents:
diff changeset
   870
  avipad->collect = gst_collect_pads_add_pad (avimux->collect,
hgs
parents:
diff changeset
   871
      newpad, sizeof (GstAviCollectData));
hgs
parents:
diff changeset
   872
  ((GstAviCollectData *) (avipad->collect))->avipad = avipad;
hgs
parents:
diff changeset
   873
  /* FIXME: hacked way to override/extend the event function of
hgs
parents:
diff changeset
   874
   * GstCollectPads; because it sets its own event function giving the
hgs
parents:
diff changeset
   875
   * element no access to events */
hgs
parents:
diff changeset
   876
  avimux->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad);
hgs
parents:
diff changeset
   877
  gst_pad_set_event_function (newpad,
hgs
parents:
diff changeset
   878
      GST_DEBUG_FUNCPTR (gst_avi_mux_handle_event));
hgs
parents:
diff changeset
   879
hgs
parents:
diff changeset
   880
  gst_element_add_pad (element, newpad);
hgs
parents:
diff changeset
   881
hgs
parents:
diff changeset
   882
  return newpad;
hgs
parents:
diff changeset
   883
hgs
parents:
diff changeset
   884
  /* ERRORS */
hgs
parents:
diff changeset
   885
wrong_direction:
hgs
parents:
diff changeset
   886
  {
hgs
parents:
diff changeset
   887
    g_warning ("avimux: request pad that is not a SINK pad\n");
hgs
parents:
diff changeset
   888
    return NULL;
hgs
parents:
diff changeset
   889
  }
hgs
parents:
diff changeset
   890
too_late:
hgs
parents:
diff changeset
   891
  {
hgs
parents:
diff changeset
   892
    g_warning ("avimux: request pad cannot be added after streaming started\n");
hgs
parents:
diff changeset
   893
    return NULL;
hgs
parents:
diff changeset
   894
  }
hgs
parents:
diff changeset
   895
wrong_template:
hgs
parents:
diff changeset
   896
  {
hgs
parents:
diff changeset
   897
    g_warning ("avimuxx: this is not our template!\n");
hgs
parents:
diff changeset
   898
    return NULL;
hgs
parents:
diff changeset
   899
  }
hgs
parents:
diff changeset
   900
}
hgs
parents:
diff changeset
   901
hgs
parents:
diff changeset
   902
static void
hgs
parents:
diff changeset
   903
gst_avi_mux_release_pad (GstElement * element, GstPad * pad)
hgs
parents:
diff changeset
   904
{
hgs
parents:
diff changeset
   905
  GstAviMux *avimux = GST_AVI_MUX (element);
hgs
parents:
diff changeset
   906
  GSList *node;
hgs
parents:
diff changeset
   907
hgs
parents:
diff changeset
   908
  node = avimux->sinkpads;
hgs
parents:
diff changeset
   909
  while (node) {
hgs
parents:
diff changeset
   910
    GstAviPad *avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
   911
hgs
parents:
diff changeset
   912
    if (avipad->collect->pad == pad) {
hgs
parents:
diff changeset
   913
      /* pad count should not be adjusted,
hgs
parents:
diff changeset
   914
       * as it also represent number of streams present */
hgs
parents:
diff changeset
   915
      avipad->collect = NULL;
hgs
parents:
diff changeset
   916
      GST_DEBUG_OBJECT (avimux, "removed pad '%s'", GST_PAD_NAME (pad));
hgs
parents:
diff changeset
   917
      gst_collect_pads_remove_pad (avimux->collect, pad);
hgs
parents:
diff changeset
   918
      gst_element_remove_pad (element, pad);
hgs
parents:
diff changeset
   919
      /* if not started yet, we can remove any sign this pad ever existed */
hgs
parents:
diff changeset
   920
      /* in this case _start will take care of the real pad count */
hgs
parents:
diff changeset
   921
      if (avimux->write_header) {
hgs
parents:
diff changeset
   922
        avimux->sinkpads = g_slist_remove (avimux->sinkpads, avipad);
hgs
parents:
diff changeset
   923
        gst_avi_mux_pad_reset (avipad, TRUE);
hgs
parents:
diff changeset
   924
        g_free (avipad);
hgs
parents:
diff changeset
   925
      }
hgs
parents:
diff changeset
   926
      return;
hgs
parents:
diff changeset
   927
    }
hgs
parents:
diff changeset
   928
hgs
parents:
diff changeset
   929
    node = node->next;
hgs
parents:
diff changeset
   930
  }
hgs
parents:
diff changeset
   931
hgs
parents:
diff changeset
   932
  g_warning ("Unknown pad %s", GST_PAD_NAME (pad));
hgs
parents:
diff changeset
   933
}
hgs
parents:
diff changeset
   934
hgs
parents:
diff changeset
   935
/* maybe some of these functions should be moved to riff.h? */
hgs
parents:
diff changeset
   936
hgs
parents:
diff changeset
   937
/* DISCLAIMER: this function is fairly ugly. So be it (i.e. it makes the rest easier)
hgs
parents:
diff changeset
   938
 * so is this struct */
hgs
parents:
diff changeset
   939
hgs
parents:
diff changeset
   940
typedef struct _GstMarkedBuffer
hgs
parents:
diff changeset
   941
{
hgs
parents:
diff changeset
   942
  guint *highmark;
hgs
parents:
diff changeset
   943
  GstBuffer *buffer;
hgs
parents:
diff changeset
   944
} GstMarkedBuffer;
hgs
parents:
diff changeset
   945
hgs
parents:
diff changeset
   946
static void
hgs
parents:
diff changeset
   947
gst_avi_mux_write_tag (const GstTagList * list, const gchar * tag,
hgs
parents:
diff changeset
   948
    gpointer data)
hgs
parents:
diff changeset
   949
{
hgs
parents:
diff changeset
   950
  const struct
hgs
parents:
diff changeset
   951
  {
hgs
parents:
diff changeset
   952
    guint32 fcc;
hgs
parents:
diff changeset
   953
    gchar *tag;
hgs
parents:
diff changeset
   954
  } rifftags[] = {
hgs
parents:
diff changeset
   955
    {
hgs
parents:
diff changeset
   956
    GST_RIFF_INFO_IARL, GST_TAG_LOCATION}, {
hgs
parents:
diff changeset
   957
    GST_RIFF_INFO_IART, GST_TAG_ARTIST}, {
hgs
parents:
diff changeset
   958
    GST_RIFF_INFO_ICMT, GST_TAG_COMMENT}, {
hgs
parents:
diff changeset
   959
    GST_RIFF_INFO_ICOP, GST_TAG_COPYRIGHT}, {
hgs
parents:
diff changeset
   960
    GST_RIFF_INFO_ICRD, GST_TAG_DATE}, {
hgs
parents:
diff changeset
   961
    GST_RIFF_INFO_IGNR, GST_TAG_GENRE}, {
hgs
parents:
diff changeset
   962
    GST_RIFF_INFO_IKEY, GST_TAG_KEYWORDS}, {
hgs
parents:
diff changeset
   963
    GST_RIFF_INFO_INAM, GST_TAG_TITLE}, {
hgs
parents:
diff changeset
   964
    GST_RIFF_INFO_ISFT, GST_TAG_ENCODER}, {
hgs
parents:
diff changeset
   965
    GST_RIFF_INFO_ISRC, GST_TAG_ISRC}, {
hgs
parents:
diff changeset
   966
    0, NULL}
hgs
parents:
diff changeset
   967
  };
hgs
parents:
diff changeset
   968
  gint n, len, plen;
hgs
parents:
diff changeset
   969
  GstBuffer *buf = ((GstMarkedBuffer *) data)->buffer;
hgs
parents:
diff changeset
   970
  guint *highmark = ((GstMarkedBuffer *) data)->highmark;
hgs
parents:
diff changeset
   971
  guint8 *buffdata = GST_BUFFER_DATA (buf) + *highmark;
hgs
parents:
diff changeset
   972
  gchar *str;
hgs
parents:
diff changeset
   973
hgs
parents:
diff changeset
   974
  for (n = 0; rifftags[n].fcc != 0; n++) {
hgs
parents:
diff changeset
   975
    if (!strcmp (rifftags[n].tag, tag) &&
hgs
parents:
diff changeset
   976
        gst_tag_list_get_string (list, tag, &str) && str) {
hgs
parents:
diff changeset
   977
      len = strlen (str);
hgs
parents:
diff changeset
   978
      plen = len + 1;
hgs
parents:
diff changeset
   979
      if (plen & 1)
hgs
parents:
diff changeset
   980
        plen++;
hgs
parents:
diff changeset
   981
      if (GST_BUFFER_SIZE (buf) >= *highmark + 8 + plen) {
hgs
parents:
diff changeset
   982
        GST_WRITE_UINT32_LE (buffdata, rifftags[n].fcc);
hgs
parents:
diff changeset
   983
        GST_WRITE_UINT32_LE (buffdata + 4, len + 1);
hgs
parents:
diff changeset
   984
        memcpy (buffdata + 8, str, len);
hgs
parents:
diff changeset
   985
        buffdata[8 + len] = 0;
hgs
parents:
diff changeset
   986
        *highmark += 8 + plen;
hgs
parents:
diff changeset
   987
        GST_DEBUG ("writing tag in buffer %p, highmark at %d", buf, *highmark);
hgs
parents:
diff changeset
   988
      }
hgs
parents:
diff changeset
   989
      g_free (str);
hgs
parents:
diff changeset
   990
      break;
hgs
parents:
diff changeset
   991
    }
hgs
parents:
diff changeset
   992
  }
hgs
parents:
diff changeset
   993
}
hgs
parents:
diff changeset
   994
hgs
parents:
diff changeset
   995
#define ODML_SUPERINDEX_SIZE    \
hgs
parents:
diff changeset
   996
    (32 + GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry))
hgs
parents:
diff changeset
   997
hgs
parents:
diff changeset
   998
static GstBuffer *
hgs
parents:
diff changeset
   999
gst_avi_mux_riff_get_avi_header (GstAviMux * avimux)
hgs
parents:
diff changeset
  1000
{
hgs
parents:
diff changeset
  1001
  const GstTagList *tags;
hgs
parents:
diff changeset
  1002
  GstBuffer *buffer;
hgs
parents:
diff changeset
  1003
  guint8 *buffdata;
hgs
parents:
diff changeset
  1004
  guint size = 0;
hgs
parents:
diff changeset
  1005
  guint highmark = 0;
hgs
parents:
diff changeset
  1006
hgs
parents:
diff changeset
  1007
  /* pointer to list size field */
hgs
parents:
diff changeset
  1008
  guint8 *riff_size, *hdrl_size;
hgs
parents:
diff changeset
  1009
  GSList *node;
hgs
parents:
diff changeset
  1010
hgs
parents:
diff changeset
  1011
  GST_DEBUG_OBJECT (avimux, "creating avi header, data_size %u, idx_size %u",
hgs
parents:
diff changeset
  1012
      avimux->data_size, avimux->idx_size);
hgs
parents:
diff changeset
  1013
hgs
parents:
diff changeset
  1014
  if (avimux->tags_snap)
hgs
parents:
diff changeset
  1015
    tags = avimux->tags_snap;
hgs
parents:
diff changeset
  1016
  else {
hgs
parents:
diff changeset
  1017
    /* need to make snapshot of current state of tags to ensure the same set
hgs
parents:
diff changeset
  1018
     * is used next time around during header rewrite at the end */
hgs
parents:
diff changeset
  1019
    tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (avimux));
hgs
parents:
diff changeset
  1020
    if (tags)
hgs
parents:
diff changeset
  1021
      tags = avimux->tags_snap = gst_tag_list_copy (tags);
hgs
parents:
diff changeset
  1022
  }
hgs
parents:
diff changeset
  1023
  if (tags) {
hgs
parents:
diff changeset
  1024
    /* that should be the strlen of all tags + header sizes
hgs
parents:
diff changeset
  1025
     * not all of tags end up in a avi, still this is a good estimate
hgs
parents:
diff changeset
  1026
     */
hgs
parents:
diff changeset
  1027
    gchar *str = gst_structure_to_string (tags);
hgs
parents:
diff changeset
  1028
    size += strlen (str) + 8 * gst_structure_n_fields (tags);
hgs
parents:
diff changeset
  1029
    g_free (str);
hgs
parents:
diff changeset
  1030
  }
hgs
parents:
diff changeset
  1031
hgs
parents:
diff changeset
  1032
  /* allocate the buffer, starting with some wild/safe upper bound */
hgs
parents:
diff changeset
  1033
  size += avimux->codec_data_size + 100 + sizeof (gst_riff_avih)
hgs
parents:
diff changeset
  1034
      + (g_slist_length (avimux->sinkpads) * (100 + sizeof (gst_riff_strh_full)
hgs
parents:
diff changeset
  1035
          + sizeof (gst_riff_strf_vids)
hgs
parents:
diff changeset
  1036
          + sizeof (gst_riff_vprp)
hgs
parents:
diff changeset
  1037
          + sizeof (gst_riff_vprp_video_field_desc) * 2
hgs
parents:
diff changeset
  1038
          + sizeof (gst_riff_strf_auds) + 2 + ODML_SUPERINDEX_SIZE));
hgs
parents:
diff changeset
  1039
  buffer = gst_buffer_new_and_alloc (size);
hgs
parents:
diff changeset
  1040
  buffdata = GST_BUFFER_DATA (buffer);
hgs
parents:
diff changeset
  1041
  highmark = 0;
hgs
parents:
diff changeset
  1042
  GST_DEBUG_OBJECT (avimux, "creating buffer %p, size %d, highmark at 0",
hgs
parents:
diff changeset
  1043
      buffer, GST_BUFFER_SIZE (buffer));
hgs
parents:
diff changeset
  1044
hgs
parents:
diff changeset
  1045
  /* avi header metadata */
hgs
parents:
diff changeset
  1046
  memcpy (buffdata + 0, "RIFF", 4);
hgs
parents:
diff changeset
  1047
  /* fill in RIFF size later */
hgs
parents:
diff changeset
  1048
  riff_size = buffdata + 4;
hgs
parents:
diff changeset
  1049
  memcpy (buffdata + 8, "AVI ", 4);
hgs
parents:
diff changeset
  1050
  memcpy (buffdata + 12, "LIST", 4);
hgs
parents:
diff changeset
  1051
  /* fill in header size later */
hgs
parents:
diff changeset
  1052
  hdrl_size = buffdata + 16;
hgs
parents:
diff changeset
  1053
  memcpy (buffdata + 20, "hdrl", 4);
hgs
parents:
diff changeset
  1054
  memcpy (buffdata + 24, "avih", 4);
hgs
parents:
diff changeset
  1055
  GST_WRITE_UINT32_LE (buffdata + 28, sizeof (gst_riff_avih));
hgs
parents:
diff changeset
  1056
  buffdata += 32;
hgs
parents:
diff changeset
  1057
  highmark += 32;
hgs
parents:
diff changeset
  1058
hgs
parents:
diff changeset
  1059
  /* the AVI header itself */
hgs
parents:
diff changeset
  1060
  GST_WRITE_UINT32_LE (buffdata + 0, avimux->avi_hdr.us_frame);
hgs
parents:
diff changeset
  1061
  GST_WRITE_UINT32_LE (buffdata + 4, avimux->avi_hdr.max_bps);
hgs
parents:
diff changeset
  1062
  GST_WRITE_UINT32_LE (buffdata + 8, avimux->avi_hdr.pad_gran);
hgs
parents:
diff changeset
  1063
  GST_WRITE_UINT32_LE (buffdata + 12, avimux->avi_hdr.flags);
hgs
parents:
diff changeset
  1064
  GST_WRITE_UINT32_LE (buffdata + 16, avimux->avi_hdr.tot_frames);
hgs
parents:
diff changeset
  1065
  GST_WRITE_UINT32_LE (buffdata + 20, avimux->avi_hdr.init_frames);
hgs
parents:
diff changeset
  1066
  GST_WRITE_UINT32_LE (buffdata + 24, avimux->avi_hdr.streams);
hgs
parents:
diff changeset
  1067
  GST_WRITE_UINT32_LE (buffdata + 28, avimux->avi_hdr.bufsize);
hgs
parents:
diff changeset
  1068
  GST_WRITE_UINT32_LE (buffdata + 32, avimux->avi_hdr.width);
hgs
parents:
diff changeset
  1069
  GST_WRITE_UINT32_LE (buffdata + 36, avimux->avi_hdr.height);
hgs
parents:
diff changeset
  1070
  GST_WRITE_UINT32_LE (buffdata + 40, avimux->avi_hdr.scale);
hgs
parents:
diff changeset
  1071
  GST_WRITE_UINT32_LE (buffdata + 44, avimux->avi_hdr.rate);
hgs
parents:
diff changeset
  1072
  GST_WRITE_UINT32_LE (buffdata + 48, avimux->avi_hdr.start);
hgs
parents:
diff changeset
  1073
  GST_WRITE_UINT32_LE (buffdata + 52, avimux->avi_hdr.length);
hgs
parents:
diff changeset
  1074
  buffdata += 56;
hgs
parents:
diff changeset
  1075
  highmark += 56;
hgs
parents:
diff changeset
  1076
hgs
parents:
diff changeset
  1077
  /* stream data */
hgs
parents:
diff changeset
  1078
  node = avimux->sinkpads;
hgs
parents:
diff changeset
  1079
  while (node) {
hgs
parents:
diff changeset
  1080
    GstAviPad *avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
  1081
    GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
hgs
parents:
diff changeset
  1082
    GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
hgs
parents:
diff changeset
  1083
    guint codec_size = 0, strl_size = 0, vprp_size = 0;
hgs
parents:
diff changeset
  1084
hgs
parents:
diff changeset
  1085
    if (avipad->is_video) {
hgs
parents:
diff changeset
  1086
      if (vidpad->vids_codec_data)
hgs
parents:
diff changeset
  1087
        codec_size = GST_BUFFER_SIZE (vidpad->vids_codec_data);
hgs
parents:
diff changeset
  1088
      strl_size = sizeof (gst_riff_strh_full) + sizeof (gst_riff_strf_vids)
hgs
parents:
diff changeset
  1089
          + GST_ROUND_UP_2 (codec_size) + 4 * 5 + ODML_SUPERINDEX_SIZE;
hgs
parents:
diff changeset
  1090
      if (vidpad->vprp.aspect) {
hgs
parents:
diff changeset
  1091
        /* let's be on the safe side */
hgs
parents:
diff changeset
  1092
        vidpad->vprp.fields = MIN (vidpad->vprp.fields,
hgs
parents:
diff changeset
  1093
            GST_RIFF_VPRP_VIDEO_FIELDS);
hgs
parents:
diff changeset
  1094
        vprp_size = G_STRUCT_OFFSET (gst_riff_vprp, field_info)
hgs
parents:
diff changeset
  1095
            + (vidpad->vprp.fields * sizeof (gst_riff_vprp_video_field_desc));
hgs
parents:
diff changeset
  1096
        strl_size += 4 * 2 + vprp_size;
hgs
parents:
diff changeset
  1097
      }
hgs
parents:
diff changeset
  1098
    } else {
hgs
parents:
diff changeset
  1099
      if (audpad->auds_codec_data)
hgs
parents:
diff changeset
  1100
        codec_size = GST_BUFFER_SIZE (audpad->auds_codec_data);
hgs
parents:
diff changeset
  1101
      /* +2 is codec_size field, not part of gst_riff_strf_auds */
hgs
parents:
diff changeset
  1102
      strl_size = sizeof (gst_riff_strh_full) + sizeof (gst_riff_strf_auds) + 2
hgs
parents:
diff changeset
  1103
          + GST_ROUND_UP_2 (codec_size) + 4 * 5 + ODML_SUPERINDEX_SIZE;
hgs
parents:
diff changeset
  1104
    }
hgs
parents:
diff changeset
  1105
hgs
parents:
diff changeset
  1106
    /* stream list metadata */
hgs
parents:
diff changeset
  1107
    memcpy (buffdata + 0, "LIST", 4);
hgs
parents:
diff changeset
  1108
    GST_WRITE_UINT32_LE (buffdata + 4, strl_size);
hgs
parents:
diff changeset
  1109
    memcpy (buffdata + 8, "strl", 4);
hgs
parents:
diff changeset
  1110
    /* generic header */
hgs
parents:
diff changeset
  1111
    memcpy (buffdata + 12, "strh", 4);
hgs
parents:
diff changeset
  1112
    GST_WRITE_UINT32_LE (buffdata + 16, sizeof (gst_riff_strh_full));
hgs
parents:
diff changeset
  1113
    /* the actual header */
hgs
parents:
diff changeset
  1114
    GST_WRITE_UINT32_LE (buffdata + 20, avipad->hdr.type);
hgs
parents:
diff changeset
  1115
    GST_WRITE_UINT32_LE (buffdata + 24, avipad->hdr.fcc_handler);
hgs
parents:
diff changeset
  1116
    GST_WRITE_UINT32_LE (buffdata + 28, avipad->hdr.flags);
hgs
parents:
diff changeset
  1117
    GST_WRITE_UINT32_LE (buffdata + 32, avipad->hdr.priority);
hgs
parents:
diff changeset
  1118
    GST_WRITE_UINT32_LE (buffdata + 36, avipad->hdr.init_frames);
hgs
parents:
diff changeset
  1119
    GST_WRITE_UINT32_LE (buffdata + 40, avipad->hdr.scale);
hgs
parents:
diff changeset
  1120
    GST_WRITE_UINT32_LE (buffdata + 44, avipad->hdr.rate);
hgs
parents:
diff changeset
  1121
    GST_WRITE_UINT32_LE (buffdata + 48, avipad->hdr.start);
hgs
parents:
diff changeset
  1122
    GST_WRITE_UINT32_LE (buffdata + 52, avipad->hdr.length);
hgs
parents:
diff changeset
  1123
    GST_WRITE_UINT32_LE (buffdata + 56, avipad->hdr.bufsize);
hgs
parents:
diff changeset
  1124
    GST_WRITE_UINT32_LE (buffdata + 60, avipad->hdr.quality);
hgs
parents:
diff changeset
  1125
    GST_WRITE_UINT32_LE (buffdata + 64, avipad->hdr.samplesize);
hgs
parents:
diff changeset
  1126
    GST_WRITE_UINT16_LE (buffdata + 68, 0);
hgs
parents:
diff changeset
  1127
    GST_WRITE_UINT16_LE (buffdata + 70, 0);
hgs
parents:
diff changeset
  1128
    GST_WRITE_UINT16_LE (buffdata + 72, 0);
hgs
parents:
diff changeset
  1129
    GST_WRITE_UINT16_LE (buffdata + 74, 0);
hgs
parents:
diff changeset
  1130
    buffdata += 76;
hgs
parents:
diff changeset
  1131
    highmark += 76;
hgs
parents:
diff changeset
  1132
hgs
parents:
diff changeset
  1133
    if (avipad->is_video) {
hgs
parents:
diff changeset
  1134
      /* the video header */
hgs
parents:
diff changeset
  1135
      memcpy (buffdata + 0, "strf", 4);
hgs
parents:
diff changeset
  1136
      GST_WRITE_UINT32_LE (buffdata + 4,
hgs
parents:
diff changeset
  1137
          sizeof (gst_riff_strf_vids) + codec_size);
hgs
parents:
diff changeset
  1138
      /* the actual header */
hgs
parents:
diff changeset
  1139
      GST_WRITE_UINT32_LE (buffdata + 8, vidpad->vids.size + codec_size);
hgs
parents:
diff changeset
  1140
      GST_WRITE_UINT32_LE (buffdata + 12, vidpad->vids.width);
hgs
parents:
diff changeset
  1141
      GST_WRITE_UINT32_LE (buffdata + 16, vidpad->vids.height);
hgs
parents:
diff changeset
  1142
      GST_WRITE_UINT16_LE (buffdata + 20, vidpad->vids.planes);
hgs
parents:
diff changeset
  1143
      GST_WRITE_UINT16_LE (buffdata + 22, vidpad->vids.bit_cnt);
hgs
parents:
diff changeset
  1144
      GST_WRITE_UINT32_LE (buffdata + 24, vidpad->vids.compression);
hgs
parents:
diff changeset
  1145
      GST_WRITE_UINT32_LE (buffdata + 28, vidpad->vids.image_size);
hgs
parents:
diff changeset
  1146
      GST_WRITE_UINT32_LE (buffdata + 32, vidpad->vids.xpels_meter);
hgs
parents:
diff changeset
  1147
      GST_WRITE_UINT32_LE (buffdata + 36, vidpad->vids.ypels_meter);
hgs
parents:
diff changeset
  1148
      GST_WRITE_UINT32_LE (buffdata + 40, vidpad->vids.num_colors);
hgs
parents:
diff changeset
  1149
      GST_WRITE_UINT32_LE (buffdata + 44, vidpad->vids.imp_colors);
hgs
parents:
diff changeset
  1150
      buffdata += 48;
hgs
parents:
diff changeset
  1151
      highmark += 48;
hgs
parents:
diff changeset
  1152
hgs
parents:
diff changeset
  1153
      /* include codec data, if any */
hgs
parents:
diff changeset
  1154
      if (codec_size) {
hgs
parents:
diff changeset
  1155
        memcpy (buffdata, GST_BUFFER_DATA (vidpad->vids_codec_data),
hgs
parents:
diff changeset
  1156
            codec_size);
hgs
parents:
diff changeset
  1157
hgs
parents:
diff changeset
  1158
        buffdata += codec_size;
hgs
parents:
diff changeset
  1159
        highmark += codec_size;
hgs
parents:
diff changeset
  1160
      }
hgs
parents:
diff changeset
  1161
      /* padding */
hgs
parents:
diff changeset
  1162
      if (highmark & 0x1) {
hgs
parents:
diff changeset
  1163
        highmark++;
hgs
parents:
diff changeset
  1164
        buffdata++;
hgs
parents:
diff changeset
  1165
      }
hgs
parents:
diff changeset
  1166
hgs
parents:
diff changeset
  1167
      /* add video property data, mainly for aspect ratio, if any */
hgs
parents:
diff changeset
  1168
      if (vprp_size) {
hgs
parents:
diff changeset
  1169
        gint f;
hgs
parents:
diff changeset
  1170
hgs
parents:
diff changeset
  1171
        /* the vprp header */
hgs
parents:
diff changeset
  1172
        memcpy (buffdata + 0, "vprp", 4);
hgs
parents:
diff changeset
  1173
        GST_WRITE_UINT32_LE (buffdata + 4, vprp_size);
hgs
parents:
diff changeset
  1174
        /* the actual data */
hgs
parents:
diff changeset
  1175
        GST_WRITE_UINT32_LE (buffdata + 8, vidpad->vprp.format_token);
hgs
parents:
diff changeset
  1176
        GST_WRITE_UINT32_LE (buffdata + 12, vidpad->vprp.standard);
hgs
parents:
diff changeset
  1177
        GST_WRITE_UINT32_LE (buffdata + 16, vidpad->vprp.vert_rate);
hgs
parents:
diff changeset
  1178
        GST_WRITE_UINT32_LE (buffdata + 20, vidpad->vprp.hor_t_total);
hgs
parents:
diff changeset
  1179
        GST_WRITE_UINT32_LE (buffdata + 24, vidpad->vprp.vert_lines);
hgs
parents:
diff changeset
  1180
        GST_WRITE_UINT32_LE (buffdata + 28, vidpad->vprp.aspect);
hgs
parents:
diff changeset
  1181
        GST_WRITE_UINT32_LE (buffdata + 32, vidpad->vprp.width);
hgs
parents:
diff changeset
  1182
        GST_WRITE_UINT32_LE (buffdata + 36, vidpad->vprp.height);
hgs
parents:
diff changeset
  1183
        GST_WRITE_UINT32_LE (buffdata + 40, vidpad->vprp.fields);
hgs
parents:
diff changeset
  1184
        buffdata += 44;
hgs
parents:
diff changeset
  1185
        highmark += 44;
hgs
parents:
diff changeset
  1186
        for (f = 0; f < vidpad->vprp.fields; ++f) {
hgs
parents:
diff changeset
  1187
          gst_riff_vprp_video_field_desc *fd;
hgs
parents:
diff changeset
  1188
hgs
parents:
diff changeset
  1189
          fd = &(vidpad->vprp.field_info[f]);
hgs
parents:
diff changeset
  1190
          GST_WRITE_UINT32_LE (buffdata + 0, fd->compressed_bm_height);
hgs
parents:
diff changeset
  1191
          GST_WRITE_UINT32_LE (buffdata + 4, fd->compressed_bm_width);
hgs
parents:
diff changeset
  1192
          GST_WRITE_UINT32_LE (buffdata + 8, fd->valid_bm_height);
hgs
parents:
diff changeset
  1193
          GST_WRITE_UINT32_LE (buffdata + 12, fd->valid_bm_width);
hgs
parents:
diff changeset
  1194
          GST_WRITE_UINT32_LE (buffdata + 16, fd->valid_bm_x_offset);
hgs
parents:
diff changeset
  1195
          GST_WRITE_UINT32_LE (buffdata + 20, fd->valid_bm_y_offset);
hgs
parents:
diff changeset
  1196
          GST_WRITE_UINT32_LE (buffdata + 24, fd->video_x_t_offset);
hgs
parents:
diff changeset
  1197
          GST_WRITE_UINT32_LE (buffdata + 28, fd->video_y_start);
hgs
parents:
diff changeset
  1198
          buffdata += 32;
hgs
parents:
diff changeset
  1199
          highmark += 32;
hgs
parents:
diff changeset
  1200
        }
hgs
parents:
diff changeset
  1201
      }
hgs
parents:
diff changeset
  1202
    } else {
hgs
parents:
diff changeset
  1203
      /* the audio header */
hgs
parents:
diff changeset
  1204
      memcpy (buffdata + 0, "strf", 4);
hgs
parents:
diff changeset
  1205
      GST_WRITE_UINT32_LE (buffdata + 4,
hgs
parents:
diff changeset
  1206
          sizeof (gst_riff_strf_auds) + 2 + codec_size);
hgs
parents:
diff changeset
  1207
      /* the actual header */
hgs
parents:
diff changeset
  1208
      GST_WRITE_UINT16_LE (buffdata + 8, audpad->auds.format);
hgs
parents:
diff changeset
  1209
      GST_WRITE_UINT16_LE (buffdata + 10, audpad->auds.channels);
hgs
parents:
diff changeset
  1210
      GST_WRITE_UINT32_LE (buffdata + 12, audpad->auds.rate);
hgs
parents:
diff changeset
  1211
      GST_WRITE_UINT32_LE (buffdata + 16, audpad->auds.av_bps);
hgs
parents:
diff changeset
  1212
      GST_WRITE_UINT16_LE (buffdata + 20, audpad->auds.blockalign);
hgs
parents:
diff changeset
  1213
      GST_WRITE_UINT16_LE (buffdata + 22, audpad->auds.size);
hgs
parents:
diff changeset
  1214
      GST_WRITE_UINT16_LE (buffdata + 24, codec_size);
hgs
parents:
diff changeset
  1215
      buffdata += 26;
hgs
parents:
diff changeset
  1216
      highmark += 26;
hgs
parents:
diff changeset
  1217
hgs
parents:
diff changeset
  1218
      /* include codec data, if any */
hgs
parents:
diff changeset
  1219
      if (codec_size) {
hgs
parents:
diff changeset
  1220
        memcpy (buffdata, GST_BUFFER_DATA (audpad->auds_codec_data),
hgs
parents:
diff changeset
  1221
            codec_size);
hgs
parents:
diff changeset
  1222
hgs
parents:
diff changeset
  1223
        buffdata += codec_size;
hgs
parents:
diff changeset
  1224
        highmark += codec_size;
hgs
parents:
diff changeset
  1225
      }
hgs
parents:
diff changeset
  1226
      /* padding */
hgs
parents:
diff changeset
  1227
      if (highmark & 0x1) {
hgs
parents:
diff changeset
  1228
        highmark++;
hgs
parents:
diff changeset
  1229
        buffdata++;
hgs
parents:
diff changeset
  1230
      }
hgs
parents:
diff changeset
  1231
    }
hgs
parents:
diff changeset
  1232
hgs
parents:
diff changeset
  1233
    /* odml superindex chunk */
hgs
parents:
diff changeset
  1234
    if (avipad->idx_index > 0)
hgs
parents:
diff changeset
  1235
      memcpy (buffdata, "indx", 4);
hgs
parents:
diff changeset
  1236
    else
hgs
parents:
diff changeset
  1237
      memcpy (buffdata, "JUNK", 4);
hgs
parents:
diff changeset
  1238
    GST_WRITE_UINT32_LE (buffdata + 4, ODML_SUPERINDEX_SIZE - 8);       /* chunk size */
hgs
parents:
diff changeset
  1239
    GST_WRITE_UINT16_LE (buffdata + 8, 4);      /* bytes per entry */
hgs
parents:
diff changeset
  1240
    buffdata[10] = 0;           /* index subtype */
hgs
parents:
diff changeset
  1241
    buffdata[11] = GST_AVI_INDEX_OF_INDEXES;    /* index type */
hgs
parents:
diff changeset
  1242
    GST_WRITE_UINT32_LE (buffdata + 12, avipad->idx_index);     /* entries in use */
hgs
parents:
diff changeset
  1243
    memcpy (buffdata + 16, avipad->tag, 4);     /* stream id */
hgs
parents:
diff changeset
  1244
    GST_WRITE_UINT32_LE (buffdata + 20, 0);     /* reserved */
hgs
parents:
diff changeset
  1245
    GST_WRITE_UINT32_LE (buffdata + 24, 0);     /* reserved */
hgs
parents:
diff changeset
  1246
    GST_WRITE_UINT32_LE (buffdata + 28, 0);     /* reserved */
hgs
parents:
diff changeset
  1247
    memcpy (buffdata + 32, avipad->idx,
hgs
parents:
diff changeset
  1248
        GST_AVI_SUPERINDEX_COUNT * sizeof (gst_avi_superindex_entry));
hgs
parents:
diff changeset
  1249
    buffdata += ODML_SUPERINDEX_SIZE;
hgs
parents:
diff changeset
  1250
    highmark += ODML_SUPERINDEX_SIZE;
hgs
parents:
diff changeset
  1251
hgs
parents:
diff changeset
  1252
    node = node->next;
hgs
parents:
diff changeset
  1253
  }
hgs
parents:
diff changeset
  1254
hgs
parents:
diff changeset
  1255
  if (avimux->video_pads > 0) {
hgs
parents:
diff changeset
  1256
    /* odml header */
hgs
parents:
diff changeset
  1257
    memcpy (buffdata + 0, "LIST", 4);
hgs
parents:
diff changeset
  1258
    GST_WRITE_UINT32_LE (buffdata + 4, sizeof (guint32) + 4 * 3);
hgs
parents:
diff changeset
  1259
    memcpy (buffdata + 8, "odml", 4);
hgs
parents:
diff changeset
  1260
    memcpy (buffdata + 12, "dmlh", 4);
hgs
parents:
diff changeset
  1261
    GST_WRITE_UINT32_LE (buffdata + 16, sizeof (guint32));
hgs
parents:
diff changeset
  1262
    GST_WRITE_UINT32_LE (buffdata + 20, avimux->total_frames);
hgs
parents:
diff changeset
  1263
    buffdata += 24;
hgs
parents:
diff changeset
  1264
    highmark += 24;
hgs
parents:
diff changeset
  1265
  }
hgs
parents:
diff changeset
  1266
hgs
parents:
diff changeset
  1267
  GST_WRITE_UINT32_LE (hdrl_size, (guint32) (buffdata - hdrl_size) - 4);
hgs
parents:
diff changeset
  1268
hgs
parents:
diff changeset
  1269
  /* tags */
hgs
parents:
diff changeset
  1270
  if (tags) {
hgs
parents:
diff changeset
  1271
    guint8 *ptr;
hgs
parents:
diff changeset
  1272
    guint startsize;
hgs
parents:
diff changeset
  1273
    GstMarkedBuffer data ;
hgs
parents:
diff changeset
  1274
    data.highmark = &highmark;
hgs
parents:
diff changeset
  1275
    data.buffer = buffer;
hgs
parents:
diff changeset
  1276
hgs
parents:
diff changeset
  1277
    memcpy (buffdata + 0, "LIST", 4);
hgs
parents:
diff changeset
  1278
    ptr = buffdata + 4;         /* fill in later */
hgs
parents:
diff changeset
  1279
    startsize = highmark + 4;
hgs
parents:
diff changeset
  1280
    memcpy (buffdata + 8, "INFO", 4);
hgs
parents:
diff changeset
  1281
    buffdata += 12;
hgs
parents:
diff changeset
  1282
    highmark += 12;
hgs
parents:
diff changeset
  1283
hgs
parents:
diff changeset
  1284
    /* 12 bytes is needed for data header */
hgs
parents:
diff changeset
  1285
    GST_BUFFER_SIZE (buffer) -= 12;
hgs
parents:
diff changeset
  1286
    gst_tag_list_foreach (tags, gst_avi_mux_write_tag, &data);
hgs
parents:
diff changeset
  1287
    GST_BUFFER_SIZE (buffer) += 12;
hgs
parents:
diff changeset
  1288
    buffdata = GST_BUFFER_DATA (buffer) + highmark;
hgs
parents:
diff changeset
  1289
hgs
parents:
diff changeset
  1290
    /* update list size */
hgs
parents:
diff changeset
  1291
    GST_WRITE_UINT32_LE (ptr, highmark - startsize - 4);
hgs
parents:
diff changeset
  1292
  }
hgs
parents:
diff changeset
  1293
hgs
parents:
diff changeset
  1294
  /* avi data header */
hgs
parents:
diff changeset
  1295
  memcpy (buffdata + 0, "LIST", 4);
hgs
parents:
diff changeset
  1296
  GST_WRITE_UINT32_LE (buffdata + 4, avimux->data_size);
hgs
parents:
diff changeset
  1297
  memcpy (buffdata + 8, "movi", 4);
hgs
parents:
diff changeset
  1298
  buffdata += 12;
hgs
parents:
diff changeset
  1299
  highmark += 12;
hgs
parents:
diff changeset
  1300
hgs
parents:
diff changeset
  1301
  /* finally we can fill in the RIFF size */
hgs
parents:
diff changeset
  1302
  /* note that riff only counts the first avi chunk */
hgs
parents:
diff changeset
  1303
  GST_WRITE_UINT32_LE (riff_size, (guint32) (buffdata - riff_size - 4)  /* header and movi tags */
hgs
parents:
diff changeset
  1304
      +avimux->idx_size + avimux->data_size - 4);       /* movi data and index */
hgs
parents:
diff changeset
  1305
hgs
parents:
diff changeset
  1306
  {                             /* only the part that is filled in actually makes up the header
hgs
parents:
diff changeset
  1307
                                 *  unref the parent as we only need this part from now on */
hgs
parents:
diff changeset
  1308
    GstBuffer *subbuffer = gst_buffer_create_sub (buffer, 0, highmark);
hgs
parents:
diff changeset
  1309
hgs
parents:
diff changeset
  1310
    gst_buffer_unref (buffer);
hgs
parents:
diff changeset
  1311
    return subbuffer;
hgs
parents:
diff changeset
  1312
  }
hgs
parents:
diff changeset
  1313
}
hgs
parents:
diff changeset
  1314
hgs
parents:
diff changeset
  1315
static GstBuffer *
hgs
parents:
diff changeset
  1316
gst_avi_mux_riff_get_avix_header (guint32 datax_size)
hgs
parents:
diff changeset
  1317
{
hgs
parents:
diff changeset
  1318
  GstBuffer *buffer;
hgs
parents:
diff changeset
  1319
  guint8 *buffdata;
hgs
parents:
diff changeset
  1320
hgs
parents:
diff changeset
  1321
  buffer = gst_buffer_new_and_alloc (24);
hgs
parents:
diff changeset
  1322
  buffdata = GST_BUFFER_DATA (buffer);
hgs
parents:
diff changeset
  1323
hgs
parents:
diff changeset
  1324
  memcpy (buffdata + 0, "RIFF", 4);
hgs
parents:
diff changeset
  1325
  GST_WRITE_UINT32_LE (buffdata + 4, datax_size + 3 * 4);
hgs
parents:
diff changeset
  1326
  memcpy (buffdata + 8, "AVIX", 4);
hgs
parents:
diff changeset
  1327
  memcpy (buffdata + 12, "LIST", 4);
hgs
parents:
diff changeset
  1328
  GST_WRITE_UINT32_LE (buffdata + 16, datax_size);
hgs
parents:
diff changeset
  1329
  memcpy (buffdata + 20, "movi", 4);
hgs
parents:
diff changeset
  1330
hgs
parents:
diff changeset
  1331
  return buffer;
hgs
parents:
diff changeset
  1332
}
hgs
parents:
diff changeset
  1333
hgs
parents:
diff changeset
  1334
static inline GstBuffer *
hgs
parents:
diff changeset
  1335
gst_avi_mux_riff_get_header (GstAviPad * avipad, guint32 video_frame_size)
hgs
parents:
diff changeset
  1336
{
hgs
parents:
diff changeset
  1337
  GstBuffer *buffer;
hgs
parents:
diff changeset
  1338
  guint8 *buffdata;
hgs
parents:
diff changeset
  1339
hgs
parents:
diff changeset
  1340
  buffer = gst_buffer_new_and_alloc (8);
hgs
parents:
diff changeset
  1341
  buffdata = GST_BUFFER_DATA (buffer);
hgs
parents:
diff changeset
  1342
  memcpy (buffdata + 0, avipad->tag, 4);
hgs
parents:
diff changeset
  1343
  GST_WRITE_UINT32_LE (buffdata + 4, video_frame_size);
hgs
parents:
diff changeset
  1344
hgs
parents:
diff changeset
  1345
  return buffer;
hgs
parents:
diff changeset
  1346
}
hgs
parents:
diff changeset
  1347
hgs
parents:
diff changeset
  1348
/* write an odml index chunk in the movi list */
hgs
parents:
diff changeset
  1349
static GstFlowReturn
hgs
parents:
diff changeset
  1350
gst_avi_mux_write_avix_index (GstAviMux * avimux, gchar * code,
hgs
parents:
diff changeset
  1351
    gchar * chunk, gst_avi_superindex_entry * super_index,
hgs
parents:
diff changeset
  1352
    gint * super_index_count)
hgs
parents:
diff changeset
  1353
{
hgs
parents:
diff changeset
  1354
  GstFlowReturn res;
hgs
parents:
diff changeset
  1355
  GstBuffer *buffer;
hgs
parents:
diff changeset
  1356
  guint8 *buffdata, *data;
hgs
parents:
diff changeset
  1357
  gst_riff_index_entry *entry;
hgs
parents:
diff changeset
  1358
  gint i;
hgs
parents:
diff changeset
  1359
  guint32 size, entry_count;
hgs
parents:
diff changeset
  1360
hgs
parents:
diff changeset
  1361
  /* allocate the maximum possible */
hgs
parents:
diff changeset
  1362
  buffer = gst_buffer_new_and_alloc (32 + 8 * avimux->idx_index);
hgs
parents:
diff changeset
  1363
  buffdata = GST_BUFFER_DATA (buffer);
hgs
parents:
diff changeset
  1364
hgs
parents:
diff changeset
  1365
  /* general index chunk info */
hgs
parents:
diff changeset
  1366
  memcpy (buffdata + 0, chunk, 4);      /* chunk id */
hgs
parents:
diff changeset
  1367
  GST_WRITE_UINT32_LE (buffdata + 4, 0);        /* chunk size; fill later */
hgs
parents:
diff changeset
  1368
  GST_WRITE_UINT16_LE (buffdata + 8, 2);        /* index entry is 2 words */
hgs
parents:
diff changeset
  1369
  buffdata[10] = 0;             /* index subtype */
hgs
parents:
diff changeset
  1370
  buffdata[11] = GST_AVI_INDEX_OF_CHUNKS;       /* index type: AVI_INDEX_OF_CHUNKS */
hgs
parents:
diff changeset
  1371
  GST_WRITE_UINT32_LE (buffdata + 12, 0);       /* entries in use; fill later */
hgs
parents:
diff changeset
  1372
  memcpy (buffdata + 16, code, 4);      /* stream to which index refers */
hgs
parents:
diff changeset
  1373
  GST_WRITE_UINT64_LE (buffdata + 20, avimux->avix_start);      /* base offset */
hgs
parents:
diff changeset
  1374
  GST_WRITE_UINT32_LE (buffdata + 28, 0);       /* reserved */
hgs
parents:
diff changeset
  1375
  buffdata += 32;
hgs
parents:
diff changeset
  1376
hgs
parents:
diff changeset
  1377
  /* now the actual index entries */
hgs
parents:
diff changeset
  1378
  i = avimux->idx_index;
hgs
parents:
diff changeset
  1379
  entry = avimux->idx;
hgs
parents:
diff changeset
  1380
  while (i > 0) {
hgs
parents:
diff changeset
  1381
    if (memcmp (&entry->id, code, 4) == 0) {
hgs
parents:
diff changeset
  1382
      /* enter relative offset to the data (!) */
hgs
parents:
diff changeset
  1383
      GST_WRITE_UINT32_LE (buffdata, GUINT32_FROM_LE (entry->offset) + 8);
hgs
parents:
diff changeset
  1384
      /* msb is set if not (!) keyframe */
hgs
parents:
diff changeset
  1385
      GST_WRITE_UINT32_LE (buffdata + 4, GUINT32_FROM_LE (entry->size)
hgs
parents:
diff changeset
  1386
          | (GUINT32_FROM_LE (entry->flags)
hgs
parents:
diff changeset
  1387
              & GST_RIFF_IF_KEYFRAME ? 0 : 1U << 31));
hgs
parents:
diff changeset
  1388
      buffdata += 8;
hgs
parents:
diff changeset
  1389
    }
hgs
parents:
diff changeset
  1390
    i--;
hgs
parents:
diff changeset
  1391
    entry++;
hgs
parents:
diff changeset
  1392
  }
hgs
parents:
diff changeset
  1393
hgs
parents:
diff changeset
  1394
  /* ok, now we know the size and no of entries, fill in where needed */
hgs
parents:
diff changeset
  1395
  data = GST_BUFFER_DATA (buffer);
hgs
parents:
diff changeset
  1396
  GST_BUFFER_SIZE (buffer) = size = buffdata - data;
hgs
parents:
diff changeset
  1397
  GST_WRITE_UINT32_LE (data + 4, size - 8);
hgs
parents:
diff changeset
  1398
  entry_count = (size - 32) / 8;
hgs
parents:
diff changeset
  1399
  GST_WRITE_UINT32_LE (data + 12, entry_count);
hgs
parents:
diff changeset
  1400
hgs
parents:
diff changeset
  1401
  /* decorate and send */
hgs
parents:
diff changeset
  1402
  gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1403
  if ((res = gst_pad_push (avimux->srcpad, buffer)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1404
    return res;
hgs
parents:
diff changeset
  1405
hgs
parents:
diff changeset
  1406
  /* keep track of this in superindex (if room) ... */
hgs
parents:
diff changeset
  1407
  if (*super_index_count < GST_AVI_SUPERINDEX_COUNT) {
hgs
parents:
diff changeset
  1408
    i = *super_index_count;
hgs
parents:
diff changeset
  1409
    super_index[i].offset = GUINT64_TO_LE (avimux->total_data);
hgs
parents:
diff changeset
  1410
    super_index[i].size = GUINT32_TO_LE (size);
hgs
parents:
diff changeset
  1411
    super_index[i].duration = GUINT32_TO_LE (entry_count);
hgs
parents:
diff changeset
  1412
    (*super_index_count)++;
hgs
parents:
diff changeset
  1413
  } else
hgs
parents:
diff changeset
  1414
    GST_WARNING_OBJECT (avimux, "No more room in superindex of stream %s",
hgs
parents:
diff changeset
  1415
        code);
hgs
parents:
diff changeset
  1416
hgs
parents:
diff changeset
  1417
  /* ... and in size */
hgs
parents:
diff changeset
  1418
  avimux->total_data += size;
hgs
parents:
diff changeset
  1419
  if (avimux->is_bigfile)
hgs
parents:
diff changeset
  1420
    avimux->datax_size += size;
hgs
parents:
diff changeset
  1421
  else
hgs
parents:
diff changeset
  1422
    avimux->data_size += size;
hgs
parents:
diff changeset
  1423
hgs
parents:
diff changeset
  1424
  return GST_FLOW_OK;
hgs
parents:
diff changeset
  1425
}
hgs
parents:
diff changeset
  1426
hgs
parents:
diff changeset
  1427
/* some other usable functions (thankyou xawtv ;-) ) */
hgs
parents:
diff changeset
  1428
hgs
parents:
diff changeset
  1429
static void
hgs
parents:
diff changeset
  1430
gst_avi_mux_add_index (GstAviMux * avimux, gchar * code, guint32 flags,
hgs
parents:
diff changeset
  1431
    guint32 size)
hgs
parents:
diff changeset
  1432
{
hgs
parents:
diff changeset
  1433
  if (avimux->idx_index == avimux->idx_count) {
hgs
parents:
diff changeset
  1434
    avimux->idx_count += 256;
hgs
parents:
diff changeset
  1435
    avimux->idx =
hgs
parents:
diff changeset
  1436
        g_realloc (avimux->idx,
hgs
parents:
diff changeset
  1437
        avimux->idx_count * sizeof (gst_riff_index_entry));
hgs
parents:
diff changeset
  1438
  }
hgs
parents:
diff changeset
  1439
  memcpy (&(avimux->idx[avimux->idx_index].id), code, 4);
hgs
parents:
diff changeset
  1440
  avimux->idx[avimux->idx_index].flags = GUINT32_TO_LE (flags);
hgs
parents:
diff changeset
  1441
  avimux->idx[avimux->idx_index].offset = GUINT32_TO_LE (avimux->idx_offset);
hgs
parents:
diff changeset
  1442
  avimux->idx[avimux->idx_index].size = GUINT32_TO_LE (size);
hgs
parents:
diff changeset
  1443
  avimux->idx_index++;
hgs
parents:
diff changeset
  1444
}
hgs
parents:
diff changeset
  1445
hgs
parents:
diff changeset
  1446
static GstFlowReturn
hgs
parents:
diff changeset
  1447
gst_avi_mux_write_index (GstAviMux * avimux)
hgs
parents:
diff changeset
  1448
{
hgs
parents:
diff changeset
  1449
  GstFlowReturn res;
hgs
parents:
diff changeset
  1450
  GstBuffer *buffer;
hgs
parents:
diff changeset
  1451
  guint8 *buffdata;
hgs
parents:
diff changeset
  1452
hgs
parents:
diff changeset
  1453
  buffer = gst_buffer_new_and_alloc (8);
hgs
parents:
diff changeset
  1454
  buffdata = GST_BUFFER_DATA (buffer);
hgs
parents:
diff changeset
  1455
  memcpy (buffdata + 0, "idx1", 4);
hgs
parents:
diff changeset
  1456
  GST_WRITE_UINT32_LE (buffdata + 4,
hgs
parents:
diff changeset
  1457
      avimux->idx_index * sizeof (gst_riff_index_entry));
hgs
parents:
diff changeset
  1458
hgs
parents:
diff changeset
  1459
  gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1460
  res = gst_pad_push (avimux->srcpad, buffer);
hgs
parents:
diff changeset
  1461
  if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  1462
    return res;
hgs
parents:
diff changeset
  1463
hgs
parents:
diff changeset
  1464
  buffer = gst_buffer_new ();
hgs
parents:
diff changeset
  1465
  GST_BUFFER_SIZE (buffer) = avimux->idx_index * sizeof (gst_riff_index_entry);
hgs
parents:
diff changeset
  1466
  GST_BUFFER_DATA (buffer) = (guint8 *) avimux->idx;
hgs
parents:
diff changeset
  1467
  GST_BUFFER_MALLOCDATA (buffer) = GST_BUFFER_DATA (buffer);
hgs
parents:
diff changeset
  1468
  avimux->idx = NULL;           /* will be free()'ed by gst_buffer_unref() */
hgs
parents:
diff changeset
  1469
  avimux->total_data += GST_BUFFER_SIZE (buffer) + 8;
hgs
parents:
diff changeset
  1470
hgs
parents:
diff changeset
  1471
  gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1472
  res = gst_pad_push (avimux->srcpad, buffer);
hgs
parents:
diff changeset
  1473
  if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  1474
    return res;
hgs
parents:
diff changeset
  1475
hgs
parents:
diff changeset
  1476
  avimux->idx_size += avimux->idx_index * sizeof (gst_riff_index_entry) + 8;
hgs
parents:
diff changeset
  1477
hgs
parents:
diff changeset
  1478
  /* update header */
hgs
parents:
diff changeset
  1479
  avimux->avi_hdr.flags |= GST_RIFF_AVIH_HASINDEX;
hgs
parents:
diff changeset
  1480
  return GST_FLOW_OK;
hgs
parents:
diff changeset
  1481
}
hgs
parents:
diff changeset
  1482
hgs
parents:
diff changeset
  1483
static GstFlowReturn
hgs
parents:
diff changeset
  1484
gst_avi_mux_bigfile (GstAviMux * avimux, gboolean last)
hgs
parents:
diff changeset
  1485
{
hgs
parents:
diff changeset
  1486
  GstFlowReturn res = GST_FLOW_OK;
hgs
parents:
diff changeset
  1487
  GstBuffer *header;
hgs
parents:
diff changeset
  1488
  GstEvent *event;
hgs
parents:
diff changeset
  1489
  GSList *node;
hgs
parents:
diff changeset
  1490
hgs
parents:
diff changeset
  1491
  /* first some odml standard index chunks in the movi list */
hgs
parents:
diff changeset
  1492
  node = avimux->sinkpads;
hgs
parents:
diff changeset
  1493
  while (node) {
hgs
parents:
diff changeset
  1494
    GstAviPad *avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
  1495
hgs
parents:
diff changeset
  1496
    node = node->next;
hgs
parents:
diff changeset
  1497
hgs
parents:
diff changeset
  1498
    res = gst_avi_mux_write_avix_index (avimux, avipad->tag,
hgs
parents:
diff changeset
  1499
        avipad->idx_tag, avipad->idx, &avipad->idx_index);
hgs
parents:
diff changeset
  1500
    if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  1501
      return res;
hgs
parents:
diff changeset
  1502
  }
hgs
parents:
diff changeset
  1503
hgs
parents:
diff changeset
  1504
  if (avimux->is_bigfile) {
hgs
parents:
diff changeset
  1505
    /* search back */
hgs
parents:
diff changeset
  1506
    event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
hgs
parents:
diff changeset
  1507
        avimux->avix_start, GST_CLOCK_TIME_NONE, avimux->avix_start);
hgs
parents:
diff changeset
  1508
    /* if the event succeeds */
hgs
parents:
diff changeset
  1509
    gst_pad_push_event (avimux->srcpad, event);
hgs
parents:
diff changeset
  1510
hgs
parents:
diff changeset
  1511
    /* rewrite AVIX header */
hgs
parents:
diff changeset
  1512
    header = gst_avi_mux_riff_get_avix_header (avimux->datax_size);
hgs
parents:
diff changeset
  1513
    gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1514
    res = gst_pad_push (avimux->srcpad, header);
hgs
parents:
diff changeset
  1515
hgs
parents:
diff changeset
  1516
    /* go back to current location, at least try */
hgs
parents:
diff changeset
  1517
    event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
hgs
parents:
diff changeset
  1518
        avimux->total_data, GST_CLOCK_TIME_NONE, avimux->total_data);
hgs
parents:
diff changeset
  1519
    gst_pad_push_event (avimux->srcpad, event);
hgs
parents:
diff changeset
  1520
hgs
parents:
diff changeset
  1521
    if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  1522
      return res;
hgs
parents:
diff changeset
  1523
  } else {                      /* write a standard index in the first riff chunk */
hgs
parents:
diff changeset
  1524
    res = gst_avi_mux_write_index (avimux);
hgs
parents:
diff changeset
  1525
    /* the index data/buffer is freed by pushing it */
hgs
parents:
diff changeset
  1526
    avimux->idx_count = 0;
hgs
parents:
diff changeset
  1527
    if (res != GST_FLOW_OK)
hgs
parents:
diff changeset
  1528
      return res;
hgs
parents:
diff changeset
  1529
  }
hgs
parents:
diff changeset
  1530
hgs
parents:
diff changeset
  1531
  avimux->avix_start = avimux->total_data;
hgs
parents:
diff changeset
  1532
hgs
parents:
diff changeset
  1533
  if (last)
hgs
parents:
diff changeset
  1534
    return res;
hgs
parents:
diff changeset
  1535
hgs
parents:
diff changeset
  1536
  avimux->is_bigfile = TRUE;
hgs
parents:
diff changeset
  1537
  avimux->numx_frames = 0;
hgs
parents:
diff changeset
  1538
  avimux->datax_size = 4;       /* movi tag */
hgs
parents:
diff changeset
  1539
  avimux->idx_index = 0;
hgs
parents:
diff changeset
  1540
hgs
parents:
diff changeset
  1541
  header = gst_avi_mux_riff_get_avix_header (0);
hgs
parents:
diff changeset
  1542
  avimux->total_data += GST_BUFFER_SIZE (header);
hgs
parents:
diff changeset
  1543
  /* avix_start is used as base offset for the odml index chunk */
hgs
parents:
diff changeset
  1544
  avimux->idx_offset = avimux->total_data - avimux->avix_start;
hgs
parents:
diff changeset
  1545
  gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1546
  return gst_pad_push (avimux->srcpad, header);
hgs
parents:
diff changeset
  1547
}
hgs
parents:
diff changeset
  1548
hgs
parents:
diff changeset
  1549
/* enough header blabla now, let's go on to actually writing the headers */
hgs
parents:
diff changeset
  1550
hgs
parents:
diff changeset
  1551
static GstFlowReturn
hgs
parents:
diff changeset
  1552
gst_avi_mux_start_file (GstAviMux * avimux)
hgs
parents:
diff changeset
  1553
{
hgs
parents:
diff changeset
  1554
  GstFlowReturn res;
hgs
parents:
diff changeset
  1555
  GstBuffer *header;
hgs
parents:
diff changeset
  1556
  GSList *node;
hgs
parents:
diff changeset
  1557
hgs
parents:
diff changeset
  1558
  avimux->total_data = 0;
hgs
parents:
diff changeset
  1559
  avimux->total_frames = 0;
hgs
parents:
diff changeset
  1560
  avimux->data_size = 4;        /* movi tag */
hgs
parents:
diff changeset
  1561
  avimux->datax_size = 0;
hgs
parents:
diff changeset
  1562
  avimux->num_frames = 0;
hgs
parents:
diff changeset
  1563
  avimux->numx_frames = 0;
hgs
parents:
diff changeset
  1564
  avimux->avix_start = 0;
hgs
parents:
diff changeset
  1565
hgs
parents:
diff changeset
  1566
  avimux->idx_index = 0;
hgs
parents:
diff changeset
  1567
  avimux->idx_offset = 0;       /* see 10 lines below */
hgs
parents:
diff changeset
  1568
  avimux->idx_size = 0;
hgs
parents:
diff changeset
  1569
  avimux->idx_count = 0;
hgs
parents:
diff changeset
  1570
  avimux->idx = NULL;
hgs
parents:
diff changeset
  1571
hgs
parents:
diff changeset
  1572
  /* state */
hgs
parents:
diff changeset
  1573
  avimux->write_header = FALSE;
hgs
parents:
diff changeset
  1574
  avimux->restart = FALSE;
hgs
parents:
diff changeset
  1575
hgs
parents:
diff changeset
  1576
  /* init streams, see what we've got */
hgs
parents:
diff changeset
  1577
  node = avimux->sinkpads;
hgs
parents:
diff changeset
  1578
  avimux->audio_pads = avimux->video_pads = 0;
hgs
parents:
diff changeset
  1579
  while (node) {
hgs
parents:
diff changeset
  1580
    GstAviPad *avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
  1581
hgs
parents:
diff changeset
  1582
    node = node->next;
hgs
parents:
diff changeset
  1583
hgs
parents:
diff changeset
  1584
    if (!avipad->is_video) {
hgs
parents:
diff changeset
  1585
      /* audio stream numbers must start at 1 iff there is a video stream 0;
hgs
parents:
diff changeset
  1586
       * request_pad inserts video pad at head of list, so this test suffices */
hgs
parents:
diff changeset
  1587
      if (avimux->video_pads)
hgs
parents:
diff changeset
  1588
        avimux->audio_pads++;
hgs
parents:
diff changeset
  1589
      avipad->tag = g_strdup_printf ("%02uwb", avimux->audio_pads);
hgs
parents:
diff changeset
  1590
      avipad->idx_tag = g_strdup_printf ("ix%02u", avimux->audio_pads);
hgs
parents:
diff changeset
  1591
      if (!avimux->video_pads)
hgs
parents:
diff changeset
  1592
        avimux->audio_pads++;
hgs
parents:
diff changeset
  1593
    } else {
hgs
parents:
diff changeset
  1594
      avipad->tag = g_strdup_printf ("%02udb", avimux->video_pads);
hgs
parents:
diff changeset
  1595
      avipad->idx_tag = g_strdup_printf ("ix%02u", avimux->video_pads++);
hgs
parents:
diff changeset
  1596
    }
hgs
parents:
diff changeset
  1597
  }
hgs
parents:
diff changeset
  1598
hgs
parents:
diff changeset
  1599
  /* let downstream know we think in BYTES and expect to do seeking later on */
hgs
parents:
diff changeset
  1600
  gst_pad_push_event (avimux->srcpad,
hgs
parents:
diff changeset
  1601
      gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES, 0, -1, 0));
hgs
parents:
diff changeset
  1602
hgs
parents:
diff changeset
  1603
  /* header */
hgs
parents:
diff changeset
  1604
  avimux->avi_hdr.streams = g_slist_length (avimux->sinkpads);
hgs
parents:
diff changeset
  1605
  avimux->is_bigfile = FALSE;
hgs
parents:
diff changeset
  1606
hgs
parents:
diff changeset
  1607
  header = gst_avi_mux_riff_get_avi_header (avimux);
hgs
parents:
diff changeset
  1608
  avimux->total_data += GST_BUFFER_SIZE (header);
hgs
parents:
diff changeset
  1609
hgs
parents:
diff changeset
  1610
  gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1611
  res = gst_pad_push (avimux->srcpad, header);
hgs
parents:
diff changeset
  1612
hgs
parents:
diff changeset
  1613
  avimux->idx_offset = avimux->total_data;
hgs
parents:
diff changeset
  1614
hgs
parents:
diff changeset
  1615
  return res;
hgs
parents:
diff changeset
  1616
}
hgs
parents:
diff changeset
  1617
hgs
parents:
diff changeset
  1618
static GstFlowReturn
hgs
parents:
diff changeset
  1619
gst_avi_mux_stop_file (GstAviMux * avimux)
hgs
parents:
diff changeset
  1620
{
hgs
parents:
diff changeset
  1621
  GstFlowReturn res = GST_FLOW_OK;
hgs
parents:
diff changeset
  1622
  GstEvent *event;
hgs
parents:
diff changeset
  1623
  GstBuffer *header;
hgs
parents:
diff changeset
  1624
  GSList *node;
hgs
parents:
diff changeset
  1625
hgs
parents:
diff changeset
  1626
  /* if bigfile, rewrite header, else write indexes */
hgs
parents:
diff changeset
  1627
  /* don't bail out at once if error, still try to re-write header */
hgs
parents:
diff changeset
  1628
  if (avimux->video_pads > 0) {
hgs
parents:
diff changeset
  1629
    if (avimux->is_bigfile) {
hgs
parents:
diff changeset
  1630
      res = gst_avi_mux_bigfile (avimux, TRUE);
hgs
parents:
diff changeset
  1631
    } else {
hgs
parents:
diff changeset
  1632
      res = gst_avi_mux_write_index (avimux);
hgs
parents:
diff changeset
  1633
    }
hgs
parents:
diff changeset
  1634
  }
hgs
parents:
diff changeset
  1635
hgs
parents:
diff changeset
  1636
  /* we do our best to make it interleaved at least ... */
hgs
parents:
diff changeset
  1637
  if (avimux->audio_pads > 0 && avimux->video_pads > 0)
hgs
parents:
diff changeset
  1638
    avimux->avi_hdr.flags |= GST_RIFF_AVIH_ISINTERLEAVED;
hgs
parents:
diff changeset
  1639
hgs
parents:
diff changeset
  1640
  /* set rate and everything having to do with that */
hgs
parents:
diff changeset
  1641
  avimux->avi_hdr.max_bps = 0;
hgs
parents:
diff changeset
  1642
  node = avimux->sinkpads;
hgs
parents:
diff changeset
  1643
  while (node) {
hgs
parents:
diff changeset
  1644
    GstAviPad *avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
  1645
hgs
parents:
diff changeset
  1646
    node = node->next;
hgs
parents:
diff changeset
  1647
hgs
parents:
diff changeset
  1648
    if (!avipad->is_video) {
hgs
parents:
diff changeset
  1649
      GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
hgs
parents:
diff changeset
  1650
hgs
parents:
diff changeset
  1651
      /* calculate bps if needed */
hgs
parents:
diff changeset
  1652
      if (!audpad->auds.av_bps) {
hgs
parents:
diff changeset
  1653
        if (audpad->audio_time) {
hgs
parents:
diff changeset
  1654
          audpad->auds.av_bps =
hgs
parents:
diff changeset
  1655
              (GST_SECOND * audpad->audio_size) / audpad->audio_time;
hgs
parents:
diff changeset
  1656
          /* round bps to nearest multiple of 8;
hgs
parents:
diff changeset
  1657
           * which is much more likely to be the (cbr) bitrate in use;
hgs
parents:
diff changeset
  1658
           * which in turn results in better timestamp calculation on playback */
hgs
parents:
diff changeset
  1659
          audpad->auds.av_bps = GST_ROUND_UP_8 (audpad->auds.av_bps - 4);
hgs
parents:
diff changeset
  1660
        } else {
hgs
parents:
diff changeset
  1661
          GST_ELEMENT_WARNING (avimux, STREAM, MUX,
hgs
parents:
diff changeset
  1662
              (_("No or invalid input audio, AVI stream will be corrupt.")),
hgs
parents:
diff changeset
  1663
              (NULL));
hgs
parents:
diff changeset
  1664
          audpad->auds.av_bps = 0;
hgs
parents:
diff changeset
  1665
        }
hgs
parents:
diff changeset
  1666
        avipad->hdr.rate = audpad->auds.av_bps * avipad->hdr.scale;
hgs
parents:
diff changeset
  1667
      }
hgs
parents:
diff changeset
  1668
      avimux->avi_hdr.max_bps += audpad->auds.av_bps;
hgs
parents:
diff changeset
  1669
      avipad->hdr.length = (audpad->audio_time * avipad->hdr.rate) / GST_SECOND;
hgs
parents:
diff changeset
  1670
    } else {
hgs
parents:
diff changeset
  1671
      GstAviVideoPad *vidpad = (GstAviVideoPad *) avipad;
hgs
parents:
diff changeset
  1672
hgs
parents:
diff changeset
  1673
      avimux->avi_hdr.max_bps += ((vidpad->vids.bit_cnt + 7) / 8) *
hgs
parents:
diff changeset
  1674
          (1000000. / avimux->avi_hdr.us_frame) * vidpad->vids.image_size;
hgs
parents:
diff changeset
  1675
      avipad->hdr.length = avimux->total_frames;
hgs
parents:
diff changeset
  1676
    }
hgs
parents:
diff changeset
  1677
  }
hgs
parents:
diff changeset
  1678
hgs
parents:
diff changeset
  1679
  /* statistics/total_frames/... */
hgs
parents:
diff changeset
  1680
  avimux->avi_hdr.tot_frames = avimux->num_frames;
hgs
parents:
diff changeset
  1681
hgs
parents:
diff changeset
  1682
  /* seek and rewrite the header */
hgs
parents:
diff changeset
  1683
  header = gst_avi_mux_riff_get_avi_header (avimux);
hgs
parents:
diff changeset
  1684
  event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
hgs
parents:
diff changeset
  1685
      0, GST_CLOCK_TIME_NONE, 0);
hgs
parents:
diff changeset
  1686
  gst_pad_push_event (avimux->srcpad, event);
hgs
parents:
diff changeset
  1687
hgs
parents:
diff changeset
  1688
  gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1689
  /* the first error survives */
hgs
parents:
diff changeset
  1690
  if (res == GST_FLOW_OK)
hgs
parents:
diff changeset
  1691
    res = gst_pad_push (avimux->srcpad, header);
hgs
parents:
diff changeset
  1692
  else
hgs
parents:
diff changeset
  1693
    gst_pad_push (avimux->srcpad, header);
hgs
parents:
diff changeset
  1694
hgs
parents:
diff changeset
  1695
  event = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
hgs
parents:
diff changeset
  1696
      avimux->total_data, GST_CLOCK_TIME_NONE, avimux->total_data);
hgs
parents:
diff changeset
  1697
  gst_pad_push_event (avimux->srcpad, event);
hgs
parents:
diff changeset
  1698
hgs
parents:
diff changeset
  1699
  avimux->write_header = TRUE;
hgs
parents:
diff changeset
  1700
hgs
parents:
diff changeset
  1701
  return res;
hgs
parents:
diff changeset
  1702
}
hgs
parents:
diff changeset
  1703
hgs
parents:
diff changeset
  1704
static GstFlowReturn
hgs
parents:
diff changeset
  1705
gst_avi_mux_restart_file (GstAviMux * avimux)
hgs
parents:
diff changeset
  1706
{
hgs
parents:
diff changeset
  1707
  GstFlowReturn res;
hgs
parents:
diff changeset
  1708
hgs
parents:
diff changeset
  1709
  if ((res = gst_avi_mux_stop_file (avimux)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1710
    return res;
hgs
parents:
diff changeset
  1711
hgs
parents:
diff changeset
  1712
  gst_pad_push_event (avimux->srcpad, gst_event_new_eos ());
hgs
parents:
diff changeset
  1713
hgs
parents:
diff changeset
  1714
  return gst_avi_mux_start_file (avimux);
hgs
parents:
diff changeset
  1715
}
hgs
parents:
diff changeset
  1716
hgs
parents:
diff changeset
  1717
/* handle events (search) */
hgs
parents:
diff changeset
  1718
static gboolean
hgs
parents:
diff changeset
  1719
gst_avi_mux_handle_event (GstPad * pad, GstEvent * event)
hgs
parents:
diff changeset
  1720
{
hgs
parents:
diff changeset
  1721
  GstAviMux *avimux;
hgs
parents:
diff changeset
  1722
  gboolean ret;
hgs
parents:
diff changeset
  1723
hgs
parents:
diff changeset
  1724
  avimux = GST_AVI_MUX (gst_pad_get_parent (pad));
hgs
parents:
diff changeset
  1725
hgs
parents:
diff changeset
  1726
  switch (GST_EVENT_TYPE (event)) {
hgs
parents:
diff changeset
  1727
    case GST_EVENT_TAG:{
hgs
parents:
diff changeset
  1728
      GstTagList *list;
hgs
parents:
diff changeset
  1729
      GstTagSetter *setter = GST_TAG_SETTER (avimux);
hgs
parents:
diff changeset
  1730
      const GstTagMergeMode mode = gst_tag_setter_get_tag_merge_mode (setter);
hgs
parents:
diff changeset
  1731
hgs
parents:
diff changeset
  1732
      gst_event_parse_tag (event, &list);
hgs
parents:
diff changeset
  1733
      gst_tag_setter_merge_tags (setter, list, mode);
hgs
parents:
diff changeset
  1734
      break;
hgs
parents:
diff changeset
  1735
    }
hgs
parents:
diff changeset
  1736
    default:
hgs
parents:
diff changeset
  1737
      break;
hgs
parents:
diff changeset
  1738
  }
hgs
parents:
diff changeset
  1739
hgs
parents:
diff changeset
  1740
  /* now GstCollectPads can take care of the rest, e.g. EOS */
hgs
parents:
diff changeset
  1741
  ret = avimux->collect_event (pad, event);
hgs
parents:
diff changeset
  1742
hgs
parents:
diff changeset
  1743
  gst_object_unref (avimux);
hgs
parents:
diff changeset
  1744
hgs
parents:
diff changeset
  1745
  return ret;
hgs
parents:
diff changeset
  1746
}
hgs
parents:
diff changeset
  1747
hgs
parents:
diff changeset
  1748
/* send extra 'padding' data */
hgs
parents:
diff changeset
  1749
static GstFlowReturn
hgs
parents:
diff changeset
  1750
gst_avi_mux_send_pad_data (GstAviMux * avimux, gulong num_bytes)
hgs
parents:
diff changeset
  1751
{
hgs
parents:
diff changeset
  1752
  GstBuffer *buffer;
hgs
parents:
diff changeset
  1753
hgs
parents:
diff changeset
  1754
  buffer = gst_buffer_new_and_alloc (num_bytes);
hgs
parents:
diff changeset
  1755
  memset (GST_BUFFER_DATA (buffer), 0, num_bytes);
hgs
parents:
diff changeset
  1756
  gst_buffer_set_caps (buffer, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1757
  return gst_pad_push (avimux->srcpad, buffer);
hgs
parents:
diff changeset
  1758
}
hgs
parents:
diff changeset
  1759
hgs
parents:
diff changeset
  1760
/* do buffer */
hgs
parents:
diff changeset
  1761
static GstFlowReturn
hgs
parents:
diff changeset
  1762
gst_avi_mux_do_buffer (GstAviMux * avimux, GstAviPad * avipad)
hgs
parents:
diff changeset
  1763
{
hgs
parents:
diff changeset
  1764
  GstFlowReturn res;
hgs
parents:
diff changeset
  1765
  GstBuffer *data, *header;
hgs
parents:
diff changeset
  1766
  gulong total_size, pad_bytes = 0;
hgs
parents:
diff changeset
  1767
  guint flags;
hgs
parents:
diff changeset
  1768
hgs
parents:
diff changeset
  1769
  data = gst_collect_pads_pop (avimux->collect, avipad->collect);
hgs
parents:
diff changeset
  1770
hgs
parents:
diff changeset
  1771
  if (avimux->restart) {
hgs
parents:
diff changeset
  1772
    if ((res = gst_avi_mux_restart_file (avimux)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1773
      return res;
hgs
parents:
diff changeset
  1774
  }
hgs
parents:
diff changeset
  1775
hgs
parents:
diff changeset
  1776
  /* need to restart or start a next avix chunk ? */
hgs
parents:
diff changeset
  1777
  if ((avimux->is_bigfile ? avimux->datax_size : avimux->data_size) +
hgs
parents:
diff changeset
  1778
      GST_BUFFER_SIZE (data) > 1024 * 1024 * 2000) {
hgs
parents:
diff changeset
  1779
    if (avimux->enable_large_avi) {
hgs
parents:
diff changeset
  1780
      if ((res = gst_avi_mux_bigfile (avimux, FALSE)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1781
        return res;
hgs
parents:
diff changeset
  1782
    } else {
hgs
parents:
diff changeset
  1783
      if ((res = gst_avi_mux_restart_file (avimux)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1784
        return res;
hgs
parents:
diff changeset
  1785
    }
hgs
parents:
diff changeset
  1786
  }
hgs
parents:
diff changeset
  1787
hgs
parents:
diff changeset
  1788
  /* get header and record some stats */
hgs
parents:
diff changeset
  1789
  if (GST_BUFFER_SIZE (data) & 1) {
hgs
parents:
diff changeset
  1790
    pad_bytes = 2 - (GST_BUFFER_SIZE (data) & 1);
hgs
parents:
diff changeset
  1791
  }
hgs
parents:
diff changeset
  1792
  header = gst_avi_mux_riff_get_header (avipad, GST_BUFFER_SIZE (data));
hgs
parents:
diff changeset
  1793
  total_size = GST_BUFFER_SIZE (header) + GST_BUFFER_SIZE (data) + pad_bytes;
hgs
parents:
diff changeset
  1794
hgs
parents:
diff changeset
  1795
  if (avimux->is_bigfile) {
hgs
parents:
diff changeset
  1796
    avimux->datax_size += total_size;
hgs
parents:
diff changeset
  1797
  } else {
hgs
parents:
diff changeset
  1798
    avimux->data_size += total_size;
hgs
parents:
diff changeset
  1799
  }
hgs
parents:
diff changeset
  1800
hgs
parents:
diff changeset
  1801
  if (avipad->is_video) {
hgs
parents:
diff changeset
  1802
    avimux->total_frames++;
hgs
parents:
diff changeset
  1803
hgs
parents:
diff changeset
  1804
    if (avimux->is_bigfile) {
hgs
parents:
diff changeset
  1805
      avimux->numx_frames++;
hgs
parents:
diff changeset
  1806
    } else {
hgs
parents:
diff changeset
  1807
      avimux->num_frames++;
hgs
parents:
diff changeset
  1808
    }
hgs
parents:
diff changeset
  1809
hgs
parents:
diff changeset
  1810
    flags = 0x02;
hgs
parents:
diff changeset
  1811
    if (!GST_BUFFER_FLAG_IS_SET (data, GST_BUFFER_FLAG_DELTA_UNIT))
hgs
parents:
diff changeset
  1812
      flags |= 0x10;
hgs
parents:
diff changeset
  1813
  } else {
hgs
parents:
diff changeset
  1814
    GstAviAudioPad *audpad = (GstAviAudioPad *) avipad;
hgs
parents:
diff changeset
  1815
hgs
parents:
diff changeset
  1816
    flags = 0;
hgs
parents:
diff changeset
  1817
    audpad->audio_size += GST_BUFFER_SIZE (data);
hgs
parents:
diff changeset
  1818
    audpad->audio_time += GST_BUFFER_DURATION (data);
hgs
parents:
diff changeset
  1819
  }
hgs
parents:
diff changeset
  1820
hgs
parents:
diff changeset
  1821
  gst_avi_mux_add_index (avimux, avipad->tag, flags, GST_BUFFER_SIZE (data));
hgs
parents:
diff changeset
  1822
hgs
parents:
diff changeset
  1823
  /* prepare buffers for sending */
hgs
parents:
diff changeset
  1824
  gst_buffer_set_caps (header, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1825
  data = gst_buffer_make_metadata_writable (data);
hgs
parents:
diff changeset
  1826
  gst_buffer_set_caps (data, GST_PAD_CAPS (avimux->srcpad));
hgs
parents:
diff changeset
  1827
hgs
parents:
diff changeset
  1828
  GST_LOG_OBJECT (avimux, "pushing buffers: head, data");
hgs
parents:
diff changeset
  1829
hgs
parents:
diff changeset
  1830
  if ((res = gst_pad_push (avimux->srcpad, header)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1831
    return res;
hgs
parents:
diff changeset
  1832
  if ((res = gst_pad_push (avimux->srcpad, data)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1833
    return res;
hgs
parents:
diff changeset
  1834
hgs
parents:
diff changeset
  1835
  if (pad_bytes) {
hgs
parents:
diff changeset
  1836
    if ((res = gst_avi_mux_send_pad_data (avimux, pad_bytes)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1837
      return res;
hgs
parents:
diff changeset
  1838
  }
hgs
parents:
diff changeset
  1839
hgs
parents:
diff changeset
  1840
  /* if any push above fails, we're in trouble with file consistency anyway */
hgs
parents:
diff changeset
  1841
  avimux->total_data += total_size;
hgs
parents:
diff changeset
  1842
  avimux->idx_offset += total_size;
hgs
parents:
diff changeset
  1843
hgs
parents:
diff changeset
  1844
  return res;
hgs
parents:
diff changeset
  1845
}
hgs
parents:
diff changeset
  1846
hgs
parents:
diff changeset
  1847
/* pick the oldest buffer from the pads and push it */
hgs
parents:
diff changeset
  1848
static GstFlowReturn
hgs
parents:
diff changeset
  1849
gst_avi_mux_do_one_buffer (GstAviMux * avimux)
hgs
parents:
diff changeset
  1850
{
hgs
parents:
diff changeset
  1851
  GstAviPad *avipad, *best_pad;
hgs
parents:
diff changeset
  1852
  GSList *node;
hgs
parents:
diff changeset
  1853
  GstBuffer *buffer;
hgs
parents:
diff changeset
  1854
  GstClockTime time, best_time;
hgs
parents:
diff changeset
  1855
hgs
parents:
diff changeset
  1856
  node = avimux->sinkpads;
hgs
parents:
diff changeset
  1857
  best_pad = NULL;
hgs
parents:
diff changeset
  1858
  best_time = GST_CLOCK_TIME_NONE;
hgs
parents:
diff changeset
  1859
  for (; node; node = node->next) {
hgs
parents:
diff changeset
  1860
    avipad = (GstAviPad *) node->data;
hgs
parents:
diff changeset
  1861
hgs
parents:
diff changeset
  1862
    if (!avipad->collect)
hgs
parents:
diff changeset
  1863
      continue;
hgs
parents:
diff changeset
  1864
hgs
parents:
diff changeset
  1865
    buffer = gst_collect_pads_peek (avimux->collect, avipad->collect);
hgs
parents:
diff changeset
  1866
    if (!buffer)
hgs
parents:
diff changeset
  1867
      continue;
hgs
parents:
diff changeset
  1868
    time = GST_BUFFER_TIMESTAMP (buffer);
hgs
parents:
diff changeset
  1869
    gst_buffer_unref (buffer);
hgs
parents:
diff changeset
  1870
hgs
parents:
diff changeset
  1871
    /* invalid timestamp buffers pass first,
hgs
parents:
diff changeset
  1872
     * these are probably initialization buffers */
hgs
parents:
diff changeset
  1873
    if (best_pad == NULL || !GST_CLOCK_TIME_IS_VALID (time)
hgs
parents:
diff changeset
  1874
        || (GST_CLOCK_TIME_IS_VALID (best_time) && time < best_time)) {
hgs
parents:
diff changeset
  1875
      best_pad = avipad;
hgs
parents:
diff changeset
  1876
      best_time = time;
hgs
parents:
diff changeset
  1877
    }
hgs
parents:
diff changeset
  1878
  }
hgs
parents:
diff changeset
  1879
hgs
parents:
diff changeset
  1880
  if (best_pad) {
hgs
parents:
diff changeset
  1881
    GST_LOG_OBJECT (avimux, "selected pad %s with time %" GST_TIME_FORMAT,
hgs
parents:
diff changeset
  1882
        GST_PAD_NAME (best_pad->collect->pad), GST_TIME_ARGS (best_time));
hgs
parents:
diff changeset
  1883
hgs
parents:
diff changeset
  1884
    return gst_avi_mux_do_buffer (avimux, best_pad);
hgs
parents:
diff changeset
  1885
  } else {
hgs
parents:
diff changeset
  1886
    /* simply finish off the file and send EOS */
hgs
parents:
diff changeset
  1887
    gst_avi_mux_stop_file (avimux);
hgs
parents:
diff changeset
  1888
    gst_pad_push_event (avimux->srcpad, gst_event_new_eos ());
hgs
parents:
diff changeset
  1889
    return GST_FLOW_UNEXPECTED;
hgs
parents:
diff changeset
  1890
  }
hgs
parents:
diff changeset
  1891
}
hgs
parents:
diff changeset
  1892
hgs
parents:
diff changeset
  1893
static GstFlowReturn
hgs
parents:
diff changeset
  1894
gst_avi_mux_collect_pads (GstCollectPads * pads, GstAviMux * avimux)
hgs
parents:
diff changeset
  1895
{
hgs
parents:
diff changeset
  1896
  GstFlowReturn res;
hgs
parents:
diff changeset
  1897
hgs
parents:
diff changeset
  1898
  if (G_UNLIKELY (avimux->write_header)) {
hgs
parents:
diff changeset
  1899
    if ((res = gst_avi_mux_start_file (avimux)) != GST_FLOW_OK)
hgs
parents:
diff changeset
  1900
      return res;
hgs
parents:
diff changeset
  1901
  }
hgs
parents:
diff changeset
  1902
hgs
parents:
diff changeset
  1903
  return gst_avi_mux_do_one_buffer (avimux);
hgs
parents:
diff changeset
  1904
}
hgs
parents:
diff changeset
  1905
hgs
parents:
diff changeset
  1906
hgs
parents:
diff changeset
  1907
static void
hgs
parents:
diff changeset
  1908
gst_avi_mux_get_property (GObject * object,
hgs
parents:
diff changeset
  1909
    guint prop_id, GValue * value, GParamSpec * pspec)
hgs
parents:
diff changeset
  1910
{
hgs
parents:
diff changeset
  1911
  GstAviMux *avimux;
hgs
parents:
diff changeset
  1912
hgs
parents:
diff changeset
  1913
  avimux = GST_AVI_MUX (object);
hgs
parents:
diff changeset
  1914
hgs
parents:
diff changeset
  1915
  switch (prop_id) {
hgs
parents:
diff changeset
  1916
    case ARG_BIGFILE:
hgs
parents:
diff changeset
  1917
      g_value_set_boolean (value, avimux->enable_large_avi);
hgs
parents:
diff changeset
  1918
      break;
hgs
parents:
diff changeset
  1919
    default:
hgs
parents:
diff changeset
  1920
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
hgs
parents:
diff changeset
  1921
      break;
hgs
parents:
diff changeset
  1922
  }
hgs
parents:
diff changeset
  1923
}
hgs
parents:
diff changeset
  1924
hgs
parents:
diff changeset
  1925
static void
hgs
parents:
diff changeset
  1926
gst_avi_mux_set_property (GObject * object,
hgs
parents:
diff changeset
  1927
    guint prop_id, const GValue * value, GParamSpec * pspec)
hgs
parents:
diff changeset
  1928
{
hgs
parents:
diff changeset
  1929
  GstAviMux *avimux;
hgs
parents:
diff changeset
  1930
hgs
parents:
diff changeset
  1931
  avimux = GST_AVI_MUX (object);
hgs
parents:
diff changeset
  1932
hgs
parents:
diff changeset
  1933
  switch (prop_id) {
hgs
parents:
diff changeset
  1934
    case ARG_BIGFILE:
hgs
parents:
diff changeset
  1935
      avimux->enable_large_avi = g_value_get_boolean (value);
hgs
parents:
diff changeset
  1936
      break;
hgs
parents:
diff changeset
  1937
    default:
hgs
parents:
diff changeset
  1938
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
hgs
parents:
diff changeset
  1939
      break;
hgs
parents:
diff changeset
  1940
  }
hgs
parents:
diff changeset
  1941
}
hgs
parents:
diff changeset
  1942
hgs
parents:
diff changeset
  1943
static GstStateChangeReturn
hgs
parents:
diff changeset
  1944
gst_avi_mux_change_state (GstElement * element, GstStateChange transition)
hgs
parents:
diff changeset
  1945
{
hgs
parents:
diff changeset
  1946
  GstAviMux *avimux;
hgs
parents:
diff changeset
  1947
  GstStateChangeReturn ret;
hgs
parents:
diff changeset
  1948
hgs
parents:
diff changeset
  1949
  avimux = GST_AVI_MUX (element);
hgs
parents:
diff changeset
  1950
hgs
parents:
diff changeset
  1951
  switch (transition) {
hgs
parents:
diff changeset
  1952
    case GST_STATE_CHANGE_READY_TO_PAUSED:
hgs
parents:
diff changeset
  1953
      gst_collect_pads_start (avimux->collect);
hgs
parents:
diff changeset
  1954
      break;
hgs
parents:
diff changeset
  1955
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
hgs
parents:
diff changeset
  1956
      break;
hgs
parents:
diff changeset
  1957
    case GST_STATE_CHANGE_PAUSED_TO_READY:
hgs
parents:
diff changeset
  1958
      gst_collect_pads_stop (avimux->collect);
hgs
parents:
diff changeset
  1959
      break;
hgs
parents:
diff changeset
  1960
    default:
hgs
parents:
diff changeset
  1961
      break;
hgs
parents:
diff changeset
  1962
  }
hgs
parents:
diff changeset
  1963
hgs
parents:
diff changeset
  1964
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
hgs
parents:
diff changeset
  1965
  if (ret == GST_STATE_CHANGE_FAILURE)
hgs
parents:
diff changeset
  1966
    goto done;
hgs
parents:
diff changeset
  1967
hgs
parents:
diff changeset
  1968
  switch (transition) {
hgs
parents:
diff changeset
  1969
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
hgs
parents:
diff changeset
  1970
      break;
hgs
parents:
diff changeset
  1971
    case GST_STATE_CHANGE_PAUSED_TO_READY:
hgs
parents:
diff changeset
  1972
      gst_avi_mux_reset (avimux);
hgs
parents:
diff changeset
  1973
      break;
hgs
parents:
diff changeset
  1974
    case GST_STATE_CHANGE_READY_TO_NULL:
hgs
parents:
diff changeset
  1975
      break;
hgs
parents:
diff changeset
  1976
    default:
hgs
parents:
diff changeset
  1977
      break;
hgs
parents:
diff changeset
  1978
  }
hgs
parents:
diff changeset
  1979
hgs
parents:
diff changeset
  1980
done:
hgs
parents:
diff changeset
  1981
  return ret;
hgs
parents:
diff changeset
  1982
}