1 /*****************************************************************************
2 * colorthres.c: Threshold color based on similarity to reference color
3 *****************************************************************************
4 * Copyright (C) 2000-2009 VLC authors and VideoLAN
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 it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
38 #include <vlc_atomic.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_rgb( CFG_PREFIX "color", 0x00FF0000, COLOR_TEXT,
76 COLOR_LONGTEXT, false )
77 change_integer_list( pi_color_values, ppsz_color_descriptions )
78 add_integer( CFG_PREFIX "saturationthres", 20,
79 N_("Saturation threshold"), "", false )
80 add_integer( CFG_PREFIX "similaritythres", 15,
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 *****************************************************************************/
101 atomic_int i_simthres;
102 atomic_int i_satthres;
106 /*****************************************************************************
107 * Create: allocates adjust video thread output method
108 *****************************************************************************
109 * This function allocates and initializes a adjust vout method.
110 *****************************************************************************/
111 static int Create( vlc_object_t *p_this )
113 filter_t *p_filter = (filter_t *)p_this;
116 switch( p_filter->fmt_in.video.i_chroma )
119 p_filter->pf_video_filter = Filter;
123 p_filter->pf_video_filter = FilterPacked;
127 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
128 (char*)&(p_filter->fmt_in.video.i_chroma) );
132 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
134 msg_Err( p_filter, "Input and output chromas don't match" );
138 /* Allocate structure */
139 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
140 if( p_filter->p_sys == NULL )
143 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
145 atomic_init( &p_sys->i_color,
146 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" ) );
147 atomic_init( &p_sys->i_simthres,
148 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "similaritythres" ) );
149 atomic_init( &p_sys->i_satthres,
150 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "saturationthres" ) );
152 var_AddCallback( p_filter, CFG_PREFIX "color", FilterCallback, p_sys );
153 var_AddCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, p_sys );
154 var_AddCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, p_sys );
159 /*****************************************************************************
160 * Destroy: destroy adjust video thread output method
161 *****************************************************************************
162 * Terminate an output method created by adjustCreateOutputMethod
163 *****************************************************************************/
164 static void Destroy( vlc_object_t *p_this )
166 filter_t *p_filter = (filter_t *)p_this;
167 filter_sys_t *p_sys = p_filter->p_sys;
169 var_DelCallback( p_filter, CFG_PREFIX "color", FilterCallback, p_sys );
170 var_DelCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, p_sys );
171 var_DelCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, p_sys );
175 static void GetReference( int *refu, int *refv, int *reflength,
178 int i_red = ( i_color & 0xFF0000 ) >> 16;
179 int i_green = ( i_color & 0x00FF00 ) >> 8;
180 int i_blue = ( i_color & 0x0000FF );
181 int i_u = (int8_t)(( -38 * i_red - 74 * i_green + 112 * i_blue + 128) >> 8) + 128;
182 int i_v = (int8_t)(( 112 * i_red - 94 * i_green - 18 * i_blue + 128) >> 8) + 128;
185 *reflength = sqrt(*refu * *refu + *refv * *refv);
188 static bool IsSimilar( int u, int v,
189 int refu, int refv, int reflength,
190 int i_satthres, int i_simthres )
192 int length = sqrt(u * u + v * v);
194 int diffu = refu * length - u * reflength;
195 int diffv = refv * length - v * reflength;
196 int64_t difflen2 = diffu * diffu + diffv * diffv;
197 int64_t thres = length * reflength;
199 return length > i_satthres && (difflen2 * i_simthres < thres);
201 /*****************************************************************************
202 * Render: displays previously rendered output
203 *****************************************************************************
204 * This function send the currently rendered image to adjust modified image,
205 * waits until it is displayed and switch the two rendering buffers, preparing
207 *****************************************************************************/
208 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
211 filter_sys_t *p_sys = p_filter->p_sys;
212 int i_simthres = atomic_load( &p_sys->i_simthres );
213 int i_satthres = atomic_load( &p_sys->i_satthres );
214 int i_color = atomic_load( &p_sys->i_color );
216 if( !p_pic ) return NULL;
218 p_outpic = filter_NewPicture( p_filter );
221 picture_Release( p_pic );
225 /* Copy the Y plane */
226 plane_CopyPixels( &p_outpic->p[Y_PLANE], &p_pic->p[Y_PLANE] );
229 * Do the U and V planes
231 int refu, refv, reflength;
232 GetReference( &refu, &refv, &reflength, i_color );
234 for( int y = 0; y < p_pic->p[U_PLANE].i_visible_lines; y++ )
236 uint8_t *p_src_u = &p_pic->p[U_PLANE].p_pixels[y * p_pic->p[U_PLANE].i_pitch];
237 uint8_t *p_src_v = &p_pic->p[V_PLANE].p_pixels[y * p_pic->p[V_PLANE].i_pitch];
238 uint8_t *p_dst_u = &p_outpic->p[U_PLANE].p_pixels[y * p_outpic->p[U_PLANE].i_pitch];
239 uint8_t *p_dst_v = &p_outpic->p[V_PLANE].p_pixels[y * p_outpic->p[V_PLANE].i_pitch];
241 for( int x = 0; x < p_pic->p[U_PLANE].i_visible_pitch; x++ )
243 if( IsSimilar( *p_src_u - 0x80, *p_src_v - 0x80,
244 refu, refv, reflength,
245 i_satthres, i_simthres ) )
248 *p_dst_u++ = *p_src_u;
249 *p_dst_v++ = *p_src_v;
261 return CopyInfoAndRelease( p_outpic, p_pic );
264 static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic )
267 filter_sys_t *p_sys = p_filter->p_sys;
268 int i_simthres = atomic_load( &p_sys->i_simthres );
269 int i_satthres = atomic_load( &p_sys->i_satthres );
270 int i_color = atomic_load( &p_sys->i_color );
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 int i_ret = GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
283 &i_y_offset, &i_u_offset, &i_v_offset );
284 if( i_ret == VLC_EGENERIC )
286 picture_Release( p_pic );
291 * Copy Y and do the U and V planes
293 int refu, refv, reflength;
294 GetReference( &refu, &refv, &reflength, i_color );
296 for( int y = 0; y < p_pic->p->i_visible_lines; y++ )
298 uint8_t *p_src = &p_pic->p->p_pixels[y * p_pic->p->i_pitch];
299 uint8_t *p_dst = &p_outpic->p->p_pixels[y * p_outpic->p->i_pitch];
301 for( int x = 0; x < p_pic->p->i_visible_pitch / 4; x++ )
303 p_dst[i_y_offset + 0] = p_src[i_y_offset + 0];
304 p_dst[i_y_offset + 2] = p_src[i_y_offset + 2];
306 if( IsSimilar( p_src[i_u_offset] - 0x80, p_src[i_v_offset] - 0x80,
307 refu, refv, reflength,
308 i_satthres, i_simthres ) )
310 p_dst[i_u_offset] = p_src[i_u_offset];
311 p_dst[i_v_offset] = p_src[i_v_offset];
315 p_dst[i_u_offset] = 0x80;
316 p_dst[i_v_offset] = 0x80;
324 return CopyInfoAndRelease( p_outpic, p_pic );
327 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
328 vlc_value_t oldval, vlc_value_t newval, void *p_data )
330 filter_sys_t *p_sys = p_data;
332 if( !strcmp( psz_var, CFG_PREFIX "color" ) )
333 atomic_store( &p_sys->i_color, newval.i_int );
334 else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
335 atomic_store( &p_sys->i_simthres, newval.i_int );
336 else /* CFG_PREFIX "saturationthres" */
337 atomic_store( &p_sys->i_satthres, newval.i_int );
339 (void)p_this; (void)oldval;