]> git.sesse.net Git - vlc/blob - modules/video_filter/gradfun.c
Qt: fix compilation on Win32, and use a decent minimum
[vlc] / modules / video_filter / gradfun.c
1 /*****************************************************************************
2  * gradfun.c: wrapper for the gradfun filter from mplayer
3  *****************************************************************************
4  * Copyright (C) 2010 Laurent Aimar
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_cpu.h>
35 #include <vlc_filter.h>
36
37 /*****************************************************************************
38  * Module descriptor
39  *****************************************************************************/
40 static int  Open (vlc_object_t *);
41 static void Close(vlc_object_t *);
42
43 #define CFG_PREFIX "gradfun-"
44
45 #define RADIUS_MIN (4)
46 #define RADIUS_MAX (32)
47 #define RADIUS_TEXT N_("Radius")
48 #define RADIUS_LONGTEXT N_("Radius in pixels")
49
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")
54
55 vlc_module_begin()
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)
66
67     set_callbacks(Open, Close)
68 vlc_module_end()
69
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 "gradfun.h"
97
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 *);
100
101 struct filter_sys_t {
102     vlc_mutex_t      lock;
103     float            strength;
104     int              radius;
105     const vlc_chroma_description_t *chroma;
106     struct vf_priv_s cfg;
107 };
108
109 static int Open(vlc_object_t *object)
110 {
111     filter_t *filter = (filter_t *)object;
112     const vlc_fourcc_t fourcc = filter->fmt_in.video.i_chroma;
113
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);
117         return VLC_EGENERIC;
118     }
119
120     filter_sys_t *sys = malloc(sizeof(*sys));
121     if (!sys)
122         return VLC_ENOMEM;
123
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);
130     sys->cfg.buf = NULL;
131
132     struct vf_priv_s *cfg = &sys->cfg;
133     cfg->thresh      = 0.0;
134     cfg->radius      = 0;
135     cfg->buf         = NULL;
136     cfg->filter_line = filter_line_c;
137     cfg->blur_line   = blur_line_c;
138
139 #if HAVE_SSE2 && HAVE_6REGS
140     if (vlc_CPU() & CPU_CAPABILITY_SSE2)
141         cfg->blur_line = blur_line_sse2;
142 #endif
143 #if HAVE_MMX2
144     if (vlc_CPU() & CPU_CAPABILITY_MMXEXT)
145         cfg->filter_line = filter_line_mmx2;
146 #endif
147 #if HAVE_SSSE3
148     if (vlc_CPU() & CPU_CAPABILITY_SSSE3)
149         cfg->filter_line = filter_line_ssse3;
150 #endif
151
152     filter->p_sys           = sys;
153     filter->pf_video_filter = Filter;
154     return VLC_SUCCESS;
155 }
156
157 static void Close(vlc_object_t *object)
158 {
159     filter_t     *filter = (filter_t *)object;
160     filter_sys_t *sys = filter->p_sys;
161
162     var_DelCallback(filter, CFG_PREFIX "radius",   Callback, NULL);
163     var_DelCallback(filter, CFG_PREFIX "strength", Callback, NULL);
164     free(sys->cfg.buf);
165     vlc_mutex_destroy(&sys->lock);
166     free(sys);
167 }
168
169 static picture_t *Filter(filter_t *filter, picture_t *src)
170 {
171     filter_sys_t *sys = filter->p_sys;
172
173     picture_t *dst = filter_NewPicture(filter);
174     if (!dst) {
175         picture_Release(src);
176         return NULL;
177     }
178
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);
183
184     const video_format_t *fmt = &filter->fmt_in.video;
185     struct vf_priv_s *cfg = &sys->cfg;
186
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));
192     }
193
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];
197
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);
207         } else {
208             plane_CopyPixels(dstp, srcp);
209         }
210     }
211
212     picture_CopyProperties(dst, src);
213     picture_Release(src);
214     return dst;
215 }
216
217 static int Callback(vlc_object_t *object, char const *cmd,
218                     vlc_value_t oldval, vlc_value_t newval, void *data)
219 {
220     filter_t     *filter = (filter_t *)object;
221     filter_sys_t *sys = filter->p_sys;
222     VLC_UNUSED(oldval); VLC_UNUSED(data);
223
224     vlc_mutex_lock(&sys->lock);
225     if (!strcmp(cmd, CFG_PREFIX "strength"))
226         sys->strength = newval.f_float;
227     else
228         sys->radius    = newval.i_int;
229     vlc_mutex_unlock(&sys->lock);
230
231     return VLC_SUCCESS;
232 }
233