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;
190 vlc_mutex_lock( &p_sys->lock );
191 int i_simthres = p_sys->i_simthres;
192 int i_satthres = p_sys->i_satthres;
193 int i_color = p_sys->i_color;
194 vlc_mutex_unlock( &p_sys->lock );
196 if( !p_pic ) return NULL;
198 p_outpic = filter_NewPicture( p_filter );
201 picture_Release( p_pic );
205 /* Copy the Y plane */
206 plane_CopyPixels( &p_outpic->p[Y_PLANE], &p_pic->p[Y_PLANE] );
209 * Do the U and V planes
211 int i_red = ( i_color & 0xFF0000 ) >> 16;
212 int i_green = ( i_color & 0xFF00 ) >> 8;
213 int i_blue = i_color & 0xFF;
214 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
215 112 * i_blue + 128) >> 8) + 128;
216 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
217 18 * i_blue + 128) >> 8) + 128;
219 int refu = i_u - 0x80; /*bright red*/
220 int refv = i_v - 0x80;
221 int reflength = sqrt(refu*refu+refv*refv);
223 for( int y = 0; y < p_pic->p[U_PLANE].i_visible_lines; y++ )
225 uint8_t *p_src_u = &p_pic->p[U_PLANE].p_pixels[y * p_pic->p[U_PLANE].i_pitch];
226 uint8_t *p_src_v = &p_pic->p[V_PLANE].p_pixels[y * p_pic->p[V_PLANE].i_pitch];
227 uint8_t *p_dst_u = &p_outpic->p[U_PLANE].p_pixels[y * p_outpic->p[U_PLANE].i_pitch];
228 uint8_t *p_dst_v = &p_outpic->p[V_PLANE].p_pixels[y * p_outpic->p[V_PLANE].i_pitch];
230 for( int x = 0; x < p_pic->p[U_PLANE].i_visible_pitch; x++ )
232 /* Length of color vector */
233 int inu = *p_src_u - 0x80;
234 int inv = *p_src_v - 0x80;
235 int length = sqrt(inu*inu+inv*inv);
237 int diffu = refu * length - inu *reflength;
238 int diffv = refv * length - inv *reflength;
239 long long int difflen2=diffu*diffu;
240 difflen2 +=diffv*diffv;
241 long long int thres = length*reflength;
243 if( length > i_satthres && (difflen2*i_simthres< thres ) )
245 *p_dst_u++ = *p_src_u;
246 *p_dst_v++ = *p_src_v;
258 return CopyInfoAndRelease( p_outpic, p_pic );
261 static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic )
264 filter_sys_t *p_sys = p_filter->p_sys;
266 vlc_mutex_lock( &p_sys->lock );
267 int i_simthres = p_sys->i_simthres;
268 int i_satthres = p_sys->i_satthres;
269 int i_color = p_sys->i_color;
270 vlc_mutex_unlock( &p_sys->lock );
272 if( !p_pic ) return NULL;
274 p_outpic = filter_NewPicture( p_filter );
277 picture_Release( p_pic );
281 int i_y_offset, i_u_offset, i_v_offset;
282 GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
283 &i_y_offset, &i_u_offset, &i_v_offset );
286 * Copy Y and do the U and V planes
288 int i_red = ( i_color & 0xFF0000 ) >> 16;
289 int i_green = ( i_color & 0xFF00 ) >> 8;
290 int i_blue = i_color & 0xFF;
291 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
292 112 * i_blue + 128) >> 8) + 128;
293 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
294 18 * i_blue + 128) >> 8) + 128;
295 int refu = i_u - 0x80; /*bright red*/
296 int refv = i_v - 0x80;
297 int reflength = sqrt(refu*refu+refv*refv);
299 for( int y = 0; y < p_pic->p->i_visible_lines; y++ )
301 uint8_t *p_src = &p_pic->p->p_pixels[y * p_pic->p->i_pitch];
302 uint8_t *p_dst = &p_outpic->p->p_pixels[y * p_outpic->p->i_pitch];
304 for( int x = 0; x < p_pic->p->i_visible_pitch / 4; x++ )
306 p_dst[i_y_offset + 0] = p_src[i_y_offset + 0];
307 p_dst[i_y_offset + 2] = p_src[i_y_offset + 2];
309 /* Length of color vector */
310 int inu = p_src[i_u_offset] - 0x80;
311 int inv = p_src[i_v_offset] - 0x80;
312 int length = sqrt(inu*inu+inv*inv);
314 int diffu = refu * length - inu *reflength;
315 int diffv = refv * length - inv *reflength;
316 long long int difflen2=diffu*diffu;
317 difflen2 +=diffv*diffv;
318 long long int thres = length*reflength;
320 if( length > i_satthres && (difflen2*i_simthres< thres ) )
322 p_dst[i_u_offset] = p_src[i_u_offset];
323 p_dst[i_v_offset] = p_src[i_v_offset];
327 p_dst[i_u_offset] = 0x80;
328 p_dst[i_v_offset] = 0x80;
336 return CopyInfoAndRelease( p_outpic, p_pic );
339 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
340 vlc_value_t oldval, vlc_value_t newval, void *p_data )
342 (void)oldval; (void)p_data;
343 filter_t *p_filter = (filter_t*)p_this;
344 filter_sys_t *p_sys = p_filter->p_sys;
346 if( !strcmp( psz_var, CFG_PREFIX "color" ) )
348 vlc_mutex_lock( &p_sys->lock );
349 p_sys->i_color = newval.i_int;
350 vlc_mutex_unlock( &p_sys->lock );
352 else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
354 vlc_mutex_lock( &p_sys->lock );
355 p_sys->i_simthres = newval.i_int;
356 vlc_mutex_unlock( &p_sys->lock );
358 else /* CFG_PREFIX "saturationthres" */
360 vlc_mutex_lock( &p_sys->lock );
361 p_sys->i_satthres = newval.i_int;
362 vlc_mutex_unlock( &p_sys->lock );