]> git.sesse.net Git - vlc/blob - modules/video_filter/colorthres.c
video_filter_rss: factorize and fix object leaks and memleaks.
[vlc] / modules / video_filter / colorthres.c
1 /*****************************************************************************
2  * colorthres.c: Theshold color based on similarity to reference color
3  *****************************************************************************
4  * Copyright (C) 2000-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sigmund Augdal <dnumgis@videolan.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 <errno.h>
33 #include <math.h>
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_sout.h>
38
39 #include <vlc_filter.h>
40 #include "filter_picture.h"
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static int  Create    ( vlc_object_t * );
46 static void Destroy   ( vlc_object_t * );
47
48 static picture_t *Filter( filter_t *, picture_t * );
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53 #define COLOR_TEXT N_("Color")
54 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
55     "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
56     "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
57     " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
58 static const int pi_color_values[] = {
59   0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
60
61 static const char *const ppsz_color_descriptions[] = {
62   N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
63
64 #define CFG_PREFIX "colorthres-"
65
66 vlc_module_begin ()
67     set_description( N_("Color threshold filter") )
68     set_shortname( N_("Color threshold" ))
69     set_category( CAT_VIDEO )
70     set_subcategory( SUBCAT_VIDEO_VFILTER )
71     set_capability( "video filter2", 0 )
72     add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
73                  COLOR_LONGTEXT, false )
74         change_integer_list( pi_color_values, ppsz_color_descriptions, NULL )
75     add_integer( CFG_PREFIX "saturationthres", 20, NULL,
76                  N_("Saturaton threshold"), "", false )
77     add_integer( CFG_PREFIX "similaritythres", 15, NULL,
78                  N_("Similarity threshold"), "", false )
79     set_callbacks( Create, Destroy )
80 vlc_module_end ()
81
82 static const char *const ppsz_filter_options[] = {
83     "color", "saturationthes", "similaritythres", NULL
84 };
85
86 /*****************************************************************************
87  * callback prototypes
88  *****************************************************************************/
89 static int FilterCallback( vlc_object_t *, char const *,
90                            vlc_value_t, vlc_value_t, void * );
91
92
93 /*****************************************************************************
94  * filter_sys_t: adjust filter method descriptor
95  *****************************************************************************/
96 struct filter_sys_t
97 {
98     int i_simthres;
99     int i_satthres;
100     int i_color;
101     vlc_mutex_t lock;
102 };
103
104 /*****************************************************************************
105  * Create: allocates adjust video thread output method
106  *****************************************************************************
107  * This function allocates and initializes a adjust vout method.
108  *****************************************************************************/
109 static int Create( vlc_object_t *p_this )
110 {
111     filter_t *p_filter = (filter_t *)p_this;
112     filter_sys_t *p_sys;
113
114     switch( p_filter->fmt_in.video.i_chroma )
115     {
116         CASE_PLANAR_YUV
117             break;
118
119         default:
120             msg_Err( p_filter, "Unsupported input chroma (%4s)",
121                      (char*)&(p_filter->fmt_in.video.i_chroma) );
122             return VLC_EGENERIC;
123     }
124
125     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
126     {
127         msg_Err( p_filter, "Input and output chromas don't match" );
128         return VLC_EGENERIC;
129     }
130
131     /* Allocate structure */
132     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
133     if( p_filter->p_sys == NULL )
134         return VLC_ENOMEM;
135
136     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
137                        p_filter->p_cfg );
138     p_sys->i_color = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
139     p_sys->i_simthres = var_CreateGetIntegerCommand( p_filter,
140                                                      CFG_PREFIX "similaritythres" );
141     p_sys->i_satthres = var_CreateGetIntegerCommand( p_filter,
142                                                      CFG_PREFIX "saturationthres" );
143
144     vlc_mutex_init( &p_sys->lock );
145
146     var_AddCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
147     var_AddCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
148     var_AddCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
149
150     p_filter->pf_video_filter = Filter;
151
152     return VLC_SUCCESS;
153 }
154
155 /*****************************************************************************
156  * Destroy: destroy adjust video thread output method
157  *****************************************************************************
158  * Terminate an output method created by adjustCreateOutputMethod
159  *****************************************************************************/
160 static void Destroy( vlc_object_t *p_this )
161 {
162     filter_t *p_filter = (filter_t *)p_this;
163
164     var_DelCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
165     var_DelCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
166     var_DelCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
167
168     vlc_mutex_destroy( &p_filter->p_sys->lock );
169     free( p_filter->p_sys );
170 }
171
172 /*****************************************************************************
173  * Render: displays previously rendered output
174  *****************************************************************************
175  * This function send the currently rendered image to adjust modified image,
176  * waits until it is displayed and switch the two rendering buffers, preparing
177  * next frame.
178  *****************************************************************************/
179 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
180 {
181     picture_t *p_outpic;
182     filter_sys_t *p_sys = p_filter->p_sys;
183     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
184     uint8_t *p_out_y, *p_out_u, *p_out_v;
185
186     vlc_mutex_lock( &p_sys->lock );
187     int i_simthres = p_sys->i_simthres;
188     int i_satthres = p_sys->i_satthres;
189     int i_color = p_sys->i_color;
190     vlc_mutex_unlock( &p_sys->lock );
191
192     if( !p_pic ) return NULL;
193
194     p_outpic = filter_NewPicture( p_filter );
195     if( !p_outpic )
196     {
197         picture_Release( p_pic );
198         return NULL;
199     }
200
201     p_in_u = p_pic->p[U_PLANE].p_pixels;
202     p_in_v = p_pic->p[V_PLANE].p_pixels;
203     p_in_y = p_pic->p[Y_PLANE].p_pixels;
204     p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
205                         * p_pic->p[U_PLANE].i_pitch - 8;
206
207     p_out_y = p_outpic->p[Y_PLANE].p_pixels;
208     p_out_u = p_outpic->p[U_PLANE].p_pixels;
209     p_out_v = p_outpic->p[V_PLANE].p_pixels;
210
211     /* Create grayscale version of input */
212     vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
213                * p_pic->p[Y_PLANE].i_pitch - 8 );
214     vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
215                * p_pic->p[U_PLANE].i_pitch - 8 );
216     vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
217                * p_pic->p[U_PLANE].i_pitch - 8 );
218
219     /*
220      * Do the U and V planes
221      */
222     int i_red = ( i_color & 0xFF0000 ) >> 16;
223     int i_green = ( i_color & 0xFF00 ) >> 8;
224     int i_blue = i_color & 0xFF;
225     int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
226                      112 * i_blue + 128) >> 8) + 128;
227     int i_v = (int8_t)(( 112 * i_red  -  94 * i_green -
228                       18 * i_blue + 128) >> 8) + 128;
229     int refu = i_u - 0x80;         /*bright red*/
230     int refv = i_v - 0x80;
231     int reflength = sqrt(refu*refu+refv*refv);
232
233     while( p_in_u < p_in_end_u ) {
234         /* Length of color vector */
235         int inu = (*p_in_u) - 0x80;
236         int inv = (*p_in_v) - 0x80;
237         int length = sqrt(inu*inu+inv*inv);
238
239         int diffu = refu * length - inu *reflength;
240         int diffv = refv * length - inv *reflength;
241         long long int difflen2=diffu*diffu;
242         difflen2 +=diffv*diffv;
243         long long int thres = length*reflength;
244         thres *= thres;
245         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
246             *p_out_u = *p_in_u;
247             *p_out_v = *p_in_v;
248 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
249         }
250         p_in_u++;
251         p_in_v++;
252         p_out_u++;
253         p_out_v++;
254     }
255
256     return CopyInfoAndRelease( p_outpic, p_pic );
257 }
258
259 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
260                             vlc_value_t oldval, vlc_value_t newval, void *p_data )
261 {
262     (void)oldval;    (void)p_data;
263     filter_t *p_filter = (filter_t*)p_this;
264     filter_sys_t *p_sys = p_filter->p_sys;
265
266     if( !strcmp( psz_var, CFG_PREFIX "color" ) )
267     {
268         vlc_mutex_lock( &p_sys->lock );
269         p_sys->i_color = newval.i_int;
270         vlc_mutex_unlock( &p_sys->lock );
271     }
272     else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
273     {
274         vlc_mutex_lock( &p_sys->lock );
275         p_sys->i_simthres = newval.i_int;
276         vlc_mutex_unlock( &p_sys->lock );
277     }
278     else /* CFG_PREFIX "saturationthres" */
279     {
280         vlc_mutex_lock( &p_sys->lock );
281         p_sys->i_satthres = newval.i_int;
282         vlc_mutex_unlock( &p_sys->lock );
283     }
284
285     return VLC_SUCCESS;
286 }