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>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
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 * );
50 /*****************************************************************************
52 *****************************************************************************/
53 #define COLOR_TEXT N_("Color")
54 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
55 "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
56 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
57 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
58 #define COLOR_HELP N_("Select one color in the video")
59 static const int pi_color_values[] = {
60 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
62 static const char *const ppsz_color_descriptions[] = {
63 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
65 #define CFG_PREFIX "colorthres-"
68 set_description( N_("Color threshold filter") )
69 set_shortname( N_("Color threshold" ))
71 set_category( CAT_VIDEO )
72 set_subcategory( SUBCAT_VIDEO_VFILTER )
73 set_capability( "video filter2", 0 )
74 add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
75 COLOR_LONGTEXT, false )
76 change_integer_list( pi_color_values, ppsz_color_descriptions, NULL )
77 add_integer( CFG_PREFIX "saturationthres", 20, NULL,
78 N_("Saturaton threshold"), "", false )
79 add_integer( CFG_PREFIX "similaritythres", 15, NULL,
80 N_("Similarity threshold"), "", false )
81 set_callbacks( Create, Destroy )
84 static const char *const ppsz_filter_options[] = {
85 "color", "saturationthes", "similaritythres", NULL
88 /*****************************************************************************
90 *****************************************************************************/
91 static int FilterCallback( vlc_object_t *, char const *,
92 vlc_value_t, vlc_value_t, void * );
95 /*****************************************************************************
96 * filter_sys_t: adjust filter method descriptor
97 *****************************************************************************/
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 )
122 msg_Err( p_filter, "Unsupported input chroma (%4s)",
123 (char*)&(p_filter->fmt_in.video.i_chroma) );
127 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
129 msg_Err( p_filter, "Input and output chromas don't match" );
133 /* Allocate structure */
134 p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
135 if( p_filter->p_sys == NULL )
138 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
140 p_sys->i_color = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
141 p_sys->i_simthres = var_CreateGetIntegerCommand( p_filter,
142 CFG_PREFIX "similaritythres" );
143 p_sys->i_satthres = var_CreateGetIntegerCommand( p_filter,
144 CFG_PREFIX "saturationthres" );
146 vlc_mutex_init( &p_sys->lock );
148 var_AddCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
149 var_AddCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
150 var_AddCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
152 p_filter->pf_video_filter = Filter;
157 /*****************************************************************************
158 * Destroy: destroy adjust video thread output method
159 *****************************************************************************
160 * Terminate an output method created by adjustCreateOutputMethod
161 *****************************************************************************/
162 static void Destroy( vlc_object_t *p_this )
164 filter_t *p_filter = (filter_t *)p_this;
166 var_DelCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
167 var_DelCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
168 var_DelCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
170 vlc_mutex_destroy( &p_filter->p_sys->lock );
171 free( p_filter->p_sys );
174 /*****************************************************************************
175 * Render: displays previously rendered output
176 *****************************************************************************
177 * This function send the currently rendered image to adjust modified image,
178 * waits until it is displayed and switch the two rendering buffers, preparing
180 *****************************************************************************/
181 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
184 filter_sys_t *p_sys = p_filter->p_sys;
185 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
186 uint8_t *p_out_y, *p_out_u, *p_out_v;
188 vlc_mutex_lock( &p_sys->lock );
189 int i_simthres = p_sys->i_simthres;
190 int i_satthres = p_sys->i_satthres;
191 int i_color = p_sys->i_color;
192 vlc_mutex_unlock( &p_sys->lock );
194 if( !p_pic ) return NULL;
196 p_outpic = filter_NewPicture( p_filter );
199 picture_Release( p_pic );
203 p_in_u = p_pic->p[U_PLANE].p_pixels;
204 p_in_v = p_pic->p[V_PLANE].p_pixels;
205 p_in_y = p_pic->p[Y_PLANE].p_pixels;
206 p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
207 * p_pic->p[U_PLANE].i_pitch - 8;
209 p_out_y = p_outpic->p[Y_PLANE].p_pixels;
210 p_out_u = p_outpic->p[U_PLANE].p_pixels;
211 p_out_v = p_outpic->p[V_PLANE].p_pixels;
213 /* Create grayscale version of input */
214 vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
215 * p_pic->p[Y_PLANE].i_pitch - 8 );
216 vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
217 * p_pic->p[U_PLANE].i_pitch - 8 );
218 vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
219 * p_pic->p[U_PLANE].i_pitch - 8 );
222 * Do the U and V planes
224 int i_red = ( i_color & 0xFF0000 ) >> 16;
225 int i_green = ( i_color & 0xFF00 ) >> 8;
226 int i_blue = i_color & 0xFF;
227 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
228 112 * i_blue + 128) >> 8) + 128;
229 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
230 18 * i_blue + 128) >> 8) + 128;
231 int refu = i_u - 0x80; /*bright red*/
232 int refv = i_v - 0x80;
233 int reflength = sqrt(refu*refu+refv*refv);
235 while( p_in_u < p_in_end_u ) {
236 /* Length of color vector */
237 int inu = (*p_in_u) - 0x80;
238 int inv = (*p_in_v) - 0x80;
239 int length = sqrt(inu*inu+inv*inv);
241 int diffu = refu * length - inu *reflength;
242 int diffv = refv * length - inv *reflength;
243 long long int difflen2=diffu*diffu;
244 difflen2 +=diffv*diffv;
245 long long int thres = length*reflength;
247 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
250 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
258 return CopyInfoAndRelease( p_outpic, p_pic );
261 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
262 vlc_value_t oldval, vlc_value_t newval, void *p_data )
264 (void)oldval; (void)p_data;
265 filter_t *p_filter = (filter_t*)p_this;
266 filter_sys_t *p_sys = p_filter->p_sys;
268 if( !strcmp( psz_var, CFG_PREFIX "color" ) )
270 vlc_mutex_lock( &p_sys->lock );
271 p_sys->i_color = newval.i_int;
272 vlc_mutex_unlock( &p_sys->lock );
274 else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
276 vlc_mutex_lock( &p_sys->lock );
277 p_sys->i_simthres = newval.i_int;
278 vlc_mutex_unlock( &p_sys->lock );
280 else /* CFG_PREFIX "saturationthres" */
282 vlc_mutex_lock( &p_sys->lock );
283 p_sys->i_satthres = newval.i_int;
284 vlc_mutex_unlock( &p_sys->lock );