89f008f9ab1b0ce624a67b6f88eafe08077625cd
[platform/upstream/gstreamer.git] / ext / libpostproc / gstpostproc.c
1 /*
2     Copyright (C) 2005 Edward Hervey (edward@fluendo.com)
3     Copyright (C) 2006 Mark Nauwelaerts (manauw@skynet.be)
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <gst/gst.h>
25 #include <gst/video/video.h>
26 #include <gst/video/gstvideofilter.h>
27 #include <liboil/liboil.h>
28 #include <liboil/liboilcpu.h>
29 #include <liboil/liboilfunction.h>
30
31 #ifdef HAVE_FFMPEG_UNINSTALLED
32 #include <avcodec.h>
33 #include <postprocess.h>
34 #else
35 #include <ffmpeg/avcodec.h>
36 #include <ffmpeg/libpostproc/postprocess.h>
37 #endif
38
39
40 typedef struct _PostProcDetails PostProcDetails;
41
42 struct _PostProcDetails {
43   char  *shortname;
44   char  *longname;
45   char  *description;
46 };
47
48 static PostProcDetails filterdetails[] = {
49   {"hb", "hdeblock",            "horizontal deblocking filter"},
50   {"vb", "vdeblock",            "vertical deblocking filter"},
51   {"h1", "x1hdeblock",          "experimental horizontal deblocking filter 1"},
52   {"v1", "x1vdeblock",          "experimental vertical deblocking filter 1"},
53   {"ha", "ahdeblock",           "another horizontal deblocking filter"},
54   {"va", "avdeblock",           "another vertical deblocking filter"},
55   {"dr", "dering",              "deringing filter"},
56   {"al", "autolevels",          "automatic brightness/contrast filter"},
57   {"lb", "linblenddeint",       "linear blend interpolater"},
58   {"li", "linipoldeint",        "linear interpolation deinterlacer"},
59   {"ci", "cubicipoldeint",      "cubic interpolation deinterlacer"},
60   {"md", "mediandeint",         "median deinterlacer"},
61   {"fd", "ffmpegdeint",         "ffmpeg deinterlacer"},
62   {"l5", "lowpass5",            "FIR lowpass deinterlacer"},
63   {"tn", "tmpnoise",            "temporal noise reducer"},
64   {"fq", "forcequant",          "force quantizer"},
65   {"de", "default",             "default filters"},
66   {NULL, NULL,                  NULL}
67 };
68
69 typedef struct  _GstPostProc GstPostProc;
70
71 struct  _GstPostProc
72 {
73   GstVideoFilter element;
74
75   GstPad *sinkpad, *srcpad;
76   guint quality;
77   gint width, height;
78
79   gint ystride, ustride, vstride;
80   gint ysize, usize, vsize;
81
82   pp_mode_t *mode;
83   pp_context_t *context;
84
85   /* props of various filters */
86   gboolean autoq;
87   guint scope;
88   /* though not all needed at once,
89    * this avoids union or ugly re-use for simplicity */
90   gint diff, flat;
91   gint t1, t2, t3;
92   gboolean range;
93   gint quant;
94
95   /* argument string for pp */
96   gchar *cargs, *args;
97 };
98
99 typedef struct  _GstPostProcClass GstPostProcClass;
100
101 struct  _GstPostProcClass
102 {
103   GstVideoFilterClass parent_class;
104
105   gint filterid;
106 };
107
108 /* properties for the various pp filters */
109 /* common props */
110 enum
111 {
112   PROP_0,
113   PROP_QUALITY,
114   PROP_AUTOQ,
115   PROP_SCOPE,
116   PROP_MAX
117 };
118
119 /* possible filter scopes */
120 enum
121 {
122   SCOPE_BOTH,
123   SCOPE_CHROMA,
124   SCOPE_LUMA
125 };
126
127 #define DEFAULT_QUALITY   PP_QUALITY_MAX
128 #define DEFAULT_AUTOQ     FALSE
129 #define DEFAULT_SCOPE     SCOPE_BOTH
130
131 /* deblocking props */
132 enum
133 {
134   PROP_DIFF = PROP_MAX,
135   PROP_FLAT
136 };
137
138 #define DEFAULT_DIFF    -1
139 #define DEFAULT_FLAT    -1
140
141 /* denoise props */
142 enum
143 {
144   PROP_T1 = PROP_MAX,
145   PROP_T2,
146   PROP_T3
147 };
148
149 #define DEFAULT_T1    -1
150 #define DEFAULT_T2    -1
151 #define DEFAULT_T3    -1
152
153 /* autolevels */
154 enum
155 {
156   PROP_RANGE = PROP_MAX
157 };
158
159 #define DEFAULT_RANGE FALSE
160
161 /* forceq props */
162 enum
163 {
164   PROP_QUANT = PROP_MAX
165 };
166
167 #define DEFAULT_QUANT  -1
168
169
170 /* hashtable, key = gtype, value = filterdetails index */
171 static GHashTable *global_plugins;
172
173 /* TODO : add support for the other format supported by libpostproc */
174
175 static GstStaticPadTemplate gst_post_proc_src_template =
176 GST_STATIC_PAD_TEMPLATE ("src",
177     GST_PAD_SRC,
178     GST_PAD_ALWAYS,
179     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
180     );
181
182 static GstStaticPadTemplate gst_post_proc_sink_template =
183 GST_STATIC_PAD_TEMPLATE ("sink",
184     GST_PAD_SINK,
185     GST_PAD_ALWAYS,
186     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
187     );
188
189 GST_DEBUG_CATEGORY (postproc_debug);
190 #define GST_CAT_DEFAULT postproc_debug
191
192 static void gst_post_proc_class_init (GstPostProcClass * klass);
193 static void gst_post_proc_base_init (GstPostProcClass * klass);
194 static void gst_post_proc_init (GstPostProc * pproc);
195 static void gst_post_proc_dispose (GObject * object);
196
197 static gboolean gst_post_proc_setcaps (GstBaseTransform * btrans, GstCaps * incaps,
198     GstCaps * outcaps);
199 static GstFlowReturn gst_post_proc_transform_ip (GstBaseTransform * btrans,
200     GstBuffer * in);
201
202 /* static GstStateChangeReturn gst_post_proc_change_state (GstElement * element, */
203 /*     GstStateChange transition); */
204
205 static void gst_post_proc_set_property (GObject * object,
206     guint prop_id, const GValue * value, GParamSpec *pspec);
207 static void gst_post_proc_get_property (GObject * object,
208     guint prop_id, GValue * value, GParamSpec *pspec);
209 static void gst_post_proc_deblock_set_property (GObject * object,
210     guint prop_id, const GValue * value, GParamSpec *pspec);
211 static void gst_post_proc_deblock_get_property (GObject * object,
212     guint prop_id, GValue * value, GParamSpec *pspec);
213 static void gst_post_proc_autolevels_set_property (GObject * object,
214     guint prop_id, const GValue * value, GParamSpec *pspec);
215 static void gst_post_proc_autolevels_get_property (GObject * object,
216     guint prop_id, GValue * value, GParamSpec *pspec);
217 static void gst_post_proc_tmpnoise_set_property (GObject * object,
218     guint prop_id, const GValue * value, GParamSpec *pspec);
219 static void gst_post_proc_tmpnoise_get_property (GObject * object,
220     guint prop_id, GValue * value, GParamSpec *pspec);
221 static void gst_post_proc_forcequant_set_property (GObject * object,
222     guint prop_id, const GValue * value, GParamSpec *pspec);
223 static void gst_post_proc_forcequant_get_property (GObject * object,
224     guint prop_id, GValue * value, GParamSpec *pspec);
225
226 static GstElementClass *parent_class = NULL;
227
228 #define GST_TYPE_PP_SCOPE (gst_pp_scope_get_type())
229 static GType
230 gst_pp_scope_get_type (void)
231 {
232   static GType pp_scope_type = 0;
233
234   static const GEnumValue pp_scope[] = {
235     {0, "Chrominance and Luminance filtering", "both"},
236     {1, "Chrominance only filtering", "chroma"},
237     {2, "Luminance only filtering", "luma"},
238     {0, NULL, NULL},
239   };
240
241   if (!pp_scope_type) {
242     pp_scope_type =
243         g_enum_register_static ("GstPostProcPPScope", pp_scope);
244   }
245   return pp_scope_type;
246 }
247
248 #ifndef GST_DISABLE_GST_DEBUG
249 static void
250 gst_ffmpeg_log_callback (void * ptr, int level, const char * fmt, va_list vl)
251 {
252   GstDebugLevel gst_level;
253
254   switch (level) {
255     case AV_LOG_QUIET:
256       gst_level = GST_LEVEL_NONE;
257       break;
258     case AV_LOG_ERROR:
259       gst_level = GST_LEVEL_ERROR;
260       break;
261     case AV_LOG_INFO:
262       gst_level = GST_LEVEL_INFO;
263       break;
264     case AV_LOG_DEBUG:
265       gst_level = GST_LEVEL_DEBUG;
266       break;
267     default:
268       gst_level = GST_LEVEL_INFO;
269       break;
270   }
271
272   gst_debug_log_valist (postproc_debug, gst_level, "", "", 0, NULL, fmt, vl);
273 }
274 #endif
275
276 #define ROUND_UP_2(x)  (((x)+1)&~1)
277 #define ROUND_UP_4(x)  (((x)+3)&~3)
278 #define ROUND_UP_8(x)  (((x)+7)&~7)
279
280 static void
281 change_context (GstPostProc * postproc, gint width, gint height)
282 {
283   guint flags;
284   gint ppflags;
285
286   GST_DEBUG_OBJECT (postproc, "change_context, width:%d, height:%d",
287       width, height);
288
289   if ((width != postproc->width) && (height != postproc->height)) {
290     if (postproc->context)
291       pp_free_context (postproc->context);
292     flags = oil_cpu_get_flags();
293     ppflags = (flags & OIL_IMPL_FLAG_MMX ? PP_CPU_CAPS_MMX : 0)
294         | (flags & OIL_IMPL_FLAG_MMXEXT ? PP_CPU_CAPS_MMX2 : 0)
295         | (flags & OIL_IMPL_FLAG_3DNOW ? PP_CPU_CAPS_3DNOW : 0)
296         | (flags & OIL_IMPL_FLAG_ALTIVEC ? PP_CPU_CAPS_ALTIVEC : 0);
297     postproc->context = pp_get_context (width, height, PP_FORMAT_420 | ppflags);
298     postproc->width = width;
299     postproc->height = height;
300     postproc->ystride = ROUND_UP_4 (width);
301     postproc->ustride = ROUND_UP_8 (width) / 2;
302     postproc->vstride = ROUND_UP_8 (postproc->ystride) / 2;
303     postproc->ysize = postproc->ystride * ROUND_UP_2 (height);
304     postproc->usize = postproc->ustride * ROUND_UP_2 (height) / 2;
305     postproc->vsize = postproc->vstride * ROUND_UP_2 (height) / 2;
306     GST_DEBUG_OBJECT (postproc, "new strides are (YUV) : %d %d %d",
307         postproc->ystride, postproc->ustride, postproc->vstride);
308   }
309 }
310
311 /* append app to *base, and places result in *base */
312 /* all input strings are free'd */
313 static void inline
314 append (gchar ** base, gchar * app)
315 {
316   gchar *res;
317   gchar *sep;
318
319   if (**base && *app)
320     sep = ":";
321   else
322     sep = "";
323   res = g_strconcat (*base, sep, app, NULL);
324   g_free (*base);
325   g_free (app);
326   *base = res;
327 }
328
329 static void
330 change_mode (GstPostProc * postproc )
331 {
332   GstPostProcClass * klass;
333   gchar *name;
334
335   klass = (GstPostProcClass *) G_OBJECT_GET_CLASS (G_OBJECT (postproc));
336
337   if (postproc->mode)
338     pp_free_mode (postproc->mode);
339
340   name = g_strdup (filterdetails[klass->filterid].shortname);
341   append (&name, g_strdup (postproc->cargs));
342   append (&name, g_strdup (postproc->args));
343   GST_DEBUG_OBJECT (postproc, "requesting pp %s", name);
344   postproc->mode = pp_get_mode_by_name_and_quality (name, postproc->quality);
345   g_free (name);
346
347   g_assert (postproc->mode);
348 }
349
350 static void
351 gst_post_proc_base_init (GstPostProcClass * klass)
352 {
353   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
354   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
355   GstElementDetails details;
356   gint ppidx;
357
358   ppidx = GPOINTER_TO_INT (g_hash_table_lookup (global_plugins,
359       GINT_TO_POINTER (G_OBJECT_CLASS_TYPE (gobject_class))));
360
361   details.longname = g_strdup_printf ("LibPostProc %s filter",
362       filterdetails[ppidx].longname);
363   details.klass = "Filter/Video";
364   details.description = g_strdup_printf ("LibPostProc %s",
365       filterdetails[ppidx].description);
366   details.author = "Edward Hervey <edward@fluendo.com>, Mark Nauwelaerts (manauw@skynet.be)";
367   gst_element_class_set_details (element_class, &details);
368   g_free(details.longname);
369   g_free(details.description);
370
371   gst_element_class_add_pad_template (element_class, 
372       gst_static_pad_template_get (&gst_post_proc_src_template));
373   gst_element_class_add_pad_template (element_class,
374       gst_static_pad_template_get (&gst_post_proc_sink_template));
375
376   klass->filterid = ppidx;
377 }
378
379 static void
380 gst_post_proc_class_init (GstPostProcClass * klass)
381 {
382   GObjectClass  *gobject_class = G_OBJECT_CLASS (klass);
383 /*   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); */
384   GstBaseTransformClass *btrans_class = GST_BASE_TRANSFORM_CLASS (klass);
385   gint ppidx;
386
387   parent_class = g_type_class_peek_parent (klass);
388
389   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_post_proc_set_property);
390   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_post_proc_get_property);
391
392   /* common props */
393   g_object_class_install_property (gobject_class, PROP_QUALITY,
394       g_param_spec_uint ("quality", "Quality",
395           "Quality level of filter (higher is better)",
396           0, PP_QUALITY_MAX, DEFAULT_QUALITY, G_PARAM_READWRITE));
397
398   g_object_class_install_property (gobject_class, PROP_AUTOQ,
399       g_param_spec_boolean ("autoq", "AutoQ",
400           "Automatically switch filter off if CPU too slow",
401           DEFAULT_AUTOQ, G_PARAM_READWRITE));
402
403   g_object_class_install_property (gobject_class, PROP_SCOPE,
404       g_param_spec_enum ("scope", "Scope",
405           "Operate on chrominance and/or luminance",
406           GST_TYPE_PP_SCOPE, DEFAULT_SCOPE, G_PARAM_READWRITE));
407
408   ppidx = klass->filterid;
409   /* per filter props */
410   if (g_strrstr (filterdetails[ppidx].longname, "deblock") != NULL &&
411       filterdetails[ppidx].longname[0] != 'x') {
412     /* deblocking */
413     g_object_class_install_property (gobject_class, PROP_DIFF,
414         g_param_spec_int ("difference", "Difference Factor",
415             "Higher values mean more deblocking (-1 = pp default)",
416             -1, G_MAXINT, DEFAULT_DIFF, G_PARAM_READWRITE));
417
418     g_object_class_install_property (gobject_class, PROP_FLAT,
419         g_param_spec_int ("flatness", "Flatness Threshold",
420             "Lower values mean more deblocking (-1 = pp default)",
421             -1, G_MAXINT, DEFAULT_FLAT, G_PARAM_READWRITE));
422
423     gobject_class->set_property =
424         GST_DEBUG_FUNCPTR (gst_post_proc_deblock_set_property);
425     gobject_class->get_property =
426         GST_DEBUG_FUNCPTR (gst_post_proc_deblock_get_property);
427   } else if (!(g_ascii_strcasecmp (filterdetails[ppidx].shortname, "tn"))) {
428     /* tmpnoise */
429     g_object_class_install_property (gobject_class, PROP_T1,
430         g_param_spec_int ("threshold-1", "Threshold One",
431             "Higher values mean stronger filtering (-1 = pp default)",
432             -1, G_MAXINT, DEFAULT_T1, G_PARAM_READWRITE));
433
434     g_object_class_install_property (gobject_class, PROP_T2,
435         g_param_spec_int ("threshold-2", "Threshold Two",
436             "Higher values mean stronger filtering (-1 = pp default)",
437             -1, G_MAXINT, DEFAULT_T2, G_PARAM_READWRITE));
438
439     g_object_class_install_property (gobject_class, PROP_T3,
440         g_param_spec_int ("threshold-3", "Threshold Three",
441             "Higher values mean stronger filtering (-1 = pp default)",
442             -1, G_MAXINT, DEFAULT_T3, G_PARAM_READWRITE));
443
444     gobject_class->set_property =
445         GST_DEBUG_FUNCPTR (gst_post_proc_tmpnoise_set_property);
446     gobject_class->get_property =
447         GST_DEBUG_FUNCPTR (gst_post_proc_tmpnoise_get_property);
448   } else if (!(g_ascii_strcasecmp (filterdetails[ppidx].shortname, "al"))) {
449     /* autolevels */
450     g_object_class_install_property (gobject_class, PROP_RANGE,
451         g_param_spec_boolean ("fully-range", "Fully Range",
452             "Stretch luminance to (0-255)",
453             DEFAULT_RANGE, G_PARAM_READWRITE));
454
455     gobject_class->set_property =
456         GST_DEBUG_FUNCPTR (gst_post_proc_autolevels_set_property);
457     gobject_class->get_property =
458         GST_DEBUG_FUNCPTR (gst_post_proc_autolevels_get_property);
459
460   } else if (!(g_ascii_strcasecmp (filterdetails[ppidx].shortname, "fq"))) {
461     /* forcequant */
462     g_object_class_install_property (gobject_class, PROP_QUANT,
463         g_param_spec_int ("quantizer", "Force Quantizer",
464           "Quantizer to use (-1 = pp default)",
465             -1, G_MAXINT, DEFAULT_QUANT, G_PARAM_READWRITE));
466
467     gobject_class->set_property =
468         GST_DEBUG_FUNCPTR (gst_post_proc_forcequant_set_property);
469     gobject_class->get_property =
470         GST_DEBUG_FUNCPTR (gst_post_proc_forcequant_get_property);
471   }
472
473   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_post_proc_dispose);
474   btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_post_proc_setcaps);
475   btrans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_post_proc_transform_ip);
476 }
477
478 static void
479 gst_post_proc_init (GstPostProc * postproc)
480 {
481   /* properties */
482   postproc->quality = DEFAULT_QUALITY;
483   postproc->autoq = DEFAULT_AUTOQ;
484   postproc->scope = DEFAULT_SCOPE;
485   postproc->diff = DEFAULT_DIFF;
486   postproc->flat = DEFAULT_FLAT;
487   postproc->quant = DEFAULT_QUANT;
488   postproc->t1 = DEFAULT_T1;
489   postproc->t2 = DEFAULT_T2;
490   postproc->t3 = DEFAULT_T3;
491   postproc->range = DEFAULT_RANGE;
492   postproc->mode = NULL;
493   postproc->cargs = g_strdup ("");
494   postproc->args = g_strdup ("");
495   change_mode (postproc);
496
497   postproc->context = NULL;
498   postproc->width = 0;
499   postproc->height = 0;
500   postproc->ystride = 0;
501   postproc->ustride = 0;
502   postproc->vstride = 0;
503   postproc->ysize = 0;
504   postproc->usize = 0;
505   postproc->vsize = 0;
506 }
507
508 static void
509 gst_post_proc_dispose (GObject * object)
510 {
511   GstPostProc * postproc = (GstPostProc *) object;
512
513   if (postproc->mode)
514     pp_free_mode (postproc->mode);
515   if (postproc->context)
516     pp_free_context (postproc->context);
517
518   g_free (postproc->cargs);
519   postproc->cargs = NULL;
520   g_free (postproc->args);
521   postproc->args = NULL;
522
523   G_OBJECT_CLASS (parent_class)->dispose (object);
524 }
525
526 static gboolean
527 gst_post_proc_setcaps (GstBaseTransform * btrans, GstCaps * incaps,
528     GstCaps * outcaps)
529 {
530   GstPostProc *postproc = (GstPostProc *) (btrans);
531   GstStructure *structure;
532   gboolean ret = FALSE;
533   gint width, height;
534
535   structure = gst_caps_get_structure (incaps, 0);
536
537   if (gst_structure_get_int (structure, "width", &width) &&
538       gst_structure_get_int (structure, "height", &height)) {
539     change_context (postproc, width, height);
540     ret = TRUE;
541   }
542
543   return ret;
544 }
545
546 static GstFlowReturn
547 gst_post_proc_transform_ip (GstBaseTransform * btrans, GstBuffer * in)
548 {
549   GstPostProc *postproc;
550   gint stride[3];
551   guint8 *outplane[3];
552   guint8 *inplane[3];
553
554   /* postprocess the buffer !*/
555   postproc = (GstPostProc *) btrans;
556
557   stride[0] = postproc->ystride;
558   stride[1] = postproc->ustride;
559   stride[2] = postproc->vstride;
560   outplane[0] = inplane[0] = GST_BUFFER_DATA (in);
561   outplane[1] = inplane[1] = outplane[0] + postproc->ysize;
562   outplane[2] = inplane[2] = outplane[1] + postproc->usize;
563
564   GST_DEBUG_OBJECT (postproc, "calling pp_postprocess, width:%d, height:%d",
565       postproc->width, postproc->height);
566
567   pp_postprocess ((const guint8**) inplane, stride, outplane, stride,
568       postproc->width, postproc->height, (int8_t*) "", 0,
569       postproc->mode, postproc->context, 0);
570
571   return GST_FLOW_OK;
572 }
573
574
575 static void
576 gst_post_proc_set_property (GObject * object, guint prop_id,
577     const GValue * value, GParamSpec *pspec)
578 {
579   GstPostProc *postproc = (GstPostProc *) object;
580   gint quality;
581   gchar *args;
582
583   switch (prop_id) {
584     case PROP_QUALITY:
585       quality = g_value_get_uint (value);
586     break;
587     case PROP_AUTOQ:
588       postproc->autoq = g_value_get_boolean (value);
589       break;
590     case PROP_SCOPE:
591       postproc->scope = g_value_get_enum (value);
592       break;
593   default:
594     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
595     break;
596   }
597
598   /* construct common args */
599   args = postproc->autoq ? g_strdup ("autoq") : g_strdup ("");
600   switch (postproc->scope) {
601     case SCOPE_BOTH:
602       break;
603     case SCOPE_CHROMA:
604       append (&args, g_strdup ("noluma"));
605       break;
606     case SCOPE_LUMA:
607       append (&args, g_strdup ("nochrom"));
608       break;
609     default:
610       g_assert_not_reached ();
611       break;
612   }
613
614   g_free (postproc->cargs);
615   postproc->cargs = args;
616
617   change_mode (postproc);
618 }
619
620 static void
621 gst_post_proc_get_property (GObject * object, guint prop_id,
622     GValue * value, GParamSpec *pspec)
623 {
624   GstPostProc *postproc = (GstPostProc *) object;
625
626   switch (prop_id) {
627     case PROP_QUALITY:
628       g_value_set_uint (value, postproc->quality);
629       break;
630     case PROP_AUTOQ:
631       g_value_set_boolean (value, postproc->autoq);
632       break;
633     case PROP_SCOPE:
634       g_value_set_enum (value, postproc->scope);
635       break;
636     default:
637     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
638     break;
639   }
640 }
641
642
643 static void
644 gst_post_proc_deblock_set_property (GObject * object, guint prop_id,
645     const GValue * value, GParamSpec *pspec)
646 {
647   GstPostProc *postproc = (GstPostProc *) object;
648
649   switch (prop_id) {
650     case PROP_DIFF:
651       postproc->diff = g_value_get_int (value);
652       break;
653     case PROP_FLAT:
654       postproc->flat = g_value_get_int (value);
655       break;
656     default:
657       gst_post_proc_set_property (object, prop_id, value, pspec);
658       break;
659   }
660
661   /* construct args */
662   g_free (postproc->args);
663   if (postproc->diff >= 0) {
664     postproc->args = g_strdup_printf ("%d", postproc->diff);
665     if (postproc->flat >= 0)
666       append (&postproc->args, g_strdup_printf ("%d", postproc->flat));
667   } else
668     postproc->args = g_strdup ("");
669   change_mode (postproc);
670 }
671
672 static void
673 gst_post_proc_deblock_get_property ( GObject * object, guint prop_id,
674     GValue * value, GParamSpec *pspec )
675 {
676   GstPostProc *postproc = (GstPostProc *) object;
677
678   switch (prop_id) {
679     case PROP_DIFF:
680       g_value_set_int (value, postproc->diff);
681       break;
682     case PROP_FLAT:
683       g_value_set_int (value, postproc->flat);
684       break;
685     default:
686       gst_post_proc_get_property (object, prop_id, value, pspec);
687       break;
688   }
689 }
690
691 static void
692 gst_post_proc_tmpnoise_set_property (GObject * object, guint prop_id,
693     const GValue * value, GParamSpec *pspec)
694 {
695   GstPostProc *postproc = (GstPostProc *) object;
696
697   switch (prop_id) {
698     case PROP_T1:
699       postproc->t1 = g_value_get_int (value);
700       break;
701     case PROP_T2:
702       postproc->t2 = g_value_get_int (value);
703       break;
704     case PROP_T3:
705       postproc->t3 = g_value_get_int (value);
706       break;
707     default:
708       gst_post_proc_set_property (object, prop_id, value, pspec);
709       break;
710   }
711
712   /* construct args */
713   g_free (postproc->args);
714   if (postproc->t1 >= 0) {
715     postproc->args = g_strdup_printf ("%d", postproc->t1);
716     if (postproc->t2 >= 0) {
717       append (&postproc->args, g_strdup_printf ("%d", postproc->t2));
718       if (postproc->t3 >= 0)
719         append (&postproc->args, g_strdup_printf ("%d", postproc->t3));
720     }
721   } else
722     postproc->args = g_strdup ("");
723   change_mode (postproc);
724 }
725
726 static void
727 gst_post_proc_tmpnoise_get_property (GObject * object, guint prop_id,
728     GValue * value, GParamSpec *pspec )
729 {
730   GstPostProc *postproc = (GstPostProc *) object;
731
732   switch (prop_id) {
733     case PROP_T1:
734       g_value_set_int (value, postproc->t1);
735       break;
736     case PROP_T2:
737       g_value_set_int (value, postproc->t2);
738       break;
739     case PROP_T3:
740       g_value_set_int (value, postproc->t3);
741       break;
742     default:
743       gst_post_proc_get_property (object, prop_id, value, pspec);
744       break;
745   }
746 }
747
748 static void
749 gst_post_proc_autolevels_set_property (GObject * object, guint prop_id,
750     const GValue * value, GParamSpec *pspec)
751 {
752   GstPostProc *postproc = (GstPostProc *) object;
753
754   switch (prop_id) {
755     case PROP_RANGE:
756       postproc->range = g_value_get_boolean (value);
757       break;
758     default:
759       gst_post_proc_set_property (object, prop_id, value, pspec);
760       break;
761   }
762
763   /* construct args */
764   g_free (postproc->args);
765   if (postproc->range)
766     postproc->args = g_strdup ("f");
767   else
768     postproc->args = g_strdup ("");
769   change_mode (postproc);
770 }
771
772 static void
773 gst_post_proc_autolevels_get_property (GObject * object, guint prop_id,
774     GValue * value, GParamSpec *pspec )
775 {
776   GstPostProc *postproc = (GstPostProc *) object;
777
778   switch (prop_id) {
779     case PROP_RANGE:
780       g_value_set_boolean (value, postproc->range);
781       break;
782     default:
783       gst_post_proc_get_property (object, prop_id, value, pspec);
784       break;
785   }
786 }
787
788 static void
789 gst_post_proc_forcequant_set_property (GObject * object, guint prop_id,
790     const GValue * value, GParamSpec *pspec)
791 {
792   GstPostProc *postproc = (GstPostProc *) object;
793
794   switch (prop_id) {
795     case PROP_QUANT:
796       postproc->quant = g_value_get_int (value);
797       break;
798     default:
799       gst_post_proc_set_property (object, prop_id, value, pspec);
800       break;
801   }
802
803   /* construct args */
804   g_free (postproc->args);
805   if (postproc->quant >= 0)
806     postproc->args = g_strdup_printf ("%d", postproc->quant);
807   else
808     postproc->args = g_strdup ("");
809   change_mode (postproc);
810 }
811
812 static void
813 gst_post_proc_forcequant_get_property (GObject * object, guint prop_id,
814     GValue * value, GParamSpec *pspec )
815 {
816   GstPostProc *postproc = (GstPostProc *) object;
817
818   switch (prop_id) {
819     case PROP_QUANT:
820       g_value_set_int (value, postproc->quant);
821       break;
822     default:
823       gst_post_proc_get_property (object, prop_id, value, pspec);
824       break;
825   }
826 }
827
828
829 gboolean
830 gst_post_proc_register(GstPlugin * plugin)
831 {
832   GTypeInfo     typeinfo = {
833     sizeof (GstPostProcClass),
834     (GBaseInitFunc) gst_post_proc_base_init,
835     NULL,
836     (GClassInitFunc) gst_post_proc_class_init,
837     NULL,
838     NULL,
839     sizeof (GstPostProc),
840     0,
841     (GInstanceInitFunc) gst_post_proc_init,
842   };
843   GType type;
844   int i;
845
846   global_plugins = g_hash_table_new (NULL, NULL);
847   for (i = 0; filterdetails[i].shortname; i++) {
848     gchar *type_name;
849
850     g_hash_table_insert (global_plugins, GINT_TO_POINTER (0),
851         GINT_TO_POINTER (i));
852
853     /* create type_name */
854     type_name = g_strdup_printf("postproc_%s", filterdetails[i].longname);
855     if (g_type_from_name (type_name)) {
856       g_free (type_name);
857       continue;
858     }
859
860     /* create gtype */
861     type = g_type_register_static (GST_TYPE_VIDEO_FILTER, type_name,
862         &typeinfo, 0);
863
864     g_hash_table_insert (global_plugins, GINT_TO_POINTER (type),
865         GINT_TO_POINTER (i));
866
867     /* register element */
868     if (!gst_element_register (plugin, type_name, GST_RANK_PRIMARY, type)) {
869       g_free(type_name);
870       return FALSE;
871     }
872
873     g_free(type_name);
874   }
875   g_hash_table_remove (global_plugins, GINT_TO_POINTER (0));
876
877   return TRUE;
878 }
879
880 static gboolean
881 plugin_init (GstPlugin * plugin)
882 {
883   GST_DEBUG_CATEGORY_INIT (postproc_debug, "postproc", 0,
884       "video postprocessing elements");
885 #ifndef GST_DISABLE_GST_DEBUG
886   av_log_set_callback (gst_ffmpeg_log_callback);
887 #endif
888
889   /* Register the filters */
890   gst_post_proc_register (plugin);
891
892   /* Now we can return the pointer to the newly created Plugin object. */
893   return TRUE;
894 }
895
896 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
897     GST_VERSION_MINOR,
898     "postproc",
899     "postprocessing elements (" FFMPEG_SOURCE ")",
900     plugin_init,
901     PACKAGE_VERSION, "GPL", "FFMpeg", "http://ffmpeg.sourceforge.net/")
902
903