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 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
39 #include <vlc_filter.h>
40 #include "filter_picture.h"
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Create ( vlc_object_t * );
46 static void Destroy ( vlc_object_t * );
48 static picture_t *Filter( filter_t *, picture_t * );
49 static picture_t *FilterPacked( filter_t *, picture_t * );
51 /*****************************************************************************
53 *****************************************************************************/
54 #define COLOR_TEXT N_("Color")
55 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
56 "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
57 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
58 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
59 #define COLOR_HELP N_("Select one color in the video")
60 static const int pi_color_values[] = {
61 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
63 static const char *const ppsz_color_descriptions[] = {
64 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
66 #define CFG_PREFIX "colorthres-"
69 set_description( N_("Color threshold filter") )
70 set_shortname( N_("Color threshold" ))
72 set_category( CAT_VIDEO )
73 set_subcategory( SUBCAT_VIDEO_VFILTER )
74 set_capability( "video filter2", 0 )
75 add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
76 COLOR_LONGTEXT, false )
77 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL )
78 add_integer( CFG_PREFIX "saturationthres", 20, NULL,
79 N_("Saturaton threshold"), "", false )
80 add_integer( CFG_PREFIX "similaritythres", 15, NULL,
81 N_("Similarity threshold"), "", false )
82 set_callbacks( Create, Destroy )
85 static const char *const ppsz_filter_options[] = {
86 "color", "saturationthres", "similaritythres", NULL
89 /*****************************************************************************
91 *****************************************************************************/
92 static int FilterCallback( vlc_object_t *, char const *,
93 vlc_value_t, vlc_value_t, void * );
96 /*****************************************************************************
97 * filter_sys_t: adjust filter method descriptor
98 *****************************************************************************/
107 /*****************************************************************************
108 * Create: allocates adjust video thread output method
109 *****************************************************************************
110 * This function allocates and initializes a adjust vout method.
111 *****************************************************************************/
112 static int Create( vlc_object_t *p_this )
114 filter_t *p_filter = (filter_t *)p_this;
117 switch( p_filter->fmt_in.video.i_chroma )
120 p_filter->pf_video_filter = Filter;
124 p_filter->pf_video_filter = FilterPacked;
128 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
129 (char*)&(p_filter->fmt_in.video.i_chroma) );
133 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
135 msg_Err( p_filter, "Input and output chromas don't match" );
139 /* Allocate structure */
140 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
141 if( p_filter->p_sys == NULL )
144 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
146 p_sys->i_color = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
147 p_sys->i_simthres = var_CreateGetIntegerCommand( p_filter,
148 CFG_PREFIX "similaritythres" );
149 p_sys->i_satthres = var_CreateGetIntegerCommand( p_filter,
150 CFG_PREFIX "saturationthres" );
152 vlc_mutex_init( &p_sys->lock );
154 var_AddCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
155 var_AddCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
156 var_AddCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
161 /*****************************************************************************
162 * Destroy: destroy adjust video thread output method
163 *****************************************************************************
164 * Terminate an output method created by adjustCreateOutputMethod
165 *****************************************************************************/
166 static void Destroy( vlc_object_t *p_this )
168 filter_t *p_filter = (filter_t *)p_this;
170 var_DelCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
171 var_DelCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
172 var_DelCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
174 vlc_mutex_destroy( &p_filter->p_sys->lock );
175 free( p_filter->p_sys );
178 /*****************************************************************************
179 * Render: displays previously rendered output
180 *****************************************************************************
181 * This function send the currently rendered image to adjust modified image,
182 * waits until it is displayed and switch the two rendering buffers, preparing
184 *****************************************************************************/
185 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
188 filter_sys_t *p_sys = p_filter->p_sys;
189 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
190 uint8_t *p_out_y, *p_out_u, *p_out_v;
192 vlc_mutex_lock( &p_sys->lock );
193 int i_simthres = p_sys->i_simthres;
194 int i_satthres = p_sys->i_satthres;
195 int i_color = p_sys->i_color;
196 vlc_mutex_unlock( &p_sys->lock );
198 if( !p_pic ) return NULL;
200 p_outpic = filter_NewPicture( p_filter );
203 picture_Release( p_pic );
207 p_in_u = p_pic->p[U_PLANE].p_pixels;
208 p_in_v = p_pic->p[V_PLANE].p_pixels;
209 p_in_y = p_pic->p[Y_PLANE].p_pixels;
210 p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
211 * p_pic->p[U_PLANE].i_pitch - 8;
213 p_out_y = p_outpic->p[Y_PLANE].p_pixels;
214 p_out_u = p_outpic->p[U_PLANE].p_pixels;
215 p_out_v = p_outpic->p[V_PLANE].p_pixels;
217 /* Create grayscale version of input */
218 vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
219 * p_pic->p[Y_PLANE].i_pitch - 8 );
220 vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
221 * p_pic->p[U_PLANE].i_pitch - 8 );
222 vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
223 * p_pic->p[U_PLANE].i_pitch - 8 );
226 * Do the U and V planes
228 int i_red = ( i_color & 0xFF0000 ) >> 16;
229 int i_green = ( i_color & 0xFF00 ) >> 8;
230 int i_blue = i_color & 0xFF;
231 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
232 112 * i_blue + 128) >> 8) + 128;
233 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
234 18 * i_blue + 128) >> 8) + 128;
235 int refu = i_u - 0x80; /*bright red*/
236 int refv = i_v - 0x80;
237 int reflength = sqrt(refu*refu+refv*refv);
239 while( p_in_u < p_in_end_u ) {
240 /* Length of color vector */
241 int inu = (*p_in_u) - 0x80;
242 int inv = (*p_in_v) - 0x80;
243 int length = sqrt(inu*inu+inv*inv);
245 int diffu = refu * length - inu *reflength;
246 int diffv = refv * length - inv *reflength;
247 long long int difflen2=diffu*diffu;
248 difflen2 +=diffv*diffv;
249 long long int thres = length*reflength;
251 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
254 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
262 return CopyInfoAndRelease( p_outpic, p_pic );
265 static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic )
268 filter_sys_t *p_sys = p_filter->p_sys;
269 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
270 uint8_t *p_out_y, *p_out_u, *p_out_v;
272 vlc_mutex_lock( &p_sys->lock );
273 int i_simthres = p_sys->i_simthres;
274 int i_satthres = p_sys->i_satthres;
275 int i_color = p_sys->i_color;
276 vlc_mutex_unlock( &p_sys->lock );
278 if( !p_pic ) return NULL;
280 p_outpic = filter_NewPicture( p_filter );
283 picture_Release( p_pic );
287 int i_y_offset, i_u_offset, i_v_offset;
288 GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
289 &i_y_offset, &i_u_offset, &i_v_offset );
290 p_in_y = p_pic->p->p_pixels+i_y_offset;
291 p_in_u = p_pic->p->p_pixels+i_u_offset;
292 p_in_v = p_pic->p->p_pixels+i_v_offset;
293 p_in_end_u = p_in_u + p_pic->p->i_visible_lines
294 * p_pic->p->i_pitch - 8;
296 p_out_y = p_outpic->p->p_pixels+i_y_offset;
297 p_out_u = p_outpic->p->p_pixels+i_u_offset;
298 p_out_v = p_outpic->p->p_pixels+i_v_offset;
300 /* Create grayscale version of input */
301 vlc_memcpy( p_outpic->p->p_pixels, p_pic->p->p_pixels,
302 p_pic->p->i_visible_lines * p_pic->p->i_pitch - 8 );
305 * Do the U and V planes
307 int i_red = ( i_color & 0xFF0000 ) >> 16;
308 int i_green = ( i_color & 0xFF00 ) >> 8;
309 int i_blue = i_color & 0xFF;
310 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
311 112 * i_blue + 128) >> 8) + 128;
312 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
313 18 * i_blue + 128) >> 8) + 128;
314 int refu = i_u - 0x80; /*bright red*/
315 int refv = i_v - 0x80;
316 int reflength = sqrt(refu*refu+refv*refv);
318 while( p_in_u < p_in_end_u ) {
319 /* Length of color vector */
320 int inu = (*p_in_u) - 0x80;
321 int inv = (*p_in_v) - 0x80;
322 int length = sqrt(inu*inu+inv*inv);
324 int diffu = refu * length - inu *reflength;
325 int diffv = refv * length - inv *reflength;
326 long long int difflen2=diffu*diffu;
327 difflen2 +=diffv*diffv;
328 long long int thres = length*reflength;
330 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
333 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
346 return CopyInfoAndRelease( p_outpic, p_pic );
349 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
350 vlc_value_t oldval, vlc_value_t newval, void *p_data )
352 (void)oldval; (void)p_data;
353 filter_t *p_filter = (filter_t*)p_this;
354 filter_sys_t *p_sys = p_filter->p_sys;
356 if( !strcmp( psz_var, CFG_PREFIX "color" ) )
358 vlc_mutex_lock( &p_sys->lock );
359 p_sys->i_color = newval.i_int;
360 vlc_mutex_unlock( &p_sys->lock );
362 else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
364 vlc_mutex_lock( &p_sys->lock );
365 p_sys->i_simthres = newval.i_int;
366 vlc_mutex_unlock( &p_sys->lock );
368 else /* CFG_PREFIX "saturationthres" */
370 vlc_mutex_lock( &p_sys->lock );
371 p_sys->i_satthres = newval.i_int;
372 vlc_mutex_unlock( &p_sys->lock );