]> git.sesse.net Git - vlc/blob - modules/video_filter/gradfun.c
7c0f47aa8c7b5a24fa4e082a94bc71fbf98737c9
[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                            NULL, RADIUS_TEXT, RADIUS_LONGTEXT, false)
64     add_float_with_range(CFG_PREFIX "strength", 1.2, STRENGTH_MIN, STRENGTH_MAX,
65                          NULL, 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     int              h_shift;
106     int              v_shift;
107     void             *base_buf;
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
115     int h_shift;
116     int v_shift;
117     switch (filter->fmt_in.video.i_chroma) {
118     case VLC_CODEC_I410:
119     case VLC_CODEC_YV9:
120         h_shift = 2; v_shift = 2;
121         break;
122     case VLC_CODEC_I411:
123         h_shift = 2; v_shift = 0;
124         break;
125     case VLC_CODEC_I420:
126     case VLC_CODEC_J420:
127     case VLC_CODEC_YV12:
128         h_shift = 1; v_shift = 1;
129         break;
130     case VLC_CODEC_I422:
131     case VLC_CODEC_J422:
132         h_shift = 1; v_shift = 0;
133         break;
134     case VLC_CODEC_I444:
135     case VLC_CODEC_J444:
136     case VLC_CODEC_YUVA:
137         h_shift = 0; v_shift = 0;
138         break;
139     case VLC_CODEC_I440:
140     case VLC_CODEC_J440:
141         h_shift = 0; v_shift = 1;
142         break;
143     default:
144         return VLC_EGENERIC;
145     }
146
147     filter_sys_t *sys = malloc(sizeof(*sys));
148     if (!sys)
149         return VLC_ENOMEM;
150
151     vlc_mutex_init(&sys->lock);
152     sys->h_shift  = h_shift;
153     sys->v_shift  = v_shift;
154     sys->strength = var_CreateGetFloatCommand(filter,   CFG_PREFIX "strength");
155     sys->radius   = var_CreateGetIntegerCommand(filter, CFG_PREFIX "radius");
156     var_AddCallback(filter, CFG_PREFIX "strength", Callback, NULL);
157     var_AddCallback(filter, CFG_PREFIX "radius",   Callback, NULL);
158     sys->base_buf = NULL;
159
160     struct vf_priv_s *cfg = &sys->cfg;
161     cfg->thresh      = 0.0;
162     cfg->radius      = 0;
163     cfg->buf         = NULL;
164     cfg->filter_line = filter_line_c;
165     cfg->blur_line   = blur_line_c;
166
167 #if HAVE_SSE2 && HAVE_6REGS
168     if (vlc_CPU() & CPU_CAPABILITY_SSE2)
169         cfg->blur_line = blur_line_sse2;
170 #endif
171 #if HAVE_MMX2
172     if (vlc_CPU() & CPU_CAPABILITY_MMXEXT)
173         cfg->filter_line = filter_line_mmx2;
174 #endif
175 #if HAVE_SSSE3
176     if (vlc_CPU() & CPU_CAPABILITY_SSSE3)
177         cfg->filter_line = filter_line_ssse3;
178 #endif
179
180     filter->p_sys           = sys;
181     filter->pf_video_filter = Filter;
182     return VLC_SUCCESS;
183 }
184
185 static void Close(vlc_object_t *object)
186 {
187     filter_t     *filter = (filter_t *)object;
188     filter_sys_t *sys = filter->p_sys;
189
190     free(sys->base_buf);
191     vlc_mutex_destroy(&sys->lock);
192     free(sys);
193 }
194
195 static picture_t *Filter(filter_t *filter, picture_t *src)
196 {
197     filter_sys_t *sys = filter->p_sys;
198
199     picture_t *dst = filter_NewPicture(filter);
200     if (!dst) {
201         picture_Release(src);
202         return NULL;
203     }
204
205     vlc_mutex_lock(&sys->lock);
206     float strength = __MIN(__MAX(sys->strength, STRENGTH_MIN), STRENGTH_MAX);
207     int   radius   = __MIN(__MAX((sys->radius + 1) & ~1, RADIUS_MIN), RADIUS_MAX);
208     vlc_mutex_unlock(&sys->lock);
209
210     const video_format_t *fmt = &filter->fmt_in.video;
211     struct vf_priv_s *cfg = &sys->cfg;
212
213     cfg->thresh = (1 << 15) / strength;
214     if (cfg->radius != radius) {
215         cfg->radius = radius;
216         cfg->buf    = vlc_memalign(&sys->base_buf, 16,
217                                    (((fmt->i_width + 15) & ~15) * (cfg->radius + 1) / 2 + 32) * sizeof(*cfg->buf));
218     }
219
220     for (int i = 0; i < dst->i_planes; i++) {
221         const plane_t *srcp = &src->p[i];
222         plane_t       *dstp = &dst->p[i];
223
224         int w = fmt->i_width;
225         int h = fmt->i_height;
226         int r = cfg->radius;
227         if (i > 0) {
228             w >>= sys->h_shift;
229             h >>= sys->v_shift;
230             r = ((r >> sys->h_shift) + (r >> sys->v_shift)) / 2;
231             r = __MIN(__MAX((r + 1) & ~1, RADIUS_MIN), RADIUS_MAX);
232         }
233         if (__MIN(w, h) > 2 * r && cfg->buf) {
234             filter_plane(cfg, dstp->p_pixels, srcp->p_pixels,
235                          w, h, dstp->i_pitch, srcp->i_pitch, r);
236         } else {
237             plane_CopyPixels(dstp, srcp);
238         }
239     }
240
241     picture_CopyProperties(dst, src);
242     picture_Release(src);
243     return dst;
244 }
245
246 static int Callback(vlc_object_t *object, char const *cmd,
247                     vlc_value_t oldval, vlc_value_t newval, void *data)
248 {
249     filter_t     *filter = (filter_t *)object;
250     filter_sys_t *sys = filter->p_sys;
251     VLC_UNUSED(oldval); VLC_UNUSED(data);
252
253     vlc_mutex_lock(&sys->lock);
254     if (!strcmp(cmd, CFG_PREFIX "strength"))
255         sys->strength = newval.f_float;
256     else
257         sys->radius    = newval.i_int;
258     vlc_mutex_unlock(&sys->lock);
259
260     return VLC_SUCCESS;
261 }
262