NEWS: update from 3.0.x branch
[vlc.git] / modules / video_filter / gradfun.c
blob2bc6e36d37af293f2a468f6c2fab1fd584be5862
1 /*****************************************************************************
2 * gradfun.c: wrapper for the gradfun filter from libav
3 *****************************************************************************
4 * Copyright (C) 2010 Laurent Aimar
6 * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8 * Based on the work of: Nolan Lum and Loren Merritt
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_cpu.h>
36 #include <vlc_filter.h>
37 #include <vlc_picture.h>
39 /*****************************************************************************
40 * Module descriptor
41 *****************************************************************************/
42 static int Open (filter_t *);
44 #define CFG_PREFIX "gradfun-"
46 #define RADIUS_MIN (4)
47 #define RADIUS_MAX (32)
48 #define RADIUS_TEXT N_("Radius")
49 #define RADIUS_LONGTEXT N_("Radius in pixels")
51 #define STRENGTH_MIN (0.51f)
52 #define STRENGTH_MAX (255)
53 #define STRENGTH_TEXT N_("Strength")
54 #define STRENGTH_LONGTEXT N_("Strength used to modify the value of a pixel")
56 vlc_module_begin()
57 set_description(N_("Gradfun video filter"))
58 set_shortname(N_("Gradfun"))
59 set_help(N_("Debanding algorithm"))
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_callback_video_filter(Open)
68 vlc_module_end()
70 /*****************************************************************************
71 * Local prototypes
72 *****************************************************************************/
73 #define FFMAX(a,b) __MAX(a,b)
74 #ifdef CAN_COMPILE_MMXEXT
75 # define HAVE_MMX2 1
76 #else
77 # define HAVE_MMX2 0
78 #endif
79 #ifdef CAN_COMPILE_SSE2
80 # define HAVE_SSE2 1
81 #else
82 # define HAVE_SSE2 0
83 #endif
84 #ifdef CAN_COMPILE_SSSE3
85 # define HAVE_SSSE3 1
86 #else
87 # define HAVE_SSSE3 0
88 #endif
89 // FIXME too restrictive
90 #ifdef __x86_64__
91 # define HAVE_6REGS 1
92 #else
93 # define HAVE_6REGS 0
94 #endif
95 #define av_clip_uint8 clip_uint8_vlc
96 #include <stdalign.h>
97 #include "gradfun.h"
99 static int Callback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
100 VIDEO_FILTER_WRAPPER_CLOSE(Filter, Close)
102 typedef struct
104 vlc_mutex_t lock;
105 float strength;
106 int radius;
107 const vlc_chroma_description_t *chroma;
108 struct vf_priv_s cfg;
109 } filter_sys_t;
111 static int Open(filter_t *filter)
113 const vlc_fourcc_t fourcc = filter->fmt_in.video.i_chroma;
115 const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription(fourcc);
116 if (!chroma || chroma->plane_count < 3 || chroma->pixel_size != 1) {
117 msg_Err(filter, "Unsupported chroma (%4.4s)", (char*)&fourcc);
118 return VLC_EGENERIC;
121 filter_sys_t *sys = malloc(sizeof(*sys));
122 if (!sys)
123 return VLC_ENOMEM;
125 vlc_mutex_init(&sys->lock);
126 sys->chroma = chroma;
127 sys->strength = var_CreateGetFloatCommand(filter, CFG_PREFIX "strength");
128 sys->radius = var_CreateGetIntegerCommand(filter, CFG_PREFIX "radius");
129 var_AddCallback(filter, CFG_PREFIX "strength", Callback, NULL);
130 var_AddCallback(filter, CFG_PREFIX "radius", Callback, NULL);
131 sys->cfg.buf = NULL;
133 struct vf_priv_s *cfg = &sys->cfg;
134 cfg->thresh = 0.0;
135 cfg->radius = 0;
136 cfg->buf = NULL;
138 #if HAVE_SSE2 && HAVE_6REGS
139 if (vlc_CPU_SSE2())
140 cfg->blur_line = blur_line_sse2;
141 else
142 #endif
143 cfg->blur_line = blur_line_c;
144 #if HAVE_SSSE3
145 if (vlc_CPU_SSSE3())
146 cfg->filter_line = filter_line_ssse3;
147 else
148 #endif
149 #if HAVE_MMX2
150 if (vlc_CPU_MMXEXT())
151 cfg->filter_line = filter_line_mmx2;
152 else
153 #endif
154 cfg->filter_line = filter_line_c;
156 filter->p_sys = sys;
157 filter->ops = &Filter_ops;
158 return VLC_SUCCESS;
161 static void Close(filter_t *filter)
163 filter_sys_t *sys = filter->p_sys;
165 var_DelCallback(filter, CFG_PREFIX "radius", Callback, NULL);
166 var_DelCallback(filter, CFG_PREFIX "strength", Callback, NULL);
167 aligned_free(sys->cfg.buf);
168 free(sys);
171 static void Filter(filter_t *filter, picture_t *src, picture_t *dst)
173 filter_sys_t *sys = filter->p_sys;
175 vlc_mutex_lock(&sys->lock);
176 float strength = VLC_CLIP(sys->strength, STRENGTH_MIN, STRENGTH_MAX);
177 int radius = VLC_CLIP((sys->radius + 1) & ~1, RADIUS_MIN, RADIUS_MAX);
178 vlc_mutex_unlock(&sys->lock);
180 const video_format_t *fmt = &filter->fmt_in.video;
181 struct vf_priv_s *cfg = &sys->cfg;
183 cfg->thresh = (1 << 15) / strength;
184 if (cfg->radius != radius) {
185 cfg->radius = radius;
186 cfg->buf = aligned_alloc(16,
187 (((fmt->i_width + 15) & ~15) * (cfg->radius + 1) / 2 + 32) * sizeof(*cfg->buf));
190 for (int i = 0; i < dst->i_planes; i++) {
191 const plane_t *srcp = &src->p[i];
192 plane_t *dstp = &dst->p[i];
194 const vlc_chroma_description_t *chroma = sys->chroma;
195 int w = fmt->i_width * chroma->p[i].w.num / chroma->p[i].w.den;
196 int h = fmt->i_height * chroma->p[i].h.num / chroma->p[i].h.den;
197 int r = (cfg->radius * chroma->p[i].w.num / chroma->p[i].w.den +
198 cfg->radius * chroma->p[i].h.num / chroma->p[i].h.den) / 2;
199 r = VLC_CLIP((r + 1) & ~1, RADIUS_MIN, RADIUS_MAX);
200 if (__MIN(w, h) > 2 * r && cfg->buf) {
201 filter_plane(cfg, dstp->p_pixels, srcp->p_pixels,
202 w, h, dstp->i_pitch, srcp->i_pitch, r);
203 } else {
204 plane_CopyPixels(dstp, srcp);
209 static int Callback(vlc_object_t *object, char const *cmd,
210 vlc_value_t oldval, vlc_value_t newval, void *data)
212 filter_t *filter = (filter_t *)object;
213 filter_sys_t *sys = filter->p_sys;
214 VLC_UNUSED(oldval); VLC_UNUSED(data);
216 vlc_mutex_lock(&sys->lock);
217 if (!strcmp(cmd, CFG_PREFIX "strength"))
218 sys->strength = newval.f_float;
219 else
220 sys->radius = newval.i_int;
221 vlc_mutex_unlock(&sys->lock);
223 return VLC_SUCCESS;