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 static void GetReference( int *refu, int *refv, int *reflength,
181 int i_red = ( i_color & 0xFF0000 ) >> 16;
182 int i_green = ( i_color & 0x00FF00 ) >> 8;
183 int i_blue = ( i_color & 0x0000FF );
184 int i_u = (int8_t)(( -38 * i_red - 74 * i_green + 112 * i_blue + 128) >> 8) + 128;
185 int i_v = (int8_t)(( 112 * i_red - 94 * i_green - 18 * i_blue + 128) >> 8) + 128;
188 *reflength = sqrt(*refu * *refu + *refv * *refv);
191 static bool IsSimilar( int u, int v,
192 int refu, int refv, int reflength,
193 int i_satthres, int i_simthres )
195 int length = sqrt(u * u + v * v);
197 int diffu = refu * length - u * reflength;
198 int diffv = refv * length - v * reflength;
199 int64_t difflen2 = diffu * diffu + diffv * diffv;
200 int64_t thres = length * reflength;
202 return length > i_satthres && (difflen2 * i_simthres < thres);
204 /*****************************************************************************
205 * Render: displays previously rendered output
206 *****************************************************************************
207 * This function send the currently rendered image to adjust modified image,
208 * waits until it is displayed and switch the two rendering buffers, preparing
210 *****************************************************************************/
211 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
214 filter_sys_t *p_sys = p_filter->p_sys;
216 vlc_mutex_lock( &p_sys->lock );
217 int i_simthres = p_sys->i_simthres;
218 int i_satthres = p_sys->i_satthres;
219 int i_color = p_sys->i_color;
220 vlc_mutex_unlock( &p_sys->lock );
222 if( !p_pic ) return NULL;
224 p_outpic = filter_NewPicture( p_filter );
227 picture_Release( p_pic );
231 /* Copy the Y plane */
232 plane_CopyPixels( &p_outpic->p[Y_PLANE], &p_pic->p[Y_PLANE] );
235 * Do the U and V planes
237 int refu, refv, reflength;
238 GetReference( &refu, &refv, &reflength, i_color );
240 for( int y = 0; y < p_pic->p[U_PLANE].i_visible_lines; y++ )
242 uint8_t *p_src_u = &p_pic->p[U_PLANE].p_pixels[y * p_pic->p[U_PLANE].i_pitch];
243 uint8_t *p_src_v = &p_pic->p[V_PLANE].p_pixels[y * p_pic->p[V_PLANE].i_pitch];
244 uint8_t *p_dst_u = &p_outpic->p[U_PLANE].p_pixels[y * p_outpic->p[U_PLANE].i_pitch];
245 uint8_t *p_dst_v = &p_outpic->p[V_PLANE].p_pixels[y * p_outpic->p[V_PLANE].i_pitch];
247 for( int x = 0; x < p_pic->p[U_PLANE].i_visible_pitch; x++ )
249 if( IsSimilar( *p_src_u - 0x80, *p_src_v - 0x80,
250 refu, refv, reflength,
251 i_satthres, i_simthres ) )
254 *p_dst_u++ = *p_src_u;
255 *p_dst_v++ = *p_src_v;
267 return CopyInfoAndRelease( p_outpic, p_pic );
270 static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic )
273 filter_sys_t *p_sys = p_filter->p_sys;
275 vlc_mutex_lock( &p_sys->lock );
276 int i_simthres = p_sys->i_simthres;
277 int i_satthres = p_sys->i_satthres;
278 int i_color = p_sys->i_color;
279 vlc_mutex_unlock( &p_sys->lock );
281 if( !p_pic ) return NULL;
283 p_outpic = filter_NewPicture( p_filter );
286 picture_Release( p_pic );
290 int i_y_offset = 0, i_u_offset = 0, i_v_offset = 0;
291 GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
292 &i_y_offset, &i_u_offset, &i_v_offset );
295 * Copy Y and do the U and V planes
297 int refu, refv, reflength;
298 GetReference( &refu, &refv, &reflength, i_color );
300 for( int y = 0; y < p_pic->p->i_visible_lines; y++ )
302 uint8_t *p_src = &p_pic->p->p_pixels[y * p_pic->p->i_pitch];
303 uint8_t *p_dst = &p_outpic->p->p_pixels[y * p_outpic->p->i_pitch];
305 for( int x = 0; x < p_pic->p->i_visible_pitch / 4; x++ )
307 p_dst[i_y_offset + 0] = p_src[i_y_offset + 0];
308 p_dst[i_y_offset + 2] = p_src[i_y_offset + 2];
310 if( IsSimilar( p_src[i_u_offset] - 0x80, p_src[i_v_offset] - 0x80,
311 refu, refv, reflength,
312 i_satthres, i_simthres ) )
314 p_dst[i_u_offset] = p_src[i_u_offset];
315 p_dst[i_v_offset] = p_src[i_v_offset];
319 p_dst[i_u_offset] = 0x80;
320 p_dst[i_v_offset] = 0x80;
328 return CopyInfoAndRelease( p_outpic, p_pic );
331 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
332 vlc_value_t oldval, vlc_value_t newval, void *p_data )
334 (void)oldval; (void)p_data;
335 filter_t *p_filter = (filter_t*)p_this;
336 filter_sys_t *p_sys = p_filter->p_sys;
338 if( !strcmp( psz_var, CFG_PREFIX "color" ) )
340 vlc_mutex_lock( &p_sys->lock );
341 p_sys->i_color = newval.i_int;
342 vlc_mutex_unlock( &p_sys->lock );
344 else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
346 vlc_mutex_lock( &p_sys->lock );
347 p_sys->i_simthres = newval.i_int;
348 vlc_mutex_unlock( &p_sys->lock );
350 else /* CFG_PREFIX "saturationthres" */
352 vlc_mutex_lock( &p_sys->lock );
353 p_sys->i_satthres = newval.i_int;
354 vlc_mutex_unlock( &p_sys->lock );