]> git.sesse.net Git - vlc/blob - modules/video_filter/gradfun.c
Use var_InheritString for --decklink-video-connection.
[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     const vlc_chroma_description_t *chroma;
106     void             *base_buf;
107     struct vf_priv_s cfg;
108 };
109
110 static int Open(vlc_object_t *object)
111 {
112     filter_t *filter = (filter_t *)object;
113     const vlc_fourcc_t fourcc = filter->fmt_in.video.i_chroma;
114
115     const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription(fourcc);
116     if (!chroma || chroma->plane_count < 3) {
117         msg_Err(filter, "Unsupported chroma (%4.4s)", (char*)&fourcc);
118         return VLC_EGENERIC;
119     }
120
121     filter_sys_t *sys = malloc(sizeof(*sys));
122     if (!sys)
123         return VLC_ENOMEM;
124
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->base_buf = NULL;
132
133     struct vf_priv_s *cfg = &sys->cfg;
134     cfg->thresh      = 0.0;
135     cfg->radius      = 0;
136     cfg->buf         = NULL;
137     cfg->filter_line = filter_line_c;
138     cfg->blur_line   = blur_line_c;
139
140 #if HAVE_SSE2 && HAVE_6REGS
141     if (vlc_CPU() & CPU_CAPABILITY_SSE2)
142         cfg->blur_line = blur_line_sse2;
143 #endif
144 #if HAVE_MMX2
145     if (vlc_CPU() & CPU_CAPABILITY_MMXEXT)
146         cfg->filter_line = filter_line_mmx2;
147 #endif
148 #if HAVE_SSSE3
149     if (vlc_CPU() & CPU_CAPABILITY_SSSE3)
150         cfg->filter_line = filter_line_ssse3;
151 #endif
152
153     filter->p_sys           = sys;
154     filter->pf_video_filter = Filter;
155     return VLC_SUCCESS;
156 }
157
158 static void Close(vlc_object_t *object)
159 {
160     filter_t     *filter = (filter_t *)object;
161     filter_sys_t *sys = filter->p_sys;
162
163     free(sys->base_buf);
164     vlc_mutex_destroy(&sys->lock);
165     free(sys);
166 }
167
168 static picture_t *Filter(filter_t *filter, picture_t *src)
169 {
170     filter_sys_t *sys = filter->p_sys;
171
172     picture_t *dst = filter_NewPicture(filter);
173     if (!dst) {
174         picture_Release(src);
175         return NULL;
176     }
177
178     vlc_mutex_lock(&sys->lock);
179     float strength = __MIN(__MAX(sys->strength, STRENGTH_MIN), STRENGTH_MAX);
180     int   radius   = __MIN(__MAX((sys->radius + 1) & ~1, RADIUS_MIN), RADIUS_MAX);
181     vlc_mutex_unlock(&sys->lock);
182
183     const video_format_t *fmt = &filter->fmt_in.video;
184     struct vf_priv_s *cfg = &sys->cfg;
185
186     cfg->thresh = (1 << 15) / strength;
187     if (cfg->radius != radius) {
188         cfg->radius = radius;
189         cfg->buf    = vlc_memalign(&sys->base_buf, 16,
190                                    (((fmt->i_width + 15) & ~15) * (cfg->radius + 1) / 2 + 32) * sizeof(*cfg->buf));
191     }
192
193     for (int i = 0; i < dst->i_planes; i++) {
194         const plane_t *srcp = &src->p[i];
195         plane_t       *dstp = &dst->p[i];
196
197         const vlc_chroma_description_t *chroma = sys->chroma;
198         int w = fmt->i_width  * chroma->p[i].w.num / chroma->p[i].w.den;
199         int h = fmt->i_height * chroma->p[i].h.num / chroma->p[i].h.den;
200         int r = (cfg->radius  * chroma->p[i].w.num / chroma->p[i].w.den +
201                  cfg->radius  * chroma->p[i].h.num / chroma->p[i].h.den) / 2;
202         r = __MIN(__MAX((r + 1) & ~1, RADIUS_MIN), RADIUS_MAX);
203         if (__MIN(w, h) > 2 * r && cfg->buf) {
204             filter_plane(cfg, dstp->p_pixels, srcp->p_pixels,
205                          w, h, dstp->i_pitch, srcp->i_pitch, r);
206         } else {
207             plane_CopyPixels(dstp, srcp);
208         }
209     }
210
211     picture_CopyProperties(dst, src);
212     picture_Release(src);
213     return dst;
214 }
215
216 static int Callback(vlc_object_t *object, char const *cmd,
217                     vlc_value_t oldval, vlc_value_t newval, void *data)
218 {
219     filter_t     *filter = (filter_t *)object;
220     filter_sys_t *sys = filter->p_sys;
221     VLC_UNUSED(oldval); VLC_UNUSED(data);
222
223     vlc_mutex_lock(&sys->lock);
224     if (!strcmp(cmd, CFG_PREFIX "strength"))
225         sys->strength = newval.f_float;
226     else
227         sys->radius    = newval.i_int;
228     vlc_mutex_unlock(&sys->lock);
229
230     return VLC_SUCCESS;
231 }
232