gstffmpegcfg.c 39.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/* GStreamer
 *
 * FFMpeg Configuration
 *
 * Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "gstffmpeg.h"
#include "gstffmpegenc.h"
30
#include "gstffmpegcfg.h"
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

#include <string.h>

/* some enums used in property declarations */

#define GST_TYPE_FFMPEG_PASS (gst_ffmpeg_pass_get_type ())
static GType
gst_ffmpeg_pass_get_type (void)
{
  static GType ffmpeg_pass_type = 0;

  if (!ffmpeg_pass_type) {
    static const GEnumValue ffmpeg_passes[] = {
      {0, "Constant Bitrate Encoding", "cbr"},
      {CODEC_FLAG_QSCALE, "Constant Quantizer", "quant"},
      {CODEC_FLAG_PASS1, "VBR Encoding - Pass 1", "pass1"},
      {CODEC_FLAG_PASS2, "VBR Encoding - Pass 2", "pass2"},
      {0, NULL, NULL},
    };

    ffmpeg_pass_type =
        g_enum_register_static ("GstFFMpegEncPass", ffmpeg_passes);
  }

  return ffmpeg_pass_type;
}

#if 0
/* some do not support 2-pass */
#define GST_TYPE_FFMPEG_LIM_PASS (gst_ffmpeg_lim_pass_get_type ())
static GType
gst_ffmpeg_lim_pass_get_type (void)
{
  static GType ffmpeg_lim_pass_type = 0;

  if (!ffmpeg_lim_pass_type) {
    static const GEnumValue ffmpeg_lim_passes[] = {
      {0, "Constant Bitrate Encoding", "cbr"},
      {CODEC_FLAG_QSCALE, "Constant Quantizer", "quant"},
      {0, NULL, NULL},
    };

    ffmpeg_lim_pass_type =
        g_enum_register_static ("GstFFMpegEncLimPass", ffmpeg_lim_passes);
  }

  return ffmpeg_lim_pass_type;
}
#endif

#define GST_TYPE_FFMPEG_MB_DECISION (gst_ffmpeg_mb_decision_get_type ())
static GType
gst_ffmpeg_mb_decision_get_type (void)
{
  static GType ffmpeg_mb_decision_type = 0;

  if (!ffmpeg_mb_decision_type) {
    static const GEnumValue ffmpeg_mb_decisions[] = {
      {FF_MB_DECISION_SIMPLE, "Use method set by mb-cmp", "simple"},
90
      {FF_MB_DECISION_BITS,
91
          "Chooses the one which needs the fewest bits aka vhq mode", "bits"},
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226
      {FF_MB_DECISION_RD, "Rate Distortion", "rd"},
      {0, NULL, NULL},
    };

    ffmpeg_mb_decision_type =
        g_enum_register_static ("GstFFMpegEncMBDecision", ffmpeg_mb_decisions);
  }

  return ffmpeg_mb_decision_type;
}

#define GST_TYPE_FFMPEG_CMP_FUNCTION (gst_ffmpeg_mb_cmp_get_type ())
static GType
gst_ffmpeg_mb_cmp_get_type (void)
{
  static GType ffmpeg_mb_cmp_type = 0;

  /* TODO fill out remaining values */
  if (!ffmpeg_mb_cmp_type) {
    static const GEnumValue ffmpeg_mb_cmps[] = {
      {FF_CMP_SAD, "Sum of Absolute Differences", "sad"},
      {FF_CMP_SSE, "Sum of Squared Errors", "sse"},
      {FF_CMP_SATD, "Sum of Absolute Hadamard Transformed Differences", "satd"},
      {FF_CMP_DCT, "Sum of Absolute DCT Transformed Differences", "dct"},
      {FF_CMP_PSNR, "Sum of the Squared Quantization Errors", "psnr"},
      {FF_CMP_BIT, "Sum of the Bits needed for the block", "bit"},
      {FF_CMP_RD, "Rate Distortion optimal", "rd"},
      {FF_CMP_ZERO, "ZERO", "zero"},
      {FF_CMP_VSAD, "VSAD", "vsad"},
      {FF_CMP_VSSE, "VSSE", "vsse"},
#if 0
/* economize a bit for now */
      {FF_CMP_NSSE, "NSSE", "nsse"},
      {FF_CMP_W53, "W53", "w53"},
      {FF_CMP_W97, "W97", "w97"},
#endif
      {0, NULL, NULL},
    };

    ffmpeg_mb_cmp_type =
        g_enum_register_static ("GstFFMpegCMPFunction", ffmpeg_mb_cmps);
  }

  return ffmpeg_mb_cmp_type;
}

#define GST_TYPE_FFMPEG_DCT_ALGO (gst_ffmpeg_dct_algo_get_type ())
static GType
gst_ffmpeg_dct_algo_get_type (void)
{
  static GType ffmpeg_dct_algo_type = 0;

  if (!ffmpeg_dct_algo_type) {
    static const GEnumValue ffmpeg_dct_algos[] = {
      {FF_DCT_AUTO, "Automatically select a good one", "auto"},
      {FF_DCT_FASTINT, "Fast Integer", "fastint"},
      {FF_DCT_INT, "Accurate Integer", "int"},
      {FF_DCT_MMX, "MMX", "mmx"},
      {FF_DCT_MLIB, "MLIB", "mlib"},
      {FF_DCT_ALTIVEC, "ALTIVEC", "altivec"},
      {FF_DCT_FAAN, "FAAN", "faan"},
      {0, NULL, NULL},
    };

    ffmpeg_dct_algo_type =
        g_enum_register_static ("GstFFMpegDCTAlgo", ffmpeg_dct_algos);
  }

  return ffmpeg_dct_algo_type;
}

#define GST_TYPE_FFMPEG_IDCT_ALGO (gst_ffmpeg_idct_algo_get_type ())
static GType
gst_ffmpeg_idct_algo_get_type (void)
{
  static GType ffmpeg_idct_algo_type = 0;

  if (!ffmpeg_idct_algo_type) {
    static const GEnumValue ffmpeg_idct_algos[] = {
      {FF_IDCT_AUTO, "Automatically select a good one", "auto"},
      {FF_IDCT_INT, "JPEG reference Integer", "int"},
      {FF_IDCT_SIMPLE, "Simple", "simple"},
      {FF_IDCT_SIMPLEMMX, "Simple MMX", "simplemmx"},
      {FF_IDCT_LIBMPEG2MMX, "LIBMPEG2MMX", "libmpeg2mmx"},
      {FF_IDCT_PS2, "PS2", "ps2"},
      {FF_IDCT_MLIB, "MLIB", "mlib"},
      {FF_IDCT_ARM, "ARM", "arm"},
      {FF_IDCT_ALTIVEC, "ALTIVEC", "altivec"},
      {FF_IDCT_SH4, "SH4", "sh4"},
      {FF_IDCT_SIMPLEARM, "SIMPLEARM", "simplearm"},
      {FF_IDCT_H264, "H264", "h264"},
      {FF_IDCT_VP3, "VP3", "vp3"},
      {FF_IDCT_IPP, "IPP", "ipp"},
      {FF_IDCT_XVIDMMX, "XVIDMMX", "xvidmmx"},
      {0, NULL, NULL},
    };

    ffmpeg_idct_algo_type =
        g_enum_register_static ("GstFFMpegIDCTAlgo", ffmpeg_idct_algos);
  }

  return ffmpeg_idct_algo_type;
}

#define GST_TYPE_FFMPEG_QUANT_TYPE (gst_ffmpeg_quant_type_get_type ())
static GType
gst_ffmpeg_quant_type_get_type (void)
{
  static GType ffmpeg_quant_type_type = 0;

  if (!ffmpeg_quant_type_type) {
    static const GEnumValue ffmpeg_quant_types[] = {
      {0, "H263 quantization", "h263"},
      {1, "MPEG quantization", "mpeg"},
      {0, NULL, NULL},
    };

    ffmpeg_quant_type_type =
        g_enum_register_static ("GstFFMpegEncQuantTypes", ffmpeg_quant_types);
  }

  return ffmpeg_quant_type_type;
}

#define GST_TYPE_FFMPEG_PRE_ME (gst_ffmpeg_pre_me_get_type ())
static GType
gst_ffmpeg_pre_me_get_type (void)
{
  static GType ffmpeg_pre_me_type = 0;

  if (!ffmpeg_pre_me_type) {
    static const GEnumValue ffmpeg_pre_mes[] = {
      {0, "Disabled", "off"},
      {1, "Only after I-frames", "key"},
      {2, "Always", "all"},
227
      {0, NULL, NULL}
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    };

    ffmpeg_pre_me_type =
        g_enum_register_static ("GstFFMpegEncPreME", ffmpeg_pre_mes);
  }

  return ffmpeg_pre_me_type;
}

#define GST_TYPE_FFMPEG_PRED_METHOD (gst_ffmpeg_pred_method_get_type ())
static GType
gst_ffmpeg_pred_method_get_type (void)
{
  static GType ffmpeg_pred_method = 0;

  if (!ffmpeg_pred_method) {
    static const GEnumValue ffmpeg_pred_methods[] = {
      {FF_PRED_LEFT, "Left", "left"},
      {FF_PRED_PLANE, "Plane", "plane"},
      {FF_PRED_MEDIAN, "Median", "median"},
248
      {0, NULL, NULL}
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
    };

    ffmpeg_pred_method =
        g_enum_register_static ("GstFFMpegEncPredMethod", ffmpeg_pred_methods);
  }

  return ffmpeg_pred_method;
}

#define GST_TYPE_FFMPEG_FLAGS (gst_ffmpeg_flags_get_type())
static GType
gst_ffmpeg_flags_get_type (void)
{
  static GType ffmpeg_flags_type = 0;

  if (!ffmpeg_flags_type) {
    static const GFlagsValue ffmpeg_flags[] = {
266 267 268
      {CODEC_FLAG_OBMC, "Use overlapped block motion compensation (h263+)",
          "obmc"},
      {CODEC_FLAG_QSCALE, "Use fixed qscale", "qscale"},
269
      {CODEC_FLAG_4MV, "Allow 4 MV per MB", "4mv"},
270
      {CODEC_FLAG_H263P_AIV, "H.263 alternative inter VLC", "aiv"},
271 272 273
      {CODEC_FLAG_QPEL, "Quartel Pel Motion Compensation", "qpel"},
      {CODEC_FLAG_GMC, "GMC", "gmc"},
      {CODEC_FLAG_MV0, "Always try a MB with MV (0,0)", "mv0"},
274
      {CODEC_FLAG_PART,
275
          "Store MV, DC and AC coefficients in seperate partitions", "part"},
276
      {CODEC_FLAG_GRAY, "Only decode/encode grayscale", "gray"},
277
      {CODEC_FLAG_NORMALIZE_AQP,
278
          "Normalize Adaptive Quantization (masking, etc)", "aqp"},
279 280
      {CODEC_FLAG_GLOBAL_HEADER,
            "Global headers in extradata instead of every keyframe",
281
          "global-headers"},
282
      {CODEC_FLAG_AC_PRED, "H263 Advanced Intra Coding / MPEG4 AC prediction",
283
          "aic"},
284 285
      {CODEC_FLAG_H263P_UMV, "Unlimited Motion Vector", "umv"},
      {CODEC_FLAG_CBP_RD, "Rate Distoration Optimization for CBP", "cbp-rd"},
286
      {CODEC_FLAG_QP_RD, "Rate Distoration Optimization for QP selection",
287
          "qp-rd"},
288
      {CODEC_FLAG_H263P_SLICE_STRUCT, "H263 slice struct", "ss"},
289
      {CODEC_FLAG_SVCD_SCAN_OFFSET,
290
          "Reserve space for SVCD scan offset user data", "scanoffset"},
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
      {CODEC_FLAG_CLOSED_GOP, "Closed GOP", "closedgop"},
      {0, NULL, NULL},
    };

    ffmpeg_flags_type =
        g_flags_register_static ("GstFFMpegFlags", ffmpeg_flags);
  }

  return ffmpeg_flags_type;
}

/* provides additional info to attach to a property */

typedef struct _GParamSpecData GParamSpecData;

struct _GParamSpecData
{
  /* offset of member in the element struct that stores the property */
  guint offset;

  /* size of the above member */
  guint size;

  /* if TRUE, try to get the default from lavc and ignore the paramspec default */
  gboolean lavc_default;

  /* these lists are arrays terminated by CODEC_ID_NONE entry:
   * property applies to a codec if it's not in the exclude_list
   * and in exclude_list (or the latter is NULL) */
  gint *include_list;
  gint *exclude_list;
};

/* properties whose member offset is higher than the config base
 * can be copied directly at context configuration time;
 * and can also retrieve a default value from lavc */
#define CONTEXT_CONFIG_OFFSET   G_STRUCT_OFFSET (GstFFMpegEnc, config)

/* additional info is named pointer specified by the quark */
static GQuark quark;

/* central configuration store:
 * list of GParamSpec's with GParamSpecData attached as named pointer */
static GList *property_list;

/* add the GParamSpec pspec to store with GParamSpecData
 * constructed from struct_type, member, default and include and exclude */
#define gst_ffmpeg_add_pspec_full(pspec, store, struct_type, member,    \
    default, include, exclude)                                          \
G_STMT_START {                                                          \
  GParamSpecData *_qdata = g_new0 (GParamSpecData, 1);                  \
  GstFFMpegEnc _enc;                                                    \
  _qdata->offset = G_STRUCT_OFFSET (struct_type, member);               \
  _qdata->size = sizeof (_enc.member);                                  \
  _qdata->lavc_default = default;                                       \
  _qdata->include_list = include;                                       \
  _qdata->exclude_list = exclude;                                       \
  g_param_spec_set_qdata_full (pspec, quark, _qdata, g_free);           \
  store = g_list_append (store, pspec);                                 \
} G_STMT_END

#define gst_ffmpeg_add_pspec(pspec, member, default, include, exclude)       \
  gst_ffmpeg_add_pspec_full (pspec, property_list, GstFFMpegEnc, member,     \
      default, include, exclude)

/* ==== BEGIN CONFIGURATION SECTION ==== */

/* some typical include and exclude lists; modify and/or add where needed */

360
static gint mpeg[] = {
361 362 363 364
  CODEC_ID_MPEG4,
  CODEC_ID_MSMPEG4V1,
  CODEC_ID_MSMPEG4V2,
  CODEC_ID_MSMPEG4V3,
365 366
  CODEC_ID_MPEG1VIDEO,
  CODEC_ID_MPEG2VIDEO,
367
  CODEC_ID_H263P,
368
  CODEC_ID_FLV1,
369
  CODEC_ID_H263,
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
  CODEC_ID_NONE
};

static gint huffyuv[] = {
  CODEC_ID_HUFFYUV,
  CODEC_ID_FFVHUFF,
  CODEC_ID_NONE
};

/* Properties should be added here for registration into the config store.
 * Note that some may occur more than once, with different include/exclude lists,
 * as some may require different defaults for different codecs,
 * or some may have slightly varying enum-types with more or less options.
 * The enum-types themselves should be declared above. */
void
385
gst_ffmpeg_cfg_init (void)
386 387 388 389 390 391 392 393 394
{
  GParamSpec *pspec;

  /* initialize global config vars */
  quark = g_quark_from_static_string ("ffmpeg-cfg-param-spec-data");
  property_list = NULL;

  /* list properties here */
  pspec = g_param_spec_enum ("pass", "Encoding pass/type",
395 396
      "Encoding pass/type", GST_TYPE_FFMPEG_PASS, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
397
  gst_ffmpeg_add_pspec (pspec, pass, FALSE, mpeg, NULL);
398 399

  pspec = g_param_spec_float ("quantizer", "Constant Quantizer",
400 401
      "Constant Quantizer", 0, 30, 0.01f,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
402
  gst_ffmpeg_add_pspec (pspec, quantizer, FALSE, mpeg, NULL);
403 404

  pspec = g_param_spec_string ("statsfile", "Statistics Filename",
405 406 407 408 409 410
      "Filename to store data for 2-pass encoding (deprecated, use multipass-cache-file)",
      "stats.log", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
  gst_ffmpeg_add_pspec (pspec, filename, FALSE, mpeg, NULL);

  pspec = g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
      "Filename for multipass cache file", "stats.log",
411
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
412
  gst_ffmpeg_add_pspec (pspec, filename, FALSE, mpeg, NULL);
413 414 415

  pspec = g_param_spec_int ("bitrate-tolerance", "Bitrate Tolerance",
      "Number of bits the bitstream is allowed to diverge from the reference",
416
      0, 100000000, 8000000, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
417
  gst_ffmpeg_add_pspec (pspec, config.bit_rate_tolerance, FALSE, mpeg, NULL);
418 419 420

  pspec = g_param_spec_enum ("mb-decision", "Macroblock Decision",
      "Macroblok Decision Mode",
421 422
      GST_TYPE_FFMPEG_MB_DECISION, FF_CMP_SAD,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
423
  gst_ffmpeg_add_pspec (pspec, config.mb_decision, FALSE, mpeg, NULL);
424 425 426

  pspec = g_param_spec_enum ("mb-cmp", "Macroblock Compare Function",
      "Macroblok Compare Function",
427 428
      GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
429
  gst_ffmpeg_add_pspec (pspec, config.mb_cmp, FALSE, mpeg, NULL);
430

431 432 433
  pspec =
      g_param_spec_enum ("me-pre-cmp",
      "Motion Estimation Pre Pass Compare Function",
434
      "Motion Estimation Pre Pass Compare Function",
435 436
      GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
437
  gst_ffmpeg_add_pspec (pspec, config.me_pre_cmp, FALSE, mpeg, NULL);
438 439 440

  pspec = g_param_spec_enum ("me-cmp", "Motion Estimation Compare Function",
      "Motion Estimation Compare Function",
441 442
      GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
443
  gst_ffmpeg_add_pspec (pspec, config.me_cmp, FALSE, mpeg, NULL);
444 445 446 447

  pspec = g_param_spec_enum ("me-sub-cmp",
      "Subpixel Motion Estimation Compare Function",
      "Subpixel Motion Estimation Compare Function",
448 449
      GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
450
  gst_ffmpeg_add_pspec (pspec, config.me_sub_cmp, FALSE, mpeg, NULL);
451 452 453

  pspec = g_param_spec_enum ("ildct-cmp", "Interlaced DCT Compare Function",
      "Interlaced DCT Compare Function",
454 455
      GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_VSAD,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
456
  gst_ffmpeg_add_pspec (pspec, config.ildct_cmp, FALSE, mpeg, NULL);
457 458 459

  pspec = g_param_spec_enum ("dct-algo", "DCT Algorithm",
      "DCT Algorithm",
460 461
      GST_TYPE_FFMPEG_DCT_ALGO, FF_DCT_AUTO,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
462
  gst_ffmpeg_add_pspec (pspec, config.dct_algo, FALSE, mpeg, NULL);
463 464 465

  pspec = g_param_spec_enum ("idct-algo", "IDCT Algorithm",
      "IDCT Algorithm",
466 467
      GST_TYPE_FFMPEG_IDCT_ALGO, FF_IDCT_AUTO,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
468
  gst_ffmpeg_add_pspec (pspec, config.idct_algo, FALSE, mpeg, NULL);
469 470

  pspec = g_param_spec_enum ("quant-type", "Quantizer Type",
471 472
      "Quantizer Type", GST_TYPE_FFMPEG_QUANT_TYPE, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
473
  gst_ffmpeg_add_pspec (pspec, config.mpeg_quant, FALSE, mpeg, NULL);
474 475

  pspec = g_param_spec_int ("qmin", "Minimum Quantizer",
476 477
      "Minimum Quantizer", 1, 31, 2,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
478
  gst_ffmpeg_add_pspec (pspec, config.qmin, FALSE, mpeg, NULL);
479 480

  pspec = g_param_spec_int ("qmax", "Maximum Quantizer",
481 482
      "Maximum Quantizer", 1, 31, 31,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
483
  gst_ffmpeg_add_pspec (pspec, config.qmax, FALSE, mpeg, NULL);
484 485 486

  pspec = g_param_spec_int ("max-qdiff", "Maximum Quantizer Difference",
      "Maximum Quantizer Difference between frames",
487
      1, 31, 3, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
488
  gst_ffmpeg_add_pspec (pspec, config.max_qdiff, FALSE, mpeg, NULL);
489

490 491 492
  pspec = g_param_spec_int ("mb-qmin", "Minimum MB Quantizer",
      "Minimum MB Quantizer", 0, 31, 2,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
493
  gst_ffmpeg_add_pspec (pspec, config.mb_qmin, FALSE, mpeg, NULL);
494

495 496 497
  pspec = g_param_spec_int ("mb-qmax", "Maximum MB Quantizer",
      "Maximum MB Quantizer", 0, 31, 31,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
498
  gst_ffmpeg_add_pspec (pspec, config.mb_qmax, FALSE, mpeg, NULL);
499 500

  pspec = g_param_spec_int ("lmin", "Minimum Lagrange Multiplier",
501 502
      "Minimum Lagrange Multiplier", 1, 31, 2,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
503
  gst_ffmpeg_add_pspec (pspec, lmin, FALSE, mpeg, NULL);
504 505

  pspec = g_param_spec_int ("lmax", "Maximum Lagrange Multiplier",
506 507
      "Maximum Lagrange Multiplier", 1, 31, 31,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
508
  gst_ffmpeg_add_pspec (pspec, lmax, FALSE, mpeg, NULL);
509 510 511

  pspec = g_param_spec_float ("qcompress", "Quantizer Change",
      "Quantizer Change between easy and hard scenes",
512
      0, 1.0f, 0.5f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
513
  gst_ffmpeg_add_pspec (pspec, config.qcompress, FALSE, mpeg, NULL);
514 515

  pspec = g_param_spec_float ("qblur", "Quantizer Smoothing",
516 517
      "Quantizer Smoothing over time", 0, 1.0f, 0.5f,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
518
  gst_ffmpeg_add_pspec (pspec, config.qblur, FALSE, mpeg, NULL);
519 520 521

  pspec = g_param_spec_float ("rc-qsquish", "Ratecontrol Limiting Method",
      "0 means limit by clipping, otherwise use nice continuous function",
522
      0, 99.0f, 1.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
523
  gst_ffmpeg_add_pspec (pspec, config.rc_qsquish, FALSE, mpeg, NULL);
524 525

  pspec = g_param_spec_float ("rc-qmod-amp", "Ratecontrol Mod",
526 527
      "Ratecontrol Mod", 0, 99.0f, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
528
  gst_ffmpeg_add_pspec (pspec, config.rc_qmod_amp, FALSE, mpeg, NULL);
529 530

  pspec = g_param_spec_int ("rc-qmod-freq", "Ratecontrol Freq",
531
      "Ratecontrol Freq", 0, 0, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
532
  gst_ffmpeg_add_pspec (pspec, config.rc_qmod_freq, FALSE, mpeg, NULL);
533 534

  pspec = g_param_spec_int ("rc-buffer-size", "Ratecontrol Buffer Size",
535 536
      "Decoder bitstream buffer size", 0, G_MAXINT, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
537
  gst_ffmpeg_add_pspec (pspec, config.rc_buffer_size, FALSE, mpeg, NULL);
538

539 540 541
  pspec =
      g_param_spec_float ("rc-buffer-aggressivity",
      "Ratecontrol Buffer Aggressivity", "Ratecontrol Buffer Aggressivity", 0,
542
      99.0f, 1.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
543 544
  gst_ffmpeg_add_pspec (pspec, config.rc_buffer_aggressivity, FALSE, mpeg,
      NULL);
545 546

  pspec = g_param_spec_int ("rc-max-rate", "Ratecontrol Maximum Bitrate",
547 548
      "Ratecontrol Maximum Bitrate", 0, G_MAXINT, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
549
  gst_ffmpeg_add_pspec (pspec, config.rc_max_rate, FALSE, mpeg, NULL);
550 551

  pspec = g_param_spec_int ("rc-min-rate", "Ratecontrol Minimum Bitrate",
552 553
      "Ratecontrol Minimum Bitrate", 0, G_MAXINT, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
554
  gst_ffmpeg_add_pspec (pspec, config.rc_min_rate, FALSE, mpeg, NULL);
555

556 557
  pspec =
      g_param_spec_float ("rc-initial-cplx",
558
      "Initial Complexity for Pass 1 Ratecontrol",
559
      "Initial Complexity for Pass 1 Ratecontrol", 0, 9999999.0f, 0,
560
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
561
  gst_ffmpeg_add_pspec (pspec, config.rc_initial_cplx, FALSE, mpeg, NULL);
562 563

  pspec = g_param_spec_string ("rc-eq", "Ratecontrol Equation",
564 565
      "Ratecontrol Equation", "tex^qComp",
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
566
  gst_ffmpeg_add_pspec (pspec, config.rc_eq, FALSE, mpeg, NULL);
567 568 569

  pspec = g_param_spec_float ("b-quant-factor", "B-Quantizer Factor",
      "Factor in B-Frame Quantizer Computation",
570
      -31.0f, 31.0f, 1.25f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
571
  gst_ffmpeg_add_pspec (pspec, config.b_quant_factor, FALSE, mpeg, NULL);
572 573 574

  pspec = g_param_spec_float ("b-quant-offset", "B-Quantizer Offset",
      "Offset in B-Frame Quantizer Computation",
575
      0.0f, 31.0f, 1.25f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
576
  gst_ffmpeg_add_pspec (pspec, config.b_quant_offset, FALSE, mpeg, NULL);
577 578 579

  pspec = g_param_spec_float ("i-quant-factor", "I-Quantizer Factor",
      "Factor in P-Frame Quantizer Computation",
580
      -31.0f, 31.0f, 0.8f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
581
  gst_ffmpeg_add_pspec (pspec, config.i_quant_factor, FALSE, mpeg, NULL);
582 583 584

  pspec = g_param_spec_float ("i-quant-offset", "I-Quantizer Offset",
      "Offset in P-Frame Quantizer Computation",
585
      0.0f, 31.0f, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
586
  gst_ffmpeg_add_pspec (pspec, config.i_quant_offset, FALSE, mpeg, NULL);
587 588 589 590

  /* note overlap with gop-size; 0 means do not override */
  pspec = g_param_spec_int ("max-key-interval", "Maximum Key Interval",
      "Maximum number of frames between two keyframes (< 0 is in sec)",
591
      -100, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
592
  gst_ffmpeg_add_pspec (pspec, max_key_interval, FALSE, mpeg, NULL);
593 594 595 596

  pspec = g_param_spec_int ("luma-elim-threshold",
      "Luma Elimination Threshold",
      "Luma Single Coefficient Elimination Threshold",
597
      -99, 99, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
598
  gst_ffmpeg_add_pspec (pspec, config.luma_elim_threshold, FALSE, mpeg, NULL);
599 600 601 602

  pspec = g_param_spec_int ("chroma-elim-threshold",
      "Chroma Elimination Threshold",
      "Chroma Single Coefficient Elimination Threshold",
603
      -99, 99, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
604
  gst_ffmpeg_add_pspec (pspec, config.chroma_elim_threshold, FALSE, mpeg, NULL);
605 606

  pspec = g_param_spec_float ("lumi-masking", "Luminance Masking",
607 608
      "Luminance Masking", -1.0f, 1.0f, 0.0f,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
609
  gst_ffmpeg_add_pspec (pspec, config.lumi_masking, FALSE, mpeg, NULL);
610 611

  pspec = g_param_spec_float ("dark-masking", "Darkness Masking",
612 613
      "Darkness Masking", -1.0f, 1.0f, 0.0f,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
614
  gst_ffmpeg_add_pspec (pspec, config.dark_masking, FALSE, mpeg, NULL);
615 616 617

  pspec = g_param_spec_float ("temporal-cplx-masking",
      "Temporal Complexity Masking",
618 619
      "Temporal Complexity Masking", -1.0f, 1.0f, 0.0f,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
620
  gst_ffmpeg_add_pspec (pspec, config.temporal_cplx_masking, FALSE, mpeg, NULL);
621 622 623

  pspec = g_param_spec_float ("spatial-cplx-masking",
      "Spatial Complexity Masking",
624 625
      "Spatial Complexity Masking", -1.0f, 1.0f, 0.0f,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
626
  gst_ffmpeg_add_pspec (pspec, config.spatial_cplx_masking, FALSE, mpeg, NULL);
627 628

  pspec = g_param_spec_float ("p-masking", "P Block Masking",
629 630
      "P Block  Masking", -1.0f, 1.0f, 0.0f,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
631
  gst_ffmpeg_add_pspec (pspec, config.p_masking, FALSE, mpeg, NULL);
632 633 634 635

  pspec = g_param_spec_int ("dia-size",
      "Motion Estimation Diamond Size/Shape",
      "Motion Estimation Diamond Size/Shape",
636
      -2000, 2000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
637
  gst_ffmpeg_add_pspec (pspec, config.dia_size, FALSE, mpeg, NULL);
638 639 640 641

  pspec = g_param_spec_int ("pre-dia-size",
      "Motion Estimation Pre Pass Diamond Size/Shape",
      "Motion Estimation Diamond Size/Shape",
642
      -2000, 2000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
643
  gst_ffmpeg_add_pspec (pspec, config.pre_dia_size, FALSE, mpeg, NULL);
644 645 646 647

  pspec = g_param_spec_int ("last-predictor-count",
      "Last Predictor Count",
      "Amount of previous Motion Vector predictors",
648
      0, 2000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
649
  gst_ffmpeg_add_pspec (pspec, config.last_predictor_count, FALSE, mpeg, NULL);
650 651 652 653

  pspec = g_param_spec_enum ("pre-me",
      "Pre Pass for Motion Estimation",
      "Pre Pass for Motion Estimation",
654
      GST_TYPE_FFMPEG_PRE_ME, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
655
  gst_ffmpeg_add_pspec (pspec, config.pre_me, FALSE, mpeg, NULL);
656 657 658 659

  pspec = g_param_spec_int ("me-subpel-quality",
      "Motion Estimation Subpixel Quality",
      "Motion Estimation Subpixel Refinement Quality",
660
      0, 8, 8, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
661
  gst_ffmpeg_add_pspec (pspec, config.me_subpel_quality, FALSE, mpeg, NULL);
662 663 664 665

  pspec = g_param_spec_int ("me-range",
      "Motion Estimation Range",
      "Motion Estimation search range in subpel units",
666
      0, 16000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
667
  gst_ffmpeg_add_pspec (pspec, config.me_range, FALSE, mpeg, NULL);
668 669 670 671

  pspec = g_param_spec_int ("intra-quant-bias",
      "Intra Quantizer Bias",
      "Intra Quantizer Bias",
672 673
      -1000000, 1000000, FF_DEFAULT_QUANT_BIAS,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
674
  gst_ffmpeg_add_pspec (pspec, config.intra_quant_bias, FALSE, mpeg, NULL);
675 676 677 678

  pspec = g_param_spec_int ("inter-quant-bias",
      "Inter Quantizer Bias",
      "Inter Quantizer Bias",
679 680
      -1000000, 1000000, FF_DEFAULT_QUANT_BIAS,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
681
  gst_ffmpeg_add_pspec (pspec, config.inter_quant_bias, FALSE, mpeg, NULL);
682 683 684

  pspec = g_param_spec_int ("noise-reduction",
      "Noise Reduction",
685 686
      "Noise Reduction Strength", 0, 1000000, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
687
  gst_ffmpeg_add_pspec (pspec, config.noise_reduction, FALSE, mpeg, NULL);
688 689 690

  pspec = g_param_spec_int ("intra-dc-precision",
      "Intra DC precision",
691 692
      "Precision of the Intra DC coefficient - 8", 0, 16, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
693
  gst_ffmpeg_add_pspec (pspec, config.intra_dc_precision, FALSE, mpeg, NULL);
694 695 696 697

  /* TODO skipped coder_type, context_model, inter_threshold, scenechange_threshold */

  pspec = g_param_spec_flags ("flags", "Flags",
698 699
      "Flags", GST_TYPE_FFMPEG_FLAGS, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
700
  gst_ffmpeg_add_pspec (pspec, config.flags, FALSE, mpeg, NULL);
701 702

  pspec = g_param_spec_boolean ("interlaced", "Interlaced Material",
703
      "Interlaced Material", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
704
  gst_ffmpeg_add_pspec (pspec, interlaced, FALSE, mpeg, NULL);
705 706

  pspec = g_param_spec_int ("max-bframes", "Max B-Frames",
707 708
      "Maximum B-frames in a row", 0, FF_MAX_B_FRAMES, 0,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
709
  gst_ffmpeg_add_pspec (pspec, config.max_b_frames, FALSE, mpeg, NULL);
710 711 712

  pspec = g_param_spec_enum ("prediction-method", "Prediction Method",
      "Prediction Method",
713 714
      GST_TYPE_FFMPEG_PRED_METHOD, FF_PRED_LEFT,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
715
  gst_ffmpeg_add_pspec (pspec, config.prediction_method, FALSE, huffyuv, NULL);
716
  pspec = g_param_spec_int ("trellis", "Trellis Quantization",
717 718
      "Trellis RD quantization", 0, 1, 1,
      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
719
  gst_ffmpeg_add_pspec (pspec, config.trellis, FALSE, mpeg, NULL);
720 721 722 723 724 725 726
}

/* ==== END CONFIGURATION SECTION ==== */


/* return TRUE if property described by pspec applies to the codec with codec_id */
static gboolean
727
gst_ffmpeg_cfg_codec_has_pspec (enum CodecID codec_id, GParamSpec * pspec)
728 729
{
  GParamSpecData *qdata;
730
  gint *codec;
731 732 733 734 735 736
  gboolean ret = FALSE;

  qdata = g_param_spec_get_qdata (pspec, quark);

  /* check if excluded first */
  if ((codec = qdata->exclude_list)) {
737
    for (; *codec != CODEC_ID_NONE; ++codec) {
738 739 740 741 742 743 744
      if (*codec == codec_id)
        return FALSE;
    }
  }

  /* no include list means it is accepted */
  if ((codec = qdata->include_list)) {
745
    for (; *codec != CODEC_ID_NONE; ++codec) {
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
      if (*codec == codec_id)
        ret = TRUE;
    }
  } else {
    ret = TRUE;
  }

  return ret;
}

/* install all properties for klass that have been registered in property_list */
void
gst_ffmpeg_cfg_install_property (GstFFMpegEncClass * klass, guint base)
{
  GParamSpec *pspec;
  GList *list;
  gint prop_id;
  AVCodecContext *ctx;

  prop_id = base;
  g_return_if_fail (base > 0);

768
  ctx = avcodec_alloc_context ();
769 770 771 772 773 774 775 776 777 778 779
  if (ctx)
    avcodec_get_context_defaults (ctx);
  else
    g_warning ("could not get context");

  for (list = property_list; list; list = list->next) {
    pspec = G_PARAM_SPEC (list->data);
    if (gst_ffmpeg_cfg_codec_has_pspec (klass->in_plugin->id, pspec)) {
      /* 'clone' the paramspec for the various codecs,
       * since a single paramspec cannot be owned by distinct types */

780 781 782
      const gchar *name = g_param_spec_get_name (pspec);
      const gchar *nick = g_param_spec_get_nick (pspec);
      const gchar *blurb = g_param_spec_get_blurb (pspec);
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
      GParamSpecData *qdata = g_param_spec_get_qdata (pspec, quark);
      gint ctx_offset = 0;
      gboolean lavc_default;

      /* cannot obtain lavc default if no context */
      if (!ctx)
        lavc_default = FALSE;
      else {
        ctx_offset = qdata->offset - CONTEXT_CONFIG_OFFSET;
        /* safety check; is it really member of the avcodec context */
        if (ctx_offset < 0)
          lavc_default = FALSE;
        else
          lavc_default = qdata->lavc_default;
      }

      switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
800 801 802
        case G_TYPE_STRING:{
          GParamSpecString *pstring = G_PARAM_SPEC_STRING (pspec);

803
          pspec = g_param_spec_string (name, nick, blurb,
804 805
              lavc_default ? G_STRUCT_MEMBER (gchar *, ctx, ctx_offset)
              : pstring->default_value, pspec->flags);
806 807
          break;
        }
808 809 810
        case G_TYPE_INT:{
          GParamSpecInt *pint = G_PARAM_SPEC_INT (pspec);

811 812 813
          pspec = g_param_spec_int (name, nick, blurb,
              pint->minimum, pint->maximum,
              lavc_default ? G_STRUCT_MEMBER (gint, ctx, ctx_offset)
814
              : pint->default_value, pspec->flags);
815 816
          break;
        }
817 818 819
        case G_TYPE_UINT:{
          GParamSpecUInt *puint = G_PARAM_SPEC_UINT (pspec);

820
          pspec = g_param_spec_uint (name, nick, blurb,
821 822 823
              puint->minimum, puint->maximum,
              lavc_default ? G_STRUCT_MEMBER (guint, ctx, ctx_offset)
              : puint->default_value, pspec->flags);
824 825
          break;
        }
826 827 828
        case G_TYPE_ULONG:{
          GParamSpecULong *pulong = G_PARAM_SPEC_ULONG (pspec);

829 830 831
          pspec = g_param_spec_ulong (name, nick, blurb,
              pulong->minimum, pulong->maximum,
              lavc_default ? G_STRUCT_MEMBER (gulong, ctx, ctx_offset)
832
              : pulong->default_value, pspec->flags);
833 834
          break;
        }
835 836 837
        case G_TYPE_FLOAT:{
          GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (pspec);

838 839 840
          pspec = g_param_spec_float (name, nick, blurb,
              pfloat->minimum, pfloat->maximum,
              lavc_default ? G_STRUCT_MEMBER (gfloat, ctx, ctx_offset)
841
              : pfloat->default_value, pspec->flags);
842 843
          break;
        }
844 845 846
        case G_TYPE_BOOLEAN:{
          GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (pspec);

847 848
          pspec = g_param_spec_boolean (name, nick, blurb,
              lavc_default ? G_STRUCT_MEMBER (gboolean, ctx, ctx_offset)
849
              : pboolean->default_value, pspec->flags);
850 851 852 853
          break;
        }
        default:
          if (G_IS_PARAM_SPEC_ENUM (pspec)) {
854 855
            GParamSpecEnum *penum = G_PARAM_SPEC_ENUM (pspec);

856 857
            pspec = g_param_spec_enum (name, nick, blurb,
                pspec->value_type,
858
                lavc_default ? G_STRUCT_MEMBER (gint, ctx, ctx_offset)
859
                : penum->default_value, pspec->flags);
860
          } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
861 862
            GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (pspec);

863 864
            pspec = g_param_spec_flags (name, nick, blurb,
                pspec->value_type,
865
                lavc_default ? G_STRUCT_MEMBER (guint, ctx, ctx_offset)
866
                : pflags->default_value, pspec->flags);
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
          } else {
            g_critical ("%s does not yet support type %s", GST_FUNCTION,
                g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
            continue;
          }
          break;
      }
      g_param_spec_set_qdata (pspec, quark, qdata);
      g_object_class_install_property (G_OBJECT_CLASS (klass), prop_id, pspec);
      ++prop_id;
    }
  }

  if (ctx)
    av_free (ctx);
}

/* returns TRUE if it is a known property for this config system,
 * FALSE otherwise */
gboolean
gst_ffmpeg_cfg_set_property (GObject * object,
    const GValue * value, GParamSpec * pspec)
{
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (object);
  GParamSpecData *qdata;

  qdata = g_param_spec_get_qdata (pspec, quark);

  /* our param specs should have such qdata */
  if (!qdata)
    return FALSE;

  /* set the member using the offset, also mild type check based on size */
  switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
    case G_TYPE_BOOLEAN:
      g_return_val_if_fail (qdata->size == sizeof (gboolean), TRUE);
      G_STRUCT_MEMBER (gboolean, ffmpegenc, qdata->offset) =
          g_value_get_boolean (value);
      break;
    case G_TYPE_UINT:
      g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
      G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset) =
          g_value_get_uint (value);
      break;
    case G_TYPE_INT:
      g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
      G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset) =
          g_value_get_int (value);
      break;
    case G_TYPE_ULONG:
      g_return_val_if_fail (qdata->size == sizeof (gulong), TRUE);
      G_STRUCT_MEMBER (glong, ffmpegenc, qdata->offset) =
          g_value_get_ulong (value);
      break;
    case G_TYPE_FLOAT:
      g_return_val_if_fail (qdata->size == sizeof (gfloat), TRUE);
      G_STRUCT_MEMBER (gfloat, ffmpegenc, qdata->offset) =
          g_value_get_float (value);
      break;
    case G_TYPE_STRING:
927 928 929
      g_return_val_if_fail (qdata->size == sizeof (gchar *), TRUE);
      g_free (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset));
      G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset) =
930 931
          g_value_dup_string (value);
      break;
932
    default:                   /* must be enum, given the check above */
933 934 935
      if (G_IS_PARAM_SPEC_ENUM (pspec)) {
        g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
        G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset) =
936
            g_value_get_enum (value);
937 938 939 940
      } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
        g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
        G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset) =
            g_value_get_flags (value);
941 942
      } else {                  /* oops, bit lazy we don't cover this case yet */
        g_critical ("%s does not yet support type %s", GST_FUNCTION,
943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980
            g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
      }

      break;
  }

  return TRUE;
}

/* returns TRUE if it is a known property for this config system,
 * FALSE otherwise */
gboolean
gst_ffmpeg_cfg_get_property (GObject * object,
    GValue * value, GParamSpec * pspec)
{
  GstFFMpegEnc *ffmpegenc = (GstFFMpegEnc *) (object);
  GParamSpecData *qdata;

  qdata = g_param_spec_get_qdata (pspec, quark);

  /* our param specs should have such qdata */
  if (!qdata)
    return FALSE;

  /* get the member using the offset, also mild type check based on size */
  switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
    case G_TYPE_BOOLEAN:
      g_return_val_if_fail (qdata->size == sizeof (gboolean), TRUE);
      g_value_set_boolean (value,
          G_STRUCT_MEMBER (gboolean, ffmpegenc, qdata->offset));
      break;
    case G_TYPE_UINT:
      g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
      g_value_set_uint (value,
          G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset));
      break;
    case G_TYPE_INT:
      g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
981
      g_value_set_int (value, G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset));
982 983 984 985 986 987 988 989 990 991 992 993
      break;
    case G_TYPE_ULONG:
      g_return_val_if_fail (qdata->size == sizeof (gulong), TRUE);
      g_value_set_ulong (value,
          G_STRUCT_MEMBER (glong, ffmpegenc, qdata->offset));
      break;
    case G_TYPE_FLOAT:
      g_return_val_if_fail (qdata->size == sizeof (gfloat), TRUE);
      g_value_set_float (value,
          G_STRUCT_MEMBER (gfloat, ffmpegenc, qdata->offset));
      break;
    case G_TYPE_STRING:
994
      g_return_val_if_fail (qdata->size == sizeof (gchar *), TRUE);
995
      g_value_take_string (value,
996
          g_strdup (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset)));
997
      break;
998
    default:                   /* must be enum, given the check above */
999 1000 1001 1002 1003 1004 1005 1006
      if (G_IS_PARAM_SPEC_ENUM (pspec)) {
        g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
        g_value_set_enum (value,
            G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset));
      } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
        g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
        g_value_set_flags (value,
            G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset));
1007
      } else {                  /* oops, bit lazy we don't cover this case yet */
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
        g_critical ("%s does not yet support type %s", GST_FUNCTION,
            g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
      }
      break;
  }

  return TRUE;
}

void
gst_ffmpeg_cfg_set_defaults (GstFFMpegEnc * ffmpegenc)
{
  GParamSpec **pspecs;
  guint num_props, i;

  pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (ffmpegenc),
      &num_props);

  for (i = 0; i < num_props; ++i) {
1027
    GValue val = { 0, };
1028
    GParamSpec *pspec = pspecs[i];
1029

1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
    /* only touch those that are really ours; i.e. should have some qdata */
    if (!g_param_spec_get_qdata (pspec, quark))
      continue;
    g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
    g_param_value_set_default (pspec, &val);
    g_object_set_property (G_OBJECT (ffmpegenc),
        g_param_spec_get_name (pspec), &val);
    g_value_unset (&val);
  }

  g_free (pspecs);

}


void
gst_ffmpeg_cfg_fill_context (GstFFMpegEnc * ffmpegenc, AVCodecContext * context)
{
  GstFFMpegEncClass *klass
      = (GstFFMpegEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
  GParamSpec *pspec;
  GParamSpecData *qdata;
  GList *list;

  list = property_list;

  while (list) {
    gint context_offset;

    pspec = G_PARAM_SPEC (list->data);
    qdata = g_param_spec_get_qdata (pspec, quark);
    context_offset = qdata->offset - CONTEXT_CONFIG_OFFSET;
    if (gst_ffmpeg_cfg_codec_has_pspec (klass->in_plugin->id, pspec)
        && context_offset >= 0) {
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
      if (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_STRING) {
        /* make a copy for ffmpeg, it will likely free only some,
         * but in any case safer than a potential double free */
        G_STRUCT_MEMBER (gchar *, context, context_offset) =
            g_strdup (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset));
      } else {
        /* memcpy a bit heavy for a small copy,
         * but hardly part of 'inner loop' */
        memcpy (G_STRUCT_MEMBER_P (context, context_offset),
            G_STRUCT_MEMBER_P (ffmpegenc, qdata->offset), qdata->size);
      }
1075 1076 1077 1078
    }
    list = list->next;
  }
}
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100

void
gst_ffmpeg_cfg_finalize (GstFFMpegEnc * ffmpegenc)
{
  GParamSpec **pspecs;
  guint num_props, i;

  pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (ffmpegenc),
      &num_props);

  for (i = 0; i < num_props; ++i) {
    GParamSpec *pspec = pspecs[i];
    GParamSpecData *qdata;

    qdata = g_param_spec_get_qdata (pspec, quark);

    /* our param specs should have such qdata */
    if (!qdata)
      continue;

    switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
      case G_TYPE_STRING:
1101 1102 1103
        if (qdata->size == sizeof (gchar *)) {
          g_free (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset));
          G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset) = NULL;
1104 1105 1106 1107 1108 1109 1110 1111
        }
        break;
      default:
        break;
    }
  }
  g_free (pspecs);
}