a1863fded7c7c178ed73da28d45bdb1ac1e8eafa
[platform/upstream/gstreamer.git] / ext / libav / gstavcfg.c
1 /* GStreamer
2  *
3  * FFMpeg Configuration
4  *
5  * Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "gstav.h"
29 #include "gstavvidenc.h"
30 #include "gstavcfg.h"
31
32 #include <string.h>
33
34 /* some enums used in property declarations */
35
36 #define GST_TYPE_FFMPEG_PASS (gst_ffmpeg_pass_get_type ())
37 static GType
38 gst_ffmpeg_pass_get_type (void)
39 {
40   static GType ffmpeg_pass_type = 0;
41
42   if (!ffmpeg_pass_type) {
43     static const GEnumValue ffmpeg_passes[] = {
44       {0, "Constant Bitrate Encoding", "cbr"},
45       {CODEC_FLAG_QSCALE, "Constant Quantizer", "quant"},
46       {CODEC_FLAG_PASS1, "VBR Encoding - Pass 1", "pass1"},
47       {CODEC_FLAG_PASS2, "VBR Encoding - Pass 2", "pass2"},
48       {0, NULL, NULL},
49     };
50
51     ffmpeg_pass_type =
52         g_enum_register_static ("GstLibAVEncPass", ffmpeg_passes);
53   }
54
55   return ffmpeg_pass_type;
56 }
57
58 #if 0
59 /* some do not support 2-pass */
60 #define GST_TYPE_FFMPEG_LIM_PASS (gst_ffmpeg_lim_pass_get_type ())
61 static GType
62 gst_ffmpeg_lim_pass_get_type (void)
63 {
64   static GType ffmpeg_lim_pass_type = 0;
65
66   if (!ffmpeg_lim_pass_type) {
67     static const GEnumValue ffmpeg_lim_passes[] = {
68       {0, "Constant Bitrate Encoding", "cbr"},
69       {CODEC_FLAG_QSCALE, "Constant Quantizer", "quant"},
70       {0, NULL, NULL},
71     };
72
73     ffmpeg_lim_pass_type =
74         g_enum_register_static ("GstLibAVEncLimPass", ffmpeg_lim_passes);
75   }
76
77   return ffmpeg_lim_pass_type;
78 }
79 #endif
80
81 #define GST_TYPE_FFMPEG_MB_DECISION (gst_ffmpeg_mb_decision_get_type ())
82 static GType
83 gst_ffmpeg_mb_decision_get_type (void)
84 {
85   static GType ffmpeg_mb_decision_type = 0;
86
87   if (!ffmpeg_mb_decision_type) {
88     static const GEnumValue ffmpeg_mb_decisions[] = {
89       {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       {FF_MB_DECISION_RD, "Rate Distortion", "rd"},
93       {0, NULL, NULL},
94     };
95
96     ffmpeg_mb_decision_type =
97         g_enum_register_static ("GstLibAVEncMBDecision", ffmpeg_mb_decisions);
98   }
99
100   return ffmpeg_mb_decision_type;
101 }
102
103 #define GST_TYPE_FFMPEG_CMP_FUNCTION (gst_ffmpeg_mb_cmp_get_type ())
104 static GType
105 gst_ffmpeg_mb_cmp_get_type (void)
106 {
107   static GType ffmpeg_mb_cmp_type = 0;
108
109   /* TODO fill out remaining values */
110   if (!ffmpeg_mb_cmp_type) {
111     static const GEnumValue ffmpeg_mb_cmps[] = {
112       {FF_CMP_SAD, "Sum of Absolute Differences", "sad"},
113       {FF_CMP_SSE, "Sum of Squared Errors", "sse"},
114       {FF_CMP_SATD, "Sum of Absolute Hadamard Transformed Differences", "satd"},
115       {FF_CMP_DCT, "Sum of Absolute DCT Transformed Differences", "dct"},
116       {FF_CMP_PSNR, "Sum of the Squared Quantization Errors", "psnr"},
117       {FF_CMP_BIT, "Sum of the Bits needed for the block", "bit"},
118       {FF_CMP_RD, "Rate Distortion optimal", "rd"},
119       {FF_CMP_ZERO, "ZERO", "zero"},
120       {FF_CMP_VSAD, "VSAD", "vsad"},
121       {FF_CMP_VSSE, "VSSE", "vsse"},
122 #if 0
123 /* economize a bit for now */
124       {FF_CMP_NSSE, "NSSE", "nsse"},
125       {FF_CMP_W53, "W53", "w53"},
126       {FF_CMP_W97, "W97", "w97"},
127 #endif
128       {0, NULL, NULL},
129     };
130
131     ffmpeg_mb_cmp_type =
132         g_enum_register_static ("GstLibAVCMPFunction", ffmpeg_mb_cmps);
133   }
134
135   return ffmpeg_mb_cmp_type;
136 }
137
138 #define GST_TYPE_FFMPEG_DCT_ALGO (gst_ffmpeg_dct_algo_get_type ())
139 static GType
140 gst_ffmpeg_dct_algo_get_type (void)
141 {
142   static GType ffmpeg_dct_algo_type = 0;
143
144   if (!ffmpeg_dct_algo_type) {
145     static const GEnumValue ffmpeg_dct_algos[] = {
146       {FF_DCT_AUTO, "Automatically select a good one", "auto"},
147       {FF_DCT_FASTINT, "Fast Integer", "fastint"},
148       {FF_DCT_INT, "Accurate Integer", "int"},
149       {FF_DCT_MMX, "MMX", "mmx"},
150       {FF_DCT_ALTIVEC, "ALTIVEC", "altivec"},
151       {FF_DCT_FAAN, "FAAN", "faan"},
152       {0, NULL, NULL},
153     };
154
155     ffmpeg_dct_algo_type =
156         g_enum_register_static ("GstLibAVDCTAlgo", ffmpeg_dct_algos);
157   }
158
159   return ffmpeg_dct_algo_type;
160 }
161
162 #define GST_TYPE_FFMPEG_IDCT_ALGO (gst_ffmpeg_idct_algo_get_type ())
163 static GType
164 gst_ffmpeg_idct_algo_get_type (void)
165 {
166   static GType ffmpeg_idct_algo_type = 0;
167
168   if (!ffmpeg_idct_algo_type) {
169     static const GEnumValue ffmpeg_idct_algos[] = {
170       {FF_IDCT_AUTO, "Automatically select a good one", "auto"},
171       {FF_IDCT_INT, "JPEG reference Integer", "int"},
172       {FF_IDCT_SIMPLE, "Simple", "simple"},
173       {FF_IDCT_SIMPLEMMX, "Simple MMX", "simplemmx"},
174       {FF_IDCT_ARM, "ARM", "arm"},
175       {FF_IDCT_ALTIVEC, "Altivec", "altivec"},
176       {FF_IDCT_SIMPLEARM, "Simple ARM", "simplearm"},
177       {FF_IDCT_XVID, "XVID", "xvid"},
178       {FF_IDCT_SIMPLEARMV5TE, "Simple ARMV5TE", "simplearmv5te"},
179       {FF_IDCT_SIMPLEARMV6, "Simple ARMV6", "simplearmv6"},
180       {FF_IDCT_FAAN, "FAAN", "faan"},
181       {FF_IDCT_SIMPLENEON, "Simple NEON", "simpleneon"},
182       {0, NULL, NULL},
183     };
184
185     ffmpeg_idct_algo_type =
186         g_enum_register_static ("GstLibAVIDCTAlgo", ffmpeg_idct_algos);
187   }
188
189   return ffmpeg_idct_algo_type;
190 }
191
192 #define GST_TYPE_FFMPEG_QUANT_TYPE (gst_ffmpeg_quant_type_get_type ())
193 static GType
194 gst_ffmpeg_quant_type_get_type (void)
195 {
196   static GType ffmpeg_quant_type_type = 0;
197
198   if (!ffmpeg_quant_type_type) {
199     static const GEnumValue ffmpeg_quant_types[] = {
200       {0, "H263 quantization", "h263"},
201       {1, "MPEG quantization", "mpeg"},
202       {0, NULL, NULL},
203     };
204
205     ffmpeg_quant_type_type =
206         g_enum_register_static ("GstLibAVEncQuantTypes", ffmpeg_quant_types);
207   }
208
209   return ffmpeg_quant_type_type;
210 }
211
212 #define GST_TYPE_FFMPEG_PRE_ME (gst_ffmpeg_pre_me_get_type ())
213 static GType
214 gst_ffmpeg_pre_me_get_type (void)
215 {
216   static GType ffmpeg_pre_me_type = 0;
217
218   if (!ffmpeg_pre_me_type) {
219     static const GEnumValue ffmpeg_pre_mes[] = {
220       {0, "Disabled", "off"},
221       {1, "Only after I-frames", "key"},
222       {2, "Always", "all"},
223       {0, NULL, NULL}
224     };
225
226     ffmpeg_pre_me_type =
227         g_enum_register_static ("GstLibAVEncPreME", ffmpeg_pre_mes);
228   }
229
230   return ffmpeg_pre_me_type;
231 }
232
233 #define GST_TYPE_FFMPEG_PRED_METHOD (gst_ffmpeg_pred_method_get_type ())
234 static GType
235 gst_ffmpeg_pred_method_get_type (void)
236 {
237   static GType ffmpeg_pred_method = 0;
238
239   if (!ffmpeg_pred_method) {
240     static const GEnumValue ffmpeg_pred_methods[] = {
241       {FF_PRED_LEFT, "Left", "left"},
242       {FF_PRED_PLANE, "Plane", "plane"},
243       {FF_PRED_MEDIAN, "Median", "median"},
244       {0, NULL, NULL}
245     };
246
247     ffmpeg_pred_method =
248         g_enum_register_static ("GstLibAVEncPredMethod", ffmpeg_pred_methods);
249   }
250
251   return ffmpeg_pred_method;
252 }
253
254 #define GST_TYPE_FFMPEG_FLAGS (gst_ffmpeg_flags_get_type())
255 static GType
256 gst_ffmpeg_flags_get_type (void)
257 {
258   static GType ffmpeg_flags_type = 0;
259
260   /* FIXME: This needs some serious resyncing with avcodec.h */
261   if (!ffmpeg_flags_type) {
262     static const GFlagsValue ffmpeg_flags[] = {
263       {CODEC_FLAG_QSCALE, "Use fixed qscale", "qscale"},
264       {CODEC_FLAG_4MV, "Allow 4 MV per MB", "4mv"},
265       {CODEC_FLAG_QPEL, "Quartel Pel Motion Compensation", "qpel"},
266       {CODEC_FLAG_GMC, "GMC", "gmc"},
267       {CODEC_FLAG_MV0, "Always try a MB with MV (0,0)", "mv0"},
268       {CODEC_FLAG_LOOP_FILTER, "Loop filter", "loop-filter"},
269       {CODEC_FLAG_GRAY, "Only decode/encode grayscale", "gray"},
270       {CODEC_FLAG_NORMALIZE_AQP,
271           "Normalize Adaptive Quantization (masking, etc)", "aqp"},
272       {CODEC_FLAG_GLOBAL_HEADER,
273             "Global headers in extradata instead of every keyframe",
274           "global-headers"},
275       {CODEC_FLAG_AC_PRED, "H263 Advanced Intra Coding / MPEG4 AC prediction",
276           "aic"},
277       {CODEC_FLAG_CLOSED_GOP, "Closed GOP", "closedgop"},
278       {0, NULL, NULL},
279     };
280
281     ffmpeg_flags_type = g_flags_register_static ("GstLibAVFlags", ffmpeg_flags);
282   }
283
284   return ffmpeg_flags_type;
285 }
286
287 /* provides additional info to attach to a property */
288
289 typedef struct _GParamSpecData GParamSpecData;
290
291 struct _GParamSpecData
292 {
293   /* offset of member in the element struct that stores the property */
294   guint offset;
295
296   /* size of the above member */
297   guint size;
298
299   /* if TRUE, try to get the default from lavc and ignore the paramspec default */
300   gboolean lavc_default;
301
302   /* these lists are arrays terminated by AV_CODEC_ID_NONE entry:
303    * property applies to a codec if it's not in the exclude_list
304    * and in exclude_list (or the latter is NULL) */
305   gint *include_list;
306   gint *exclude_list;
307 };
308
309 /* properties whose member offset is higher than the config base
310  * can be copied directly at context configuration time;
311  * and can also retrieve a default value from lavc */
312 #define CONTEXT_CONFIG_OFFSET   G_STRUCT_OFFSET (GstFFMpegVidEnc, config)
313
314 /* additional info is named pointer specified by the quark */
315 static GQuark quark;
316
317 /* central configuration store:
318  * list of GParamSpec's with GParamSpecData attached as named pointer */
319 static GList *property_list;
320
321 /* add the GParamSpec pspec to store with GParamSpecData
322  * constructed from struct_type, member, default and include and exclude */
323 #define gst_ffmpeg_add_pspec_full(pspec, store, struct_type, member,    \
324     default, include, exclude)                                          \
325 G_STMT_START {                                                          \
326   GParamSpecData *_qdata = g_new0 (GParamSpecData, 1);                  \
327   GstFFMpegVidEnc _enc;                                                    \
328   _qdata->offset = G_STRUCT_OFFSET (struct_type, member);               \
329   _qdata->size = sizeof (_enc.member);                                  \
330   _qdata->lavc_default = default;                                       \
331   _qdata->include_list = include;                                       \
332   _qdata->exclude_list = exclude;                                       \
333   g_param_spec_set_qdata_full (pspec, quark, _qdata, g_free);           \
334   store = g_list_append (store, pspec);                                 \
335 } G_STMT_END
336
337 #define gst_ffmpeg_add_pspec(pspec, member, default, include, exclude)       \
338   gst_ffmpeg_add_pspec_full (pspec, property_list, GstFFMpegVidEnc, member,     \
339       default, include, exclude)
340
341 /* ==== BEGIN CONFIGURATION SECTION ==== */
342
343 /* some typical include and exclude lists; modify and/or add where needed */
344
345 static gint mpeg[] = {
346   AV_CODEC_ID_MPEG4,
347   AV_CODEC_ID_MSMPEG4V1,
348   AV_CODEC_ID_MSMPEG4V2,
349   AV_CODEC_ID_MSMPEG4V3,
350   AV_CODEC_ID_MPEG1VIDEO,
351   AV_CODEC_ID_MPEG2VIDEO,
352   AV_CODEC_ID_H263P,
353   AV_CODEC_ID_FLV1,
354   AV_CODEC_ID_H263,
355   AV_CODEC_ID_NONE
356 };
357
358 static gint huffyuv[] = {
359   AV_CODEC_ID_HUFFYUV,
360   AV_CODEC_ID_FFVHUFF,
361   AV_CODEC_ID_NONE
362 };
363
364 /* Properties should be added here for registration into the config store.
365  * Note that some may occur more than once, with different include/exclude lists,
366  * as some may require different defaults for different codecs,
367  * or some may have slightly varying enum-types with more or less options.
368  * The enum-types themselves should be declared above. */
369 void
370 gst_ffmpeg_cfg_init (void)
371 {
372   GParamSpec *pspec;
373
374   /* initialize global config vars */
375   quark = g_quark_from_static_string ("ffmpeg-cfg-param-spec-data");
376   property_list = NULL;
377
378   /* list properties here */
379   pspec = g_param_spec_enum ("pass", "Encoding pass/type",
380       "Encoding pass/type", GST_TYPE_FFMPEG_PASS, 0,
381       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
382   gst_ffmpeg_add_pspec (pspec, pass, FALSE, mpeg, NULL);
383
384   pspec = g_param_spec_float ("quantizer", "Constant Quantizer",
385       "Constant Quantizer", 0, 30, 0.01f,
386       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
387   gst_ffmpeg_add_pspec (pspec, quantizer, FALSE, mpeg, NULL);
388
389   pspec = g_param_spec_string ("multipass-cache-file", "Multipass Cache File",
390       "Filename for multipass cache file", "stats.log",
391       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
392   gst_ffmpeg_add_pspec (pspec, filename, FALSE, mpeg, NULL);
393
394   pspec = g_param_spec_int ("bitrate-tolerance", "Bitrate Tolerance",
395       "Number of bits the bitstream is allowed to diverge from the reference",
396       0, 100000000, 8000000, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
397   gst_ffmpeg_add_pspec (pspec, config.bit_rate_tolerance, FALSE, mpeg, NULL);
398
399   pspec = g_param_spec_enum ("mb-decision", "Macroblock Decision",
400       "Macroblok Decision Mode",
401       GST_TYPE_FFMPEG_MB_DECISION, FF_CMP_SAD,
402       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
403   gst_ffmpeg_add_pspec (pspec, config.mb_decision, FALSE, mpeg, NULL);
404
405   pspec = g_param_spec_enum ("mb-cmp", "Macroblock Compare Function",
406       "Macroblok Compare Function",
407       GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
408       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
409   gst_ffmpeg_add_pspec (pspec, config.mb_cmp, FALSE, mpeg, NULL);
410
411   pspec =
412       g_param_spec_enum ("me-pre-cmp",
413       "Motion Estimation Pre Pass Compare Function",
414       "Motion Estimation Pre Pass Compare Function",
415       GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
416       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
417   gst_ffmpeg_add_pspec (pspec, config.me_pre_cmp, FALSE, mpeg, NULL);
418
419   pspec = g_param_spec_enum ("me-cmp", "Motion Estimation Compare Function",
420       "Motion Estimation Compare Function",
421       GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
422       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
423   gst_ffmpeg_add_pspec (pspec, config.me_cmp, FALSE, mpeg, NULL);
424
425   pspec = g_param_spec_enum ("me-sub-cmp",
426       "Subpixel Motion Estimation Compare Function",
427       "Subpixel Motion Estimation Compare Function",
428       GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_SAD,
429       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
430   gst_ffmpeg_add_pspec (pspec, config.me_sub_cmp, FALSE, mpeg, NULL);
431
432   pspec = g_param_spec_enum ("ildct-cmp", "Interlaced DCT Compare Function",
433       "Interlaced DCT Compare Function",
434       GST_TYPE_FFMPEG_CMP_FUNCTION, FF_CMP_VSAD,
435       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
436   gst_ffmpeg_add_pspec (pspec, config.ildct_cmp, FALSE, mpeg, NULL);
437
438   pspec = g_param_spec_enum ("dct-algo", "DCT Algorithm",
439       "DCT Algorithm",
440       GST_TYPE_FFMPEG_DCT_ALGO, FF_DCT_AUTO,
441       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
442   gst_ffmpeg_add_pspec (pspec, config.dct_algo, FALSE, mpeg, NULL);
443
444   pspec = g_param_spec_enum ("idct-algo", "IDCT Algorithm",
445       "IDCT Algorithm",
446       GST_TYPE_FFMPEG_IDCT_ALGO, FF_IDCT_AUTO,
447       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
448   gst_ffmpeg_add_pspec (pspec, config.idct_algo, FALSE, mpeg, NULL);
449
450   pspec = g_param_spec_enum ("quant-type", "Quantizer Type",
451       "Quantizer Type", GST_TYPE_FFMPEG_QUANT_TYPE, 0,
452       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
453   gst_ffmpeg_add_pspec (pspec, config.mpeg_quant, FALSE, mpeg, NULL);
454
455   pspec = g_param_spec_int ("qmin", "Minimum Quantizer",
456       "Minimum Quantizer", 1, 31, 2,
457       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
458   gst_ffmpeg_add_pspec (pspec, config.qmin, FALSE, mpeg, NULL);
459
460   pspec = g_param_spec_int ("qmax", "Maximum Quantizer",
461       "Maximum Quantizer", 1, 31, 31,
462       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
463   gst_ffmpeg_add_pspec (pspec, config.qmax, FALSE, mpeg, NULL);
464
465   pspec = g_param_spec_int ("max-qdiff", "Maximum Quantizer Difference",
466       "Maximum Quantizer Difference between frames",
467       1, 31, 3, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
468   gst_ffmpeg_add_pspec (pspec, config.max_qdiff, FALSE, mpeg, NULL);
469
470   pspec = g_param_spec_int ("lmin", "Minimum Lagrange Multiplier",
471       "Minimum Lagrange Multiplier", 1, 31, 2,
472       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
473   gst_ffmpeg_add_pspec (pspec, lmin, FALSE, mpeg, NULL);
474
475   pspec = g_param_spec_int ("lmax", "Maximum Lagrange Multiplier",
476       "Maximum Lagrange Multiplier", 1, 31, 31,
477       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
478   gst_ffmpeg_add_pspec (pspec, lmax, FALSE, mpeg, NULL);
479
480   pspec = g_param_spec_float ("qcompress", "Quantizer Change",
481       "Quantizer Change between easy and hard scenes",
482       0, 1.0f, 0.5f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
483   gst_ffmpeg_add_pspec (pspec, config.qcompress, FALSE, mpeg, NULL);
484
485   pspec = g_param_spec_float ("qblur", "Quantizer Smoothing",
486       "Quantizer Smoothing over time", 0, 1.0f, 0.5f,
487       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
488   gst_ffmpeg_add_pspec (pspec, config.qblur, FALSE, mpeg, NULL);
489
490   pspec = g_param_spec_float ("rc-qsquish", "Ratecontrol Limiting Method",
491       "0 means limit by clipping, otherwise use nice continuous function",
492       0, 99.0f, 1.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
493   gst_ffmpeg_add_pspec (pspec, config.rc_qsquish, FALSE, mpeg, NULL);
494
495   pspec = g_param_spec_float ("rc-qmod-amp", "Ratecontrol Mod",
496       "Ratecontrol Mod", 0, 99.0f, 0,
497       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
498   gst_ffmpeg_add_pspec (pspec, config.rc_qmod_amp, FALSE, mpeg, NULL);
499
500   pspec = g_param_spec_int ("rc-qmod-freq", "Ratecontrol Freq",
501       "Ratecontrol Freq", 0, 0, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
502   gst_ffmpeg_add_pspec (pspec, config.rc_qmod_freq, FALSE, mpeg, NULL);
503
504   pspec = g_param_spec_int ("rc-buffer-size", "Ratecontrol Buffer Size",
505       "Decoder bitstream buffer size", 0, G_MAXINT, 0,
506       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
507   gst_ffmpeg_add_pspec (pspec, config.rc_buffer_size, FALSE, mpeg, NULL);
508
509   pspec =
510       g_param_spec_float ("rc-buffer-aggressivity",
511       "Ratecontrol Buffer Aggressivity", "Ratecontrol Buffer Aggressivity", 0,
512       99.0f, 1.0f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
513   gst_ffmpeg_add_pspec (pspec, config.rc_buffer_aggressivity, FALSE, mpeg,
514       NULL);
515
516 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT (57, 3, 0)
517   pspec = g_param_spec_int ("rc-max-rate", "Ratecontrol Maximum Bitrate",
518       "Ratecontrol Maximum Bitrate", 0, G_MAXINT, 0,
519       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
520 #else
521   pspec = g_param_spec_int64 ("rc-max-rate", "Ratecontrol Maximum Bitrate",
522       "Ratecontrol Maximum Bitrate", 0, G_MAXINT64, 0,
523       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
524 #endif
525   gst_ffmpeg_add_pspec (pspec, config.rc_max_rate, FALSE, mpeg, NULL);
526
527   pspec = g_param_spec_int64 ("rc-min-rate", "Ratecontrol Minimum Bitrate",
528       "Ratecontrol Minimum Bitrate", 0, G_MAXINT64, 0,
529       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
530   gst_ffmpeg_add_pspec (pspec, config.rc_min_rate, FALSE, mpeg, NULL);
531
532   pspec =
533       g_param_spec_float ("rc-initial-cplx",
534       "Initial Complexity for Pass 1 Ratecontrol",
535       "Initial Complexity for Pass 1 Ratecontrol", 0, 9999999.0f, 0,
536       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
537   gst_ffmpeg_add_pspec (pspec, config.rc_initial_cplx, FALSE, mpeg, NULL);
538
539   pspec = g_param_spec_string ("rc-eq", "Ratecontrol Equation",
540       "Ratecontrol Equation", "tex^qComp",
541       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
542   gst_ffmpeg_add_pspec (pspec, config.rc_eq, FALSE, mpeg, NULL);
543
544   pspec = g_param_spec_float ("b-quant-factor", "B-Quantizer Factor",
545       "Factor in B-Frame Quantizer Computation",
546       -31.0f, 31.0f, 1.25f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
547   gst_ffmpeg_add_pspec (pspec, config.b_quant_factor, FALSE, mpeg, NULL);
548
549   pspec = g_param_spec_float ("b-quant-offset", "B-Quantizer Offset",
550       "Offset in B-Frame Quantizer Computation",
551       0.0f, 31.0f, 1.25f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
552   gst_ffmpeg_add_pspec (pspec, config.b_quant_offset, FALSE, mpeg, NULL);
553
554   pspec = g_param_spec_float ("i-quant-factor", "I-Quantizer Factor",
555       "Factor in P-Frame Quantizer Computation",
556       -31.0f, 31.0f, 0.8f, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
557   gst_ffmpeg_add_pspec (pspec, config.i_quant_factor, FALSE, mpeg, NULL);
558
559   pspec = g_param_spec_float ("i-quant-offset", "I-Quantizer Offset",
560       "Offset in P-Frame Quantizer Computation",
561       0.0f, 31.0f, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
562   gst_ffmpeg_add_pspec (pspec, config.i_quant_offset, FALSE, mpeg, NULL);
563
564   /* note overlap with gop-size; 0 means do not override */
565   pspec = g_param_spec_int ("max-key-interval", "Maximum Key Interval",
566       "Maximum number of frames between two keyframes (< 0 is in sec)",
567       -100, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
568   gst_ffmpeg_add_pspec (pspec, max_key_interval, FALSE, mpeg, NULL);
569
570   pspec = g_param_spec_float ("lumi-masking", "Luminance Masking",
571       "Luminance Masking", -1.0f, 1.0f, 0.0f,
572       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
573   gst_ffmpeg_add_pspec (pspec, config.lumi_masking, FALSE, mpeg, NULL);
574
575   pspec = g_param_spec_float ("dark-masking", "Darkness Masking",
576       "Darkness Masking", -1.0f, 1.0f, 0.0f,
577       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
578   gst_ffmpeg_add_pspec (pspec, config.dark_masking, FALSE, mpeg, NULL);
579
580   pspec = g_param_spec_float ("temporal-cplx-masking",
581       "Temporal Complexity Masking",
582       "Temporal Complexity Masking", -1.0f, 1.0f, 0.0f,
583       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
584   gst_ffmpeg_add_pspec (pspec, config.temporal_cplx_masking, FALSE, mpeg, NULL);
585
586   pspec = g_param_spec_float ("spatial-cplx-masking",
587       "Spatial Complexity Masking",
588       "Spatial Complexity Masking", -1.0f, 1.0f, 0.0f,
589       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
590   gst_ffmpeg_add_pspec (pspec, config.spatial_cplx_masking, FALSE, mpeg, NULL);
591
592   pspec = g_param_spec_float ("p-masking", "P Block Masking",
593       "P Block  Masking", -1.0f, 1.0f, 0.0f,
594       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
595   gst_ffmpeg_add_pspec (pspec, config.p_masking, FALSE, mpeg, NULL);
596
597   pspec = g_param_spec_int ("dia-size",
598       "Motion Estimation Diamond Size/Shape",
599       "Motion Estimation Diamond Size/Shape",
600       -2000, 2000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
601   gst_ffmpeg_add_pspec (pspec, config.dia_size, FALSE, mpeg, NULL);
602
603   pspec = g_param_spec_int ("pre-dia-size",
604       "Motion Estimation Pre Pass Diamond Size/Shape",
605       "Motion Estimation Diamond Size/Shape",
606       -2000, 2000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
607   gst_ffmpeg_add_pspec (pspec, config.pre_dia_size, FALSE, mpeg, NULL);
608
609   pspec = g_param_spec_int ("last-predictor-count",
610       "Last Predictor Count",
611       "Amount of previous Motion Vector predictors",
612       0, 2000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
613   gst_ffmpeg_add_pspec (pspec, config.last_predictor_count, FALSE, mpeg, NULL);
614
615   pspec = g_param_spec_enum ("pre-me",
616       "Pre Pass for Motion Estimation",
617       "Pre Pass for Motion Estimation",
618       GST_TYPE_FFMPEG_PRE_ME, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
619   gst_ffmpeg_add_pspec (pspec, config.pre_me, FALSE, mpeg, NULL);
620
621   pspec = g_param_spec_int ("me-subpel-quality",
622       "Motion Estimation Subpixel Quality",
623       "Motion Estimation Subpixel Refinement Quality",
624       0, 8, 8, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
625   gst_ffmpeg_add_pspec (pspec, config.me_subpel_quality, FALSE, mpeg, NULL);
626
627   pspec = g_param_spec_int ("me-range",
628       "Motion Estimation Range",
629       "Motion Estimation search range in subpel units",
630       0, 16000, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
631   gst_ffmpeg_add_pspec (pspec, config.me_range, FALSE, mpeg, NULL);
632
633   pspec = g_param_spec_int ("intra-quant-bias",
634       "Intra Quantizer Bias",
635       "Intra Quantizer Bias",
636       -1000000, 1000000, FF_DEFAULT_QUANT_BIAS,
637       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
638   gst_ffmpeg_add_pspec (pspec, config.intra_quant_bias, FALSE, mpeg, NULL);
639
640   pspec = g_param_spec_int ("inter-quant-bias",
641       "Inter Quantizer Bias",
642       "Inter Quantizer Bias",
643       -1000000, 1000000, FF_DEFAULT_QUANT_BIAS,
644       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
645   gst_ffmpeg_add_pspec (pspec, config.inter_quant_bias, FALSE, mpeg, NULL);
646
647   pspec = g_param_spec_int ("noise-reduction",
648       "Noise Reduction",
649       "Noise Reduction Strength", 0, 1000000, 0,
650       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
651   gst_ffmpeg_add_pspec (pspec, config.noise_reduction, FALSE, mpeg, NULL);
652
653   pspec = g_param_spec_int ("intra-dc-precision",
654       "Intra DC precision",
655       "Precision of the Intra DC coefficient - 8", 0, 16, 0,
656       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
657   gst_ffmpeg_add_pspec (pspec, config.intra_dc_precision, FALSE, mpeg, NULL);
658
659   /* TODO skipped coder_type, context_model, inter_threshold, scenechange_threshold */
660
661   pspec = g_param_spec_flags ("flags", "Flags",
662       "Flags", GST_TYPE_FFMPEG_FLAGS, 0,
663       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
664   gst_ffmpeg_add_pspec (pspec, config.flags, FALSE, mpeg, NULL);
665
666   pspec = g_param_spec_boolean ("interlaced", "Interlaced Material",
667       "Interlaced Material", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
668   gst_ffmpeg_add_pspec (pspec, interlaced, FALSE, mpeg, NULL);
669
670   pspec = g_param_spec_int ("max-bframes", "Max B-Frames",
671       "Maximum B-frames in a row", 0, INT_MAX, 0,
672       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
673   gst_ffmpeg_add_pspec (pspec, config.max_b_frames, FALSE, mpeg, NULL);
674
675   pspec = g_param_spec_enum ("prediction-method", "Prediction Method",
676       "Prediction Method",
677       GST_TYPE_FFMPEG_PRED_METHOD, FF_PRED_LEFT,
678       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
679   gst_ffmpeg_add_pspec (pspec, config.prediction_method, FALSE, huffyuv, NULL);
680   pspec = g_param_spec_int ("trellis", "Trellis Quantization",
681       "Trellis RD quantization", 0, 1, 1,
682       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
683   gst_ffmpeg_add_pspec (pspec, config.trellis, FALSE, mpeg, NULL);
684 }
685
686 /* ==== END CONFIGURATION SECTION ==== */
687
688
689 /* return TRUE if property described by pspec applies to the codec with codec_id */
690 static gboolean
691 gst_ffmpeg_cfg_codec_has_pspec (enum AVCodecID codec_id, GParamSpec * pspec)
692 {
693   GParamSpecData *qdata;
694   gint *codec;
695   gboolean ret = FALSE;
696
697   qdata = g_param_spec_get_qdata (pspec, quark);
698
699   /* check if excluded first */
700   if ((codec = qdata->exclude_list)) {
701     for (; *codec != AV_CODEC_ID_NONE; ++codec) {
702       if (*codec == codec_id)
703         return FALSE;
704     }
705   }
706
707   /* no include list means it is accepted */
708   if ((codec = qdata->include_list)) {
709     for (; *codec != AV_CODEC_ID_NONE; ++codec) {
710       if (*codec == codec_id)
711         ret = TRUE;
712     }
713   } else {
714     ret = TRUE;
715   }
716
717   return ret;
718 }
719
720 /* install all properties for klass that have been registered in property_list */
721 void
722 gst_ffmpeg_cfg_install_property (GstFFMpegVidEncClass * klass, guint base)
723 {
724   GParamSpec *pspec;
725   GList *list;
726   gint prop_id;
727   AVCodecContext *ctx;
728
729   prop_id = base;
730   g_return_if_fail (base > 0);
731
732   ctx = avcodec_alloc_context3 (klass->in_plugin);
733   if (!ctx)
734     g_warning ("could not get context");
735
736   for (list = property_list; list; list = list->next) {
737     pspec = G_PARAM_SPEC (list->data);
738     if (gst_ffmpeg_cfg_codec_has_pspec (klass->in_plugin->id, pspec)) {
739       /* 'clone' the paramspec for the various codecs,
740        * since a single paramspec cannot be owned by distinct types */
741
742       const gchar *name = g_param_spec_get_name (pspec);
743       const gchar *nick = g_param_spec_get_nick (pspec);
744       const gchar *blurb = g_param_spec_get_blurb (pspec);
745       GParamSpecData *qdata = g_param_spec_get_qdata (pspec, quark);
746       gint ctx_offset = 0;
747       gboolean lavc_default;
748
749       /* cannot obtain lavc default if no context */
750       if (!ctx)
751         lavc_default = FALSE;
752       else {
753         ctx_offset = qdata->offset - CONTEXT_CONFIG_OFFSET;
754         /* safety check; is it really member of the avcodec context */
755         if (ctx_offset < 0)
756           lavc_default = FALSE;
757         else
758           lavc_default = qdata->lavc_default;
759       }
760
761       switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
762         case G_TYPE_STRING:{
763           GParamSpecString *pstring = G_PARAM_SPEC_STRING (pspec);
764
765           pspec = g_param_spec_string (name, nick, blurb,
766               lavc_default ? G_STRUCT_MEMBER (gchar *, ctx, ctx_offset)
767               : pstring->default_value, pspec->flags);
768           break;
769         }
770         case G_TYPE_INT:{
771           GParamSpecInt *pint = G_PARAM_SPEC_INT (pspec);
772
773           pspec = g_param_spec_int (name, nick, blurb,
774               pint->minimum, pint->maximum,
775               lavc_default ? G_STRUCT_MEMBER (gint, ctx, ctx_offset)
776               : pint->default_value, pspec->flags);
777           break;
778         }
779         case G_TYPE_INT64:{
780           GParamSpecInt64 *pint = G_PARAM_SPEC_INT64 (pspec);
781
782           pspec = g_param_spec_int64 (name, nick, blurb,
783               pint->minimum, pint->maximum,
784               lavc_default ? G_STRUCT_MEMBER (gint64, ctx, ctx_offset)
785               : pint->default_value, pspec->flags);
786           break;
787         }
788         case G_TYPE_UINT:{
789           GParamSpecUInt *puint = G_PARAM_SPEC_UINT (pspec);
790
791           pspec = g_param_spec_uint (name, nick, blurb,
792               puint->minimum, puint->maximum,
793               lavc_default ? G_STRUCT_MEMBER (guint, ctx, ctx_offset)
794               : puint->default_value, pspec->flags);
795           break;
796         }
797         case G_TYPE_FLOAT:{
798           GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT (pspec);
799
800           pspec = g_param_spec_float (name, nick, blurb,
801               pfloat->minimum, pfloat->maximum,
802               lavc_default ? G_STRUCT_MEMBER (gfloat, ctx, ctx_offset)
803               : pfloat->default_value, pspec->flags);
804           break;
805         }
806         case G_TYPE_BOOLEAN:{
807           GParamSpecBoolean *pboolean = G_PARAM_SPEC_BOOLEAN (pspec);
808
809           pspec = g_param_spec_boolean (name, nick, blurb,
810               lavc_default ? G_STRUCT_MEMBER (gboolean, ctx, ctx_offset)
811               : pboolean->default_value, pspec->flags);
812           break;
813         }
814         default:
815           if (G_IS_PARAM_SPEC_ENUM (pspec)) {
816             GParamSpecEnum *penum = G_PARAM_SPEC_ENUM (pspec);
817
818             pspec = g_param_spec_enum (name, nick, blurb,
819                 pspec->value_type,
820                 lavc_default ? G_STRUCT_MEMBER (gint, ctx, ctx_offset)
821                 : penum->default_value, pspec->flags);
822           } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
823             GParamSpecFlags *pflags = G_PARAM_SPEC_FLAGS (pspec);
824
825             pspec = g_param_spec_flags (name, nick, blurb,
826                 pspec->value_type,
827                 lavc_default ? G_STRUCT_MEMBER (guint, ctx, ctx_offset)
828                 : pflags->default_value, pspec->flags);
829           } else {
830             g_critical ("%s does not yet support type %s", GST_FUNCTION,
831                 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
832             continue;
833           }
834           break;
835       }
836       g_param_spec_set_qdata (pspec, quark, qdata);
837       g_object_class_install_property (G_OBJECT_CLASS (klass), prop_id, pspec);
838       ++prop_id;
839     }
840   }
841
842   if (ctx) {
843     gst_ffmpeg_avcodec_close (ctx);
844     av_free (ctx);
845   }
846 }
847
848 /* returns TRUE if it is a known property for this config system,
849  * FALSE otherwise */
850 gboolean
851 gst_ffmpeg_cfg_set_property (GObject * object,
852     const GValue * value, GParamSpec * pspec)
853 {
854   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) (object);
855   GParamSpecData *qdata;
856
857   qdata = g_param_spec_get_qdata (pspec, quark);
858
859   /* our param specs should have such qdata */
860   if (!qdata)
861     return FALSE;
862
863   /* set the member using the offset, also mild type check based on size */
864   switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
865     case G_TYPE_BOOLEAN:
866       g_return_val_if_fail (qdata->size == sizeof (gboolean), TRUE);
867       G_STRUCT_MEMBER (gboolean, ffmpegenc, qdata->offset) =
868           g_value_get_boolean (value);
869       break;
870     case G_TYPE_UINT:
871       g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
872       G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset) =
873           g_value_get_uint (value);
874       break;
875     case G_TYPE_INT:
876       g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
877       G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset) =
878           g_value_get_int (value);
879       break;
880     case G_TYPE_INT64:
881       g_return_val_if_fail (qdata->size == sizeof (gint64), TRUE);
882       G_STRUCT_MEMBER (gint64, ffmpegenc, qdata->offset) =
883           g_value_get_int64 (value);
884       break;
885     case G_TYPE_FLOAT:
886       g_return_val_if_fail (qdata->size == sizeof (gfloat), TRUE);
887       G_STRUCT_MEMBER (gfloat, ffmpegenc, qdata->offset) =
888           g_value_get_float (value);
889       break;
890     case G_TYPE_STRING:
891       g_return_val_if_fail (qdata->size == sizeof (gchar *), TRUE);
892       g_free (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset));
893       G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset) =
894           g_value_dup_string (value);
895       break;
896     default:                   /* must be enum, given the check above */
897       if (G_IS_PARAM_SPEC_ENUM (pspec)) {
898         g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
899         G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset) =
900             g_value_get_enum (value);
901       } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
902         g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
903         G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset) =
904             g_value_get_flags (value);
905       } else {                  /* oops, bit lazy we don't cover this case yet */
906         g_critical ("%s does not yet support type %s", GST_FUNCTION,
907             g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
908       }
909
910       break;
911   }
912
913   return TRUE;
914 }
915
916 /* returns TRUE if it is a known property for this config system,
917  * FALSE otherwise */
918 gboolean
919 gst_ffmpeg_cfg_get_property (GObject * object,
920     GValue * value, GParamSpec * pspec)
921 {
922   GstFFMpegVidEnc *ffmpegenc = (GstFFMpegVidEnc *) (object);
923   GParamSpecData *qdata;
924
925   qdata = g_param_spec_get_qdata (pspec, quark);
926
927   /* our param specs should have such qdata */
928   if (!qdata)
929     return FALSE;
930
931   /* get the member using the offset, also mild type check based on size */
932   switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
933     case G_TYPE_BOOLEAN:
934       g_return_val_if_fail (qdata->size == sizeof (gboolean), TRUE);
935       g_value_set_boolean (value,
936           G_STRUCT_MEMBER (gboolean, ffmpegenc, qdata->offset));
937       break;
938     case G_TYPE_UINT:
939       g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
940       g_value_set_uint (value,
941           G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset));
942       break;
943     case G_TYPE_INT:
944       g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
945       g_value_set_int (value, G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset));
946       break;
947     case G_TYPE_INT64:
948       g_return_val_if_fail (qdata->size == sizeof (gint64), TRUE);
949       g_value_set_int64 (value, G_STRUCT_MEMBER (gint64, ffmpegenc,
950               qdata->offset));
951       break;
952     case G_TYPE_FLOAT:
953       g_return_val_if_fail (qdata->size == sizeof (gfloat), TRUE);
954       g_value_set_float (value,
955           G_STRUCT_MEMBER (gfloat, ffmpegenc, qdata->offset));
956       break;
957     case G_TYPE_STRING:
958       g_return_val_if_fail (qdata->size == sizeof (gchar *), TRUE);
959       g_value_take_string (value,
960           g_strdup (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset)));
961       break;
962     default:                   /* must be enum, given the check above */
963       if (G_IS_PARAM_SPEC_ENUM (pspec)) {
964         g_return_val_if_fail (qdata->size == sizeof (gint), TRUE);
965         g_value_set_enum (value,
966             G_STRUCT_MEMBER (gint, ffmpegenc, qdata->offset));
967       } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
968         g_return_val_if_fail (qdata->size == sizeof (guint), TRUE);
969         g_value_set_flags (value,
970             G_STRUCT_MEMBER (guint, ffmpegenc, qdata->offset));
971       } else {                  /* oops, bit lazy we don't cover this case yet */
972         g_critical ("%s does not yet support type %s", GST_FUNCTION,
973             g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
974       }
975       break;
976   }
977
978   return TRUE;
979 }
980
981 void
982 gst_ffmpeg_cfg_set_defaults (GstFFMpegVidEnc * ffmpegenc)
983 {
984   GParamSpec **pspecs;
985   guint num_props, i;
986
987   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (ffmpegenc),
988       &num_props);
989
990   for (i = 0; i < num_props; ++i) {
991     GValue val = { 0, };
992     GParamSpec *pspec = pspecs[i];
993
994     /* only touch those that are really ours; i.e. should have some qdata */
995     if (!g_param_spec_get_qdata (pspec, quark))
996       continue;
997     g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
998     g_param_value_set_default (pspec, &val);
999     g_object_set_property (G_OBJECT (ffmpegenc),
1000         g_param_spec_get_name (pspec), &val);
1001     g_value_unset (&val);
1002   }
1003
1004   g_free (pspecs);
1005
1006 }
1007
1008
1009 void
1010 gst_ffmpeg_cfg_fill_context (GstFFMpegVidEnc * ffmpegenc,
1011     AVCodecContext * context)
1012 {
1013   GstFFMpegVidEncClass *klass
1014       = (GstFFMpegVidEncClass *) G_OBJECT_GET_CLASS (ffmpegenc);
1015   GParamSpec *pspec;
1016   GParamSpecData *qdata;
1017   GList *list;
1018
1019   list = property_list;
1020
1021   while (list) {
1022     gint context_offset;
1023
1024     pspec = G_PARAM_SPEC (list->data);
1025     qdata = g_param_spec_get_qdata (pspec, quark);
1026     context_offset = qdata->offset - CONTEXT_CONFIG_OFFSET;
1027     if (gst_ffmpeg_cfg_codec_has_pspec (klass->in_plugin->id, pspec)
1028         && context_offset >= 0) {
1029       if (G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_STRING) {
1030         /* make a copy for ffmpeg, it will likely free only some,
1031          * but in any case safer than a potential double free */
1032         G_STRUCT_MEMBER (gchar *, context, context_offset) =
1033             av_strdup (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset));
1034       } else {
1035         /* memcpy a bit heavy for a small copy,
1036          * but hardly part of 'inner loop' */
1037         memcpy (G_STRUCT_MEMBER_P (context, context_offset),
1038             G_STRUCT_MEMBER_P (ffmpegenc, qdata->offset), qdata->size);
1039       }
1040     }
1041     list = list->next;
1042   }
1043 }
1044
1045 void
1046 gst_ffmpeg_cfg_finalize (GstFFMpegVidEnc * ffmpegenc)
1047 {
1048   GParamSpec **pspecs;
1049   guint num_props, i;
1050
1051   pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (ffmpegenc),
1052       &num_props);
1053
1054   for (i = 0; i < num_props; ++i) {
1055     GParamSpec *pspec = pspecs[i];
1056     GParamSpecData *qdata;
1057
1058     qdata = g_param_spec_get_qdata (pspec, quark);
1059
1060     /* our param specs should have such qdata */
1061     if (!qdata)
1062       continue;
1063
1064     switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) {
1065       case G_TYPE_STRING:
1066         if (qdata->size == sizeof (gchar *)) {
1067           g_free (G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset));
1068           G_STRUCT_MEMBER (gchar *, ffmpegenc, qdata->offset) = NULL;
1069         }
1070         break;
1071       default:
1072         break;
1073     }
1074   }
1075   g_free (pspecs);
1076 }