1 /*****************************************************************************
2 * colorthres.c: Threshold color based on similarity to reference color
3 *****************************************************************************
4 * Copyright (C) 2000-2009 the VideoLAN team
7 * Authors: Sigmund Augdal <dnumgis@videolan.org>
8 * Antoine Cellerier <dionoea at videolan dot org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
36 #include <vlc_common.h>
37 #include <vlc_plugin.h>
40 #include <vlc_filter.h>
41 #include "filter_picture.h"
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Create ( vlc_object_t * );
47 static void Destroy ( vlc_object_t * );
49 static picture_t *Filter( filter_t *, picture_t * );
50 static picture_t *FilterPacked( filter_t *, picture_t * );
52 /*****************************************************************************
54 *****************************************************************************/
55 #define COLOR_TEXT N_("Color")
56 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
57 "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
58 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
59 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
60 #define COLOR_HELP N_("Select one color in the video")
61 static const int pi_color_values[] = {
62 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
64 static const char *const ppsz_color_descriptions[] = {
65 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
67 #define CFG_PREFIX "colorthres-"
70 set_description( N_("Color threshold filter") )
71 set_shortname( N_("Color threshold" ))
73 set_category( CAT_VIDEO )
74 set_subcategory( SUBCAT_VIDEO_VFILTER )
75 set_capability( "video filter2", 0 )
76 add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
77 COLOR_LONGTEXT, false )
78 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL )
79 add_integer( CFG_PREFIX "saturationthres", 20, NULL,
80 N_("Saturaton threshold"), "", false )
81 add_integer( CFG_PREFIX "similaritythres", 15, NULL,
82 N_("Similarity threshold"), "", false )
83 set_callbacks( Create, Destroy )
86 static const char *const ppsz_filter_options[] = {
87 "color", "saturationthes", "similaritythres", NULL
90 /*****************************************************************************
92 *****************************************************************************/
93 static int FilterCallback( vlc_object_t *, char const *,
94 vlc_value_t, vlc_value_t, void * );
97 /*****************************************************************************
98 * filter_sys_t: adjust filter method descriptor
99 *****************************************************************************/
108 /*****************************************************************************
109 * Create: allocates adjust video thread output method
110 *****************************************************************************
111 * This function allocates and initializes a adjust vout method.
112 *****************************************************************************/
113 static int Create( vlc_object_t *p_this )
115 filter_t *p_filter = (filter_t *)p_this;
118 switch( p_filter->fmt_in.video.i_chroma )
121 p_filter->pf_video_filter = Filter;
125 p_filter->pf_video_filter = FilterPacked;
129 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
130 (char*)&(p_filter->fmt_in.video.i_chroma) );
134 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
136 msg_Err( p_filter, "Input and output chromas don't match" );
140 /* Allocate structure */
141 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
142 if( p_filter->p_sys == NULL )
145 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
147 p_sys->i_color = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
148 p_sys->i_simthres = var_CreateGetIntegerCommand( p_filter,
149 CFG_PREFIX "similaritythres" );
150 p_sys->i_satthres = var_CreateGetIntegerCommand( p_filter,
151 CFG_PREFIX "saturationthres" );
153 vlc_mutex_init( &p_sys->lock );
155 var_AddCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
156 var_AddCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
157 var_AddCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
162 /*****************************************************************************
163 * Destroy: destroy adjust video thread output method
164 *****************************************************************************
165 * Terminate an output method created by adjustCreateOutputMethod
166 *****************************************************************************/
167 static void Destroy( vlc_object_t *p_this )
169 filter_t *p_filter = (filter_t *)p_this;
171 var_DelCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
172 var_DelCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
173 var_DelCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
175 vlc_mutex_destroy( &p_filter->p_sys->lock );
176 free( p_filter->p_sys );
179 /*****************************************************************************
180 * Render: displays previously rendered output
181 *****************************************************************************
182 * This function send the currently rendered image to adjust modified image,
183 * waits until it is displayed and switch the two rendering buffers, preparing
185 *****************************************************************************/
186 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
189 filter_sys_t *p_sys = p_filter->p_sys;
190 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
191 uint8_t *p_out_y, *p_out_u, *p_out_v;
193 vlc_mutex_lock( &p_sys->lock );
194 int i_simthres = p_sys->i_simthres;
195 int i_satthres = p_sys->i_satthres;
196 int i_color = p_sys->i_color;
197 vlc_mutex_unlock( &p_sys->lock );
199 if( !p_pic ) return NULL;
201 p_outpic = filter_NewPicture( p_filter );
204 picture_Release( p_pic );
208 p_in_u = p_pic->p[U_PLANE].p_pixels;
209 p_in_v = p_pic->p[V_PLANE].p_pixels;
210 p_in_y = p_pic->p[Y_PLANE].p_pixels;
211 p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
212 * p_pic->p[U_PLANE].i_pitch - 8;
214 p_out_y = p_outpic->p[Y_PLANE].p_pixels;
215 p_out_u = p_outpic->p[U_PLANE].p_pixels;
216 p_out_v = p_outpic->p[V_PLANE].p_pixels;
218 /* Create grayscale version of input */
219 vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
220 * p_pic->p[Y_PLANE].i_pitch - 8 );
221 vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
222 * p_pic->p[U_PLANE].i_pitch - 8 );
223 vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
224 * p_pic->p[U_PLANE].i_pitch - 8 );
227 * Do the U and V planes
229 int i_red = ( i_color & 0xFF0000 ) >> 16;
230 int i_green = ( i_color & 0xFF00 ) >> 8;
231 int i_blue = i_color & 0xFF;
232 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
233 112 * i_blue + 128) >> 8) + 128;
234 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
235 18 * i_blue + 128) >> 8) + 128;
236 int refu = i_u - 0x80; /*bright red*/
237 int refv = i_v - 0x80;
238 int reflength = sqrt(refu*refu+refv*refv);
240 while( p_in_u < p_in_end_u ) {
241 /* Length of color vector */
242 int inu = (*p_in_u) - 0x80;
243 int inv = (*p_in_v) - 0x80;
244 int length = sqrt(inu*inu+inv*inv);
246 int diffu = refu * length - inu *reflength;
247 int diffv = refv * length - inv *reflength;
248 long long int difflen2=diffu*diffu;
249 difflen2 +=diffv*diffv;
250 long long int thres = length*reflength;
252 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
255 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
263 return CopyInfoAndRelease( p_outpic, p_pic );
266 static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic )
269 filter_sys_t *p_sys = p_filter->p_sys;
270 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
271 uint8_t *p_out_y, *p_out_u, *p_out_v;
273 vlc_mutex_lock( &p_sys->lock );
274 int i_simthres = p_sys->i_simthres;
275 int i_satthres = p_sys->i_satthres;
276 int i_color = p_sys->i_color;
277 vlc_mutex_unlock( &p_sys->lock );
279 if( !p_pic ) return NULL;
281 p_outpic = filter_NewPicture( p_filter );
284 picture_Release( p_pic );
288 int i_y_offset, i_u_offset, i_v_offset;
289 GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
290 &i_y_offset, &i_u_offset, &i_v_offset );
291 p_in_y = p_pic->p->p_pixels+i_y_offset;
292 p_in_u = p_pic->p->p_pixels+i_u_offset;
293 p_in_v = p_pic->p->p_pixels+i_v_offset;
294 p_in_end_u = p_in_u + p_pic->p->i_visible_lines
295 * p_pic->p->i_pitch - 8;
297 p_out_y = p_outpic->p->p_pixels+i_y_offset;
298 p_out_u = p_outpic->p->p_pixels+i_u_offset;
299 p_out_v = p_outpic->p->p_pixels+i_v_offset;
301 /* Create grayscale version of input */
302 vlc_memcpy( p_outpic->p->p_pixels, p_pic->p->p_pixels,
303 p_pic->p->i_visible_lines * p_pic->p->i_pitch - 8 );
306 * Do the U and V planes
308 int i_red = ( i_color & 0xFF0000 ) >> 16;
309 int i_green = ( i_color & 0xFF00 ) >> 8;
310 int i_blue = i_color & 0xFF;
311 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
312 112 * i_blue + 128) >> 8) + 128;
313 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
314 18 * i_blue + 128) >> 8) + 128;
315 int refu = i_u - 0x80; /*bright red*/
316 int refv = i_v - 0x80;
317 int reflength = sqrt(refu*refu+refv*refv);
319 while( p_in_u < p_in_end_u ) {
320 /* Length of color vector */
321 int inu = (*p_in_u) - 0x80;
322 int inv = (*p_in_v) - 0x80;
323 int length = sqrt(inu*inu+inv*inv);
325 int diffu = refu * length - inu *reflength;
326 int diffv = refv * length - inv *reflength;
327 long long int difflen2=diffu*diffu;
328 difflen2 +=diffv*diffv;
329 long long int thres = length*reflength;
331 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
334 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
347 return CopyInfoAndRelease( p_outpic, p_pic );
350 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
351 vlc_value_t oldval, vlc_value_t newval, void *p_data )
353 (void)oldval; (void)p_data;
354 filter_t *p_filter = (filter_t*)p_this;
355 filter_sys_t *p_sys = p_filter->p_sys;
357 if( !strcmp( psz_var, CFG_PREFIX "color" ) )
359 vlc_mutex_lock( &p_sys->lock );
360 p_sys->i_color = newval.i_int;
361 vlc_mutex_unlock( &p_sys->lock );
363 else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
365 vlc_mutex_lock( &p_sys->lock );
366 p_sys->i_simthres = newval.i_int;
367 vlc_mutex_unlock( &p_sys->lock );
369 else /* CFG_PREFIX "saturationthres" */
371 vlc_mutex_lock( &p_sys->lock );
372 p_sys->i_satthres = newval.i_int;
373 vlc_mutex_unlock( &p_sys->lock );