]> git.sesse.net Git - vlc/blob - modules/video_filter/gradfun.c
String removal
[vlc] / modules / video_filter / gradfun.c
1 /*****************************************************************************
2  * gradfun.c: wrapper for the gradfun filter from libav
3  *****************************************************************************
4  * Copyright (C) 2010 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
9  * Based on the work of: Nolan Lum and Loren Merritt
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_cpu.h>
37 #include <vlc_filter.h>
38
39 /*****************************************************************************
40  * Module descriptor
41  *****************************************************************************/
42 static int  Open (vlc_object_t *);
43 static void Close(vlc_object_t *);
44
45 #define CFG_PREFIX "gradfun-"
46
47 #define RADIUS_MIN (4)
48 #define RADIUS_MAX (32)
49 #define RADIUS_TEXT N_("Radius")
50 #define RADIUS_LONGTEXT N_("Radius in pixels")
51
52 #define STRENGTH_MIN (0.51)
53 #define STRENGTH_MAX (255)
54 #define STRENGTH_TEXT N_("Strength")
55 #define STRENGTH_LONGTEXT N_("Strength used to modify the value of a pixel")
56
57 vlc_module_begin()
58     set_description(N_("Gradfun video filter"))
59     set_shortname(N_("Gradfun"))
60     set_help(N_("Debanding algorithm"))
61     set_capability("video filter2", 0)
62     set_category(CAT_VIDEO)
63     set_subcategory(SUBCAT_VIDEO_VFILTER)
64     add_integer_with_range(CFG_PREFIX "radius", 16, RADIUS_MIN, RADIUS_MAX,
65                            RADIUS_TEXT, RADIUS_LONGTEXT, false)
66     add_float_with_range(CFG_PREFIX "strength", 1.2, STRENGTH_MIN, STRENGTH_MAX,
67                          STRENGTH_TEXT, STRENGTH_LONGTEXT, false)
68
69     set_callbacks(Open, Close)
70 vlc_module_end()
71
72 /*****************************************************************************
73  * Local prototypes
74  *****************************************************************************/
75 #define FFMAX(a,b) __MAX(a,b)
76 #ifdef CAN_COMPILE_MMXEXT
77 #   define HAVE_MMX2 1
78 #else
79 #   define HAVE_MMX2 0
80 #endif
81 #ifdef CAN_COMPILE_SSE2
82 #   define HAVE_SSE2 1
83 #else
84 #   define HAVE_SSE2 0
85 #endif
86 #ifdef CAN_COMPILE_SSSE3
87 #   define HAVE_SSSE3 1
88 #else
89 #   define HAVE_SSSE3 0
90 #endif
91 // FIXME too restrictive
92 #ifdef __x86_64__
93 #   define HAVE_6REGS 1
94 #else
95 #   define HAVE_6REGS 0
96 #endif
97 #define av_clip_uint8 clip_uint8_vlc
98 #include "gradfun.h"
99
100 static picture_t *Filter(filter_t *, picture_t *);
101 static int Callback(vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void *);
102
103 struct filter_sys_t {
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 };
110
111 static int Open(vlc_object_t *object)
112 {
113     filter_t *filter = (filter_t *)object;
114     const vlc_fourcc_t fourcc = filter->fmt_in.video.i_chroma;
115
116     const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription(fourcc);
117     if (!chroma || chroma->plane_count < 3 || chroma->pixel_size != 1) {
118         msg_Err(filter, "Unsupported chroma (%4.4s)", (char*)&fourcc);
119         return VLC_EGENERIC;
120     }
121
122     filter_sys_t *sys = malloc(sizeof(*sys));
123     if (!sys)
124         return VLC_ENOMEM;
125
126     vlc_mutex_init(&sys->lock);
127     sys->chroma   = chroma;
128     sys->strength = var_CreateGetFloatCommand(filter,   CFG_PREFIX "strength");
129     sys->radius   = var_CreateGetIntegerCommand(filter, CFG_PREFIX "radius");
130     var_AddCallback(filter, CFG_PREFIX "strength", Callback, NULL);
131     var_AddCallback(filter, CFG_PREFIX "radius",   Callback, NULL);
132     sys->cfg.buf = NULL;
133
134     struct vf_priv_s *cfg = &sys->cfg;
135     cfg->thresh      = 0.0;
136     cfg->radius      = 0;
137     cfg->buf         = NULL;
138
139 #if HAVE_SSE2 && HAVE_6REGS
140     if (vlc_CPU_SSE2())
141         cfg->blur_line = blur_line_sse2;
142     else
143 #endif
144         cfg->blur_line   = blur_line_c;
145 #if HAVE_SSSE3
146     if (vlc_CPU_SSSE3())
147         cfg->filter_line = filter_line_ssse3;
148     else
149 #endif
150 #if HAVE_MMX2
151     if (vlc_CPU_MMXEXT())
152         cfg->filter_line = filter_line_mmx2;
153     else
154 #endif
155         cfg->filter_line = filter_line_c;
156
157     filter->p_sys           = sys;
158     filter->pf_video_filter = Filter;
159     return VLC_SUCCESS;
160 }
161
162 static void Close(vlc_object_t *object)
163 {
164     filter_t     *filter = (filter_t *)object;
165     filter_sys_t *sys = filter->p_sys;
166
167     var_DelCallback(filter, CFG_PREFIX "radius",   Callback, NULL);
168     var_DelCallback(filter, CFG_PREFIX "strength", Callback, NULL);
169     vlc_free(sys->cfg.buf);
170     vlc_mutex_destroy(&sys->lock);
171     free(sys);
172 }
173
174 static picture_t *Filter(filter_t *filter, picture_t *src)
175 {
176     filter_sys_t *sys = filter->p_sys;
177
178     picture_t *dst = filter_NewPicture(filter);
179     if (!dst) {
180         picture_Release(src);
181         return NULL;
182     }
183
184     vlc_mutex_lock(&sys->lock);
185     float strength = VLC_CLIP(sys->strength, STRENGTH_MIN, STRENGTH_MAX);
186     int   radius   = VLC_CLIP((sys->radius + 1) & ~1, RADIUS_MIN, RADIUS_MAX);
187     vlc_mutex_unlock(&sys->lock);
188
189     const video_format_t *fmt = &filter->fmt_in.video;
190     struct vf_priv_s *cfg = &sys->cfg;
191
192     cfg->thresh = (1 << 15) / strength;
193     if (cfg->radius != radius) {
194         cfg->radius = radius;
195         cfg->buf    = vlc_memalign(16,
196                                    (((fmt->i_width + 15) & ~15) * (cfg->radius + 1) / 2 + 32) * sizeof(*cfg->buf));
197     }
198
199     for (int i = 0; i < dst->i_planes; i++) {
200         const plane_t *srcp = &src->p[i];
201         plane_t       *dstp = &dst->p[i];
202
203         const vlc_chroma_description_t *chroma = sys->chroma;
204         int w = fmt->i_width  * chroma->p[i].w.num / chroma->p[i].w.den;
205         int h = fmt->i_height * chroma->p[i].h.num / chroma->p[i].h.den;
206         int r = (cfg->radius  * chroma->p[i].w.num / chroma->p[i].w.den +
207                  cfg->radius  * chroma->p[i].h.num / chroma->p[i].h.den) / 2;
208         r = VLC_CLIP((r + 1) & ~1, RADIUS_MIN, RADIUS_MAX);
209         if (__MIN(w, h) > 2 * r && cfg->buf) {
210             filter_plane(cfg, dstp->p_pixels, srcp->p_pixels,
211                          w, h, dstp->i_pitch, srcp->i_pitch, r);
212         } else {
213             plane_CopyPixels(dstp, srcp);
214         }
215     }
216
217     picture_CopyProperties(dst, src);
218     picture_Release(src);
219     return dst;
220 }
221
222 static int Callback(vlc_object_t *object, char const *cmd,
223                     vlc_value_t oldval, vlc_value_t newval, void *data)
224 {
225     filter_t     *filter = (filter_t *)object;
226     filter_sys_t *sys = filter->p_sys;
227     VLC_UNUSED(oldval); VLC_UNUSED(data);
228
229     vlc_mutex_lock(&sys->lock);
230     if (!strcmp(cmd, CFG_PREFIX "strength"))
231         sys->strength = newval.f_float;
232     else
233         sys->radius    = newval.i_int;
234     vlc_mutex_unlock(&sys->lock);
235
236     return VLC_SUCCESS;
237 }
238