1 /*****************************************************************************
2 * gradfun.c: wrapper for the gradfun filter from mplayer
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
7 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
37 /*****************************************************************************
39 *****************************************************************************/
40 static int Open (vlc_object_t *);
41 static void Close(vlc_object_t *);
43 #define CFG_PREFIX "gradfun-"
45 #define RADIUS_MIN (4)
46 #define RADIUS_MAX (32)
47 #define RADIUS_TEXT N_("Radius")
48 #define RADIUS_LONGTEXT N_("Radius in pixels")
50 #define STRENGTH_MIN (0.51)
51 #define STRENGTH_MAX (255)
52 #define STRENGTH_TEXT N_("Strength")
53 #define STRENGTH_LONGTEXT N_("Strength used to modify the value of a pixel")
56 set_description(N_("Gradfun video filter"))
57 set_shortname(N_("Gradfun"))
58 set_help("Debanding algorithm")
59 set_capability("video filter2", 0)
60 set_category(CAT_VIDEO)
61 set_subcategory(SUBCAT_VIDEO_VFILTER)
62 add_integer_with_range(CFG_PREFIX "radius", 16, RADIUS_MIN, RADIUS_MAX,
63 RADIUS_TEXT, RADIUS_LONGTEXT, false)
64 add_float_with_range(CFG_PREFIX "strength", 1.2, STRENGTH_MIN, STRENGTH_MAX,
65 STRENGTH_TEXT, STRENGTH_LONGTEXT, false)
67 set_callbacks(Open, Close)
70 /*****************************************************************************
72 *****************************************************************************/
73 #define FFMAX(a,b) __MAX(a,b)
74 #ifdef CAN_COMPILE_MMXEXT
79 #ifdef CAN_COMPILE_SSE2
84 #ifdef CAN_COMPILE_SSSE3
89 // FIXME too restrictive
95 #define av_clip_uint8 clip_uint8_vlc
98 static picture_t *Filter(filter_t *, picture_t *);
99 static int Callback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
101 struct filter_sys_t {
105 const vlc_chroma_description_t *chroma;
106 struct vf_priv_s cfg;
109 static int Open(vlc_object_t *object)
111 filter_t *filter = (filter_t *)object;
112 const vlc_fourcc_t fourcc = filter->fmt_in.video.i_chroma;
114 const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription(fourcc);
115 if (!chroma || chroma->plane_count < 3) {
116 msg_Err(filter, "Unsupported chroma (%4.4s)", (char*)&fourcc);
120 filter_sys_t *sys = malloc(sizeof(*sys));
124 vlc_mutex_init(&sys->lock);
125 sys->chroma = chroma;
126 sys->strength = var_CreateGetFloatCommand(filter, CFG_PREFIX "strength");
127 sys->radius = var_CreateGetIntegerCommand(filter, CFG_PREFIX "radius");
128 var_AddCallback(filter, CFG_PREFIX "strength", Callback, NULL);
129 var_AddCallback(filter, CFG_PREFIX "radius", Callback, NULL);
132 struct vf_priv_s *cfg = &sys->cfg;
136 cfg->filter_line = filter_line_c;
137 cfg->blur_line = blur_line_c;
139 #if HAVE_SSE2 && HAVE_6REGS
140 if (vlc_CPU() & CPU_CAPABILITY_SSE2)
141 cfg->blur_line = blur_line_sse2;
144 if (vlc_CPU() & CPU_CAPABILITY_MMXEXT)
145 cfg->filter_line = filter_line_mmx2;
148 if (vlc_CPU() & CPU_CAPABILITY_SSSE3)
149 cfg->filter_line = filter_line_ssse3;
153 filter->pf_video_filter = Filter;
157 static void Close(vlc_object_t *object)
159 filter_t *filter = (filter_t *)object;
160 filter_sys_t *sys = filter->p_sys;
162 var_DelCallback(filter, CFG_PREFIX "radius", Callback, NULL);
163 var_DelCallback(filter, CFG_PREFIX "strength", Callback, NULL);
165 vlc_mutex_destroy(&sys->lock);
169 static picture_t *Filter(filter_t *filter, picture_t *src)
171 filter_sys_t *sys = filter->p_sys;
173 picture_t *dst = filter_NewPicture(filter);
175 picture_Release(src);
179 vlc_mutex_lock(&sys->lock);
180 float strength = __MIN(__MAX(sys->strength, STRENGTH_MIN), STRENGTH_MAX);
181 int radius = __MIN(__MAX((sys->radius + 1) & ~1, RADIUS_MIN), RADIUS_MAX);
182 vlc_mutex_unlock(&sys->lock);
184 const video_format_t *fmt = &filter->fmt_in.video;
185 struct vf_priv_s *cfg = &sys->cfg;
187 cfg->thresh = (1 << 15) / strength;
188 if (cfg->radius != radius) {
189 cfg->radius = radius;
190 cfg->buf = vlc_memalign(16,
191 (((fmt->i_width + 15) & ~15) * (cfg->radius + 1) / 2 + 32) * sizeof(*cfg->buf));
194 for (int i = 0; i < dst->i_planes; i++) {
195 const plane_t *srcp = &src->p[i];
196 plane_t *dstp = &dst->p[i];
198 const vlc_chroma_description_t *chroma = sys->chroma;
199 int w = fmt->i_width * chroma->p[i].w.num / chroma->p[i].w.den;
200 int h = fmt->i_height * chroma->p[i].h.num / chroma->p[i].h.den;
201 int r = (cfg->radius * chroma->p[i].w.num / chroma->p[i].w.den +
202 cfg->radius * chroma->p[i].h.num / chroma->p[i].h.den) / 2;
203 r = __MIN(__MAX((r + 1) & ~1, RADIUS_MIN), RADIUS_MAX);
204 if (__MIN(w, h) > 2 * r && cfg->buf) {
205 filter_plane(cfg, dstp->p_pixels, srcp->p_pixels,
206 w, h, dstp->i_pitch, srcp->i_pitch, r);
208 plane_CopyPixels(dstp, srcp);
212 picture_CopyProperties(dst, src);
213 picture_Release(src);
217 static int Callback(vlc_object_t *object, char const *cmd,
218 vlc_value_t oldval, vlc_value_t newval, void *data)
220 filter_t *filter = (filter_t *)object;
221 filter_sys_t *sys = filter->p_sys;
222 VLC_UNUSED(oldval); VLC_UNUSED(data);
224 vlc_mutex_lock(&sys->lock);
225 if (!strcmp(cmd, CFG_PREFIX "strength"))
226 sys->strength = newval.f_float;
228 sys->radius = newval.i_int;
229 vlc_mutex_unlock(&sys->lock);