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