Remove _GNU_SOURCE and string.h too
[vlc.git] / modules / video_filter / gaussianblur.c
1 /*****************************************************************************
2  * gaussianblur.c : gaussian blur video filter
3  *****************************************************************************
4  * Copyright (C) 2000-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -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 #include <vlc/vlc.h>
29 #include <vlc_vout.h>
30
31 #include "vlc_filter.h"
32
33 #include <math.h>                                          /* exp(), sqrt() */
34
35 /*****************************************************************************
36  * Local prototypes
37  *****************************************************************************/
38 static int  Create    ( vlc_object_t * );
39 static void Destroy   ( vlc_object_t * );
40
41 static picture_t *Filter( filter_t *, picture_t * );
42
43 #define SIGMA_TEXT N_("Gaussian's std deviation")
44 #define SIGMA_LONGTEXT N_( \
45     "Gaussian's standard deviation. The bluring will take " \
46     "into account pixels up to 3*sigma away in any direction.")
47
48 #define FILTER_PREFIX "gaussianblur-"
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 vlc_module_begin();
54     set_description( _("Gaussian blur video filter") );
55     set_shortname( _( "Gaussian Blur" ));
56     set_capability( "video filter2", 0 );
57     set_category( CAT_VIDEO );
58     set_subcategory( SUBCAT_VIDEO_VFILTER );
59
60     add_float( FILTER_PREFIX "sigma", 2., NULL, SIGMA_TEXT, SIGMA_LONGTEXT,
61                VLC_FALSE );
62
63     set_callbacks( Create, Destroy );
64 vlc_module_end();
65
66 static const char *ppsz_filter_options[] = {
67     "sigma", NULL
68 };
69
70 /* Comment this to use floats instead of integers (faster for bigger sigma
71  * values)
72  * For sigma = 2 ints are faster
73  * For sigma = 4 floats are faster
74  */
75 #define DONT_USE_FLOATS
76 struct filter_sys_t
77 {
78     double f_sigma;
79     int i_dim;
80 #ifdef DONT_USE_FLOATS
81     int *pi_distribution;
82     int *pi_buffer;
83     int *pi_scale;
84 #else
85     float *pf_distribution;
86     float *pf_buffer;
87     float *pf_scale;
88 #endif
89 };
90
91 static void gaussianblur_InitDistribution( filter_sys_t *p_sys )
92 {
93     double f_sigma = p_sys->f_sigma;
94     int i_dim = (int)(3.*f_sigma);
95 #ifdef DONT_USE_FLOATS
96     int *pi_distribution = (int*)malloc( (2*i_dim+1) * sizeof( int ) );
97 #else
98     float *pf_distribution = (float*)malloc( (2*i_dim+1) * sizeof( float ) );
99 #endif
100     int x;
101     for( x = -i_dim; x <= i_dim; x++ )
102     {
103 #ifdef DONT_USE_FLOATS
104         pi_distribution[i_dim+x] =
105             (int)( sqrt( exp(-(x*x)/(f_sigma*f_sigma) )
106                  / (2.*M_PI*f_sigma*f_sigma) )  * (double)(1<<8) );
107         printf("%d\n",pi_distribution[i_dim+x]);
108 #else
109         pf_distribution[i_dim+x] = (float)
110             sqrt( exp(-(x*x)/(f_sigma*f_sigma) ) / (2.*M_PI*f_sigma*f_sigma) );
111         printf("%f\n",pf_distribution[i_dim+x]);
112 #endif
113     }
114     p_sys->i_dim = i_dim;
115 #ifdef DONT_USE_FLOATS
116     p_sys->pi_distribution = pi_distribution;
117 #else
118     p_sys->pf_distribution = pf_distribution;
119 #endif
120 }
121
122 static int Create( vlc_object_t *p_this )
123 {
124     filter_t *p_filter = (filter_t *)p_this;
125
126     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
127     if( p_filter->p_sys == NULL )
128     {
129         msg_Err( p_filter, "out of memory" );
130         return VLC_ENOMEM;
131     }
132
133     config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options,
134                        p_filter->p_cfg );
135
136     p_filter->pf_video_filter = Filter;
137
138     p_filter->p_sys->f_sigma =
139         var_CreateGetFloat( p_filter, FILTER_PREFIX "sigma" );
140     if( p_filter->p_sys->f_sigma <= 0. )
141     {
142         msg_Err( p_filter, "sigma must be positive" );
143         return VLC_EGENERIC;
144     }
145     gaussianblur_InitDistribution( p_filter->p_sys );
146     msg_Dbg( p_filter, "gaussian distribution is %d pixels wide",
147              p_filter->p_sys->i_dim*2+1 );
148 #ifdef DONT_USE_FLOATS
149     p_filter->p_sys->pi_buffer = NULL;
150     p_filter->p_sys->pi_scale = NULL;
151 #else
152     p_filter->p_sys->pf_buffer = NULL;
153     p_filter->p_sys->pf_scale = NULL;
154 #endif
155
156     return VLC_SUCCESS;
157 }
158
159 static void Destroy( vlc_object_t *p_this )
160 {
161     filter_t *p_filter = (filter_t *)p_this;
162 #ifdef DONT_USE_FLOATS
163     free( p_filter->p_sys->pi_distribution );
164     free( p_filter->p_sys->pi_buffer );
165     free( p_filter->p_sys->pi_scale );
166 #else
167     free( p_filter->p_sys->pf_distribution );
168     free( p_filter->p_sys->pf_buffer );
169     free( p_filter->p_sys->pf_scale );
170 #endif
171     free( p_filter->p_sys );
172 }
173
174 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
175 {
176     picture_t *p_outpic;
177     filter_sys_t *p_sys = p_filter->p_sys;
178     int i_plane;
179     const int i_dim = p_sys->i_dim;
180 #ifdef DONT_USE_FLOATS
181     int *pi_buffer;
182     int *pi_scale;
183     const int *pi_distribution = p_sys->pi_distribution;
184 #else
185     float *pf_buffer;
186     float *pf_scale;
187     const float *pf_distribution = p_sys->pf_distribution;
188 #endif
189     if( !p_pic ) return NULL;
190
191     p_outpic = p_filter->pf_vout_buffer_new( p_filter );
192     if( !p_outpic )
193     {
194         msg_Warn( p_filter, "can't get output picture" );
195         if( p_pic->pf_release )
196             p_pic->pf_release( p_pic );
197         return NULL;
198     }
199 #ifdef DONT_USE_FLOATS
200     if( !p_sys->pi_buffer )
201     {
202         p_sys->pi_buffer = (int*)realloc( p_sys->pi_buffer,
203                                           p_pic->p[Y_PLANE].i_visible_lines
204                                           * p_pic->p[Y_PLANE].i_pitch
205                                           * sizeof( int ) );
206     }
207     pi_buffer = p_sys->pi_buffer;
208 #else
209     if( !p_sys->pf_buffer )
210     {
211         p_sys->pf_buffer = (float*)realloc( p_sys->pf_buffer,
212                                             p_pic->p[Y_PLANE].i_visible_lines
213                                             * p_pic->p[Y_PLANE].i_pitch
214                                             * sizeof( float ) );
215     }
216     pf_buffer = p_sys->pf_buffer;
217 #endif
218 #ifdef DONT_USE_FLOATS
219     if( !p_sys->pi_scale )
220 #else
221     if( !p_sys->pf_scale )
222 #endif
223     {
224         const int i_visible_lines = p_pic->p[Y_PLANE].i_visible_lines;
225         const int i_visible_pitch = p_pic->p[Y_PLANE].i_visible_pitch;
226         const int i_pitch = p_pic->p[Y_PLANE].i_pitch;
227         int i_col, i_line;
228 #ifdef DONT_USE_FLOATS
229         p_sys->pi_scale = (int*)malloc( i_visible_lines * i_pitch
230                                         * sizeof( int ) );
231         pi_scale = p_sys->pi_scale;
232 #else
233         p_sys->pf_scale = (float*)malloc( i_visible_lines * i_pitch
234                                           * sizeof( float ) );
235         pf_scale = p_sys->pf_scale;
236 #endif
237         for( i_line = 0 ; i_line < i_visible_lines ; i_line++ )
238         {
239             for( i_col = 0; i_col < i_visible_pitch ; i_col++ )
240             {
241                 int x, y;
242 #ifdef DONT_USE_FLOATS
243                 int value = 0;
244 #else
245                 double value = 0.;
246 #endif
247                 for( y = __MAX( -i_dim, -i_line );
248                      y <= __MIN( i_dim, i_visible_lines - i_line - 1 );
249                      y++ )
250                 {
251                     for( x = __MAX( -i_dim, -i_col );
252                          x <= __MIN( i_dim, i_visible_pitch - i_col + 1 );
253                          x++ )
254                     {
255 #ifdef DONT_USE_FLOATS
256                         value += pi_distribution[y+i_dim]
257                                * pi_distribution[x+i_dim];
258 #else
259                         value += ((double)pf_distribution[y+i_dim])
260                                * ((double)pf_distribution[x+i_dim]);
261 #endif
262                     }
263                 }
264 #ifdef DONT_USE_FLOATS
265                 pi_scale[i_line*i_pitch+i_col] = value;
266 #else
267                 pf_scale[i_line*i_pitch+i_col] = (float)(1./value);
268 #endif
269             }
270         }
271     }
272 #ifdef DONT_USE_FLOATS
273     pi_scale = p_sys->pi_scale;
274 #else
275     pf_scale = p_sys->pf_scale;
276 #endif
277
278     for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
279     {
280
281         uint8_t *p_in = p_pic->p[i_plane].p_pixels;
282         uint8_t *p_out = p_outpic->p[i_plane].p_pixels;
283
284         const int i_visible_lines = p_pic->p[i_plane].i_visible_lines;
285         const int i_visible_pitch = p_pic->p[i_plane].i_visible_pitch;
286         const int i_pitch = p_pic->p[i_plane].i_pitch;
287
288         int i_line, i_col;
289         const int factor = i_plane ? 1 : 0;
290
291         for( i_line = 0 ; i_line < i_visible_lines ; i_line++ )
292         {
293             for( i_col = 0; i_col < i_visible_pitch ; i_col++ )
294             {
295 #ifdef DONT_USE_FLOATS
296                 int value = 0;
297 #else
298                 float value = 0.;
299 #endif
300                 int x;
301                 const int c = i_line*i_pitch+i_col;
302                 for( x = __MAX( -i_dim, -i_col*(factor+1) );
303                      x <= __MIN( i_dim, (i_visible_pitch - i_col)*(factor+1) + 1 );
304                      x++ )
305                 {
306 #ifdef DONT_USE_FLOATS
307                     value += pi_distribution[x+i_dim]
308                            * p_in[c+(x>>factor)];
309 #else
310                     value += pf_distribution[x+i_dim]
311                            * (float)p_in[c+(x>>factor)];
312 #endif
313                 }
314 #ifdef DONT_USE_FLOATS
315                 pi_buffer[c] = value;
316 #else
317                 pf_buffer[c] = value;
318 #endif
319             }
320         }
321         for( i_line = 0 ; i_line < i_visible_lines ; i_line++ )
322         {
323             for( i_col = 0; i_col < i_visible_pitch ; i_col++ )
324             {
325 #ifdef DONT_USE_FLOATS
326                 int value = 0;
327 #else
328                 float value = 0.;
329 #endif
330                 int y;
331                 const int c = i_line*i_pitch+i_col;
332                 for( y = __MAX( -i_dim, (-i_line)*(factor+1) );
333                      y <= __MIN( i_dim, (i_visible_lines - i_line)*(factor+1) - 1 );
334                      y++ )
335                 {
336 #ifdef DONT_USE_FLOATS
337                     value += pi_distribution[y+i_dim]
338                            * pi_buffer[c+(y>>factor)*i_pitch];
339 #else
340                     value += pf_distribution[y+i_dim]
341                            * pf_buffer[c+(y>>factor)*i_pitch];
342 #endif
343                 }
344 #ifdef DONT_USE_FLOATS
345                 p_out[c] = (uint8_t)(value/pi_scale[(i_line<<factor)*(i_pitch<<factor)+(i_col<<factor)]);
346 #else
347                 p_out[c] = (uint8_t)(value*pf_scale[(i_line<<factor)*(i_pitch<<factor)+(i_col<<factor)]);
348 #endif
349             }
350         }
351     }
352
353     p_outpic->date = p_pic->date;
354     p_outpic->b_force = p_pic->b_force;
355     p_outpic->i_nb_fields = p_pic->i_nb_fields;
356     p_outpic->b_progressive = p_pic->b_progressive;
357     p_outpic->b_top_field_first = p_pic->b_top_field_first;
358
359     if( p_pic->pf_release )
360         p_pic->pf_release( p_pic );
361
362     return p_outpic;
363 }