1 /*****************************************************************************
2 * colorthres.c: Theshold color based on similarity to reference color
3 *****************************************************************************
4 * Copyright (C) 2000-2006 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 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
36 #include "vlc_filter.h"
38 /*****************************************************************************
40 *****************************************************************************/
41 static int Create ( vlc_object_t * );
42 static void Destroy ( vlc_object_t * );
44 static picture_t *Filter( filter_t *, picture_t * );
46 /*****************************************************************************
48 *****************************************************************************/
49 #define COLOR_TEXT N_("Color")
50 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
51 "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
52 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
53 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
54 static int pi_color_values[] = {
55 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
57 static const char *ppsz_color_descriptions[] = {
58 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
60 #define CFG_PREFIX "colorthres-"
63 set_description( _("Color threshold filter") );
64 set_shortname( _("Color threshold" ));
65 set_category( CAT_VIDEO );
66 set_subcategory( SUBCAT_VIDEO_VFILTER );
67 set_capability( "video filter2", 0 );
68 add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
69 COLOR_LONGTEXT, VLC_FALSE );
70 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
71 add_integer( CFG_PREFIX "saturationthres", 20, NULL,
72 _("Saturaton threshold"), "", VLC_FALSE );
73 add_integer( CFG_PREFIX "similaritythres", 15, NULL,
74 _("Similarity threshold"), "", VLC_FALSE );
75 set_callbacks( Create, Destroy );
78 static const char *ppsz_filter_options[] = {
79 "color", "saturationthes", "similaritythres", NULL
82 /*****************************************************************************
83 * filter_sys_t: adjust filter method descriptor
84 *****************************************************************************/
89 /*****************************************************************************
90 * Create: allocates adjust video thread output method
91 *****************************************************************************
92 * This function allocates and initializes a adjust vout method.
93 *****************************************************************************/
94 static int Create( vlc_object_t *p_this )
96 filter_t *p_filter = (filter_t *)p_this;
98 /* XXX: we might need to add/remove some FOURCCs ... */
99 if( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','0') )
101 msg_Err( p_filter, "Unsupported input chroma (%4s)",
102 (char*)&(p_filter->fmt_in.video.i_chroma) );
106 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
108 msg_Err( p_filter, "Input and output chromas don't match" );
112 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
114 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
115 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "similaritythres" );
116 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "saturationthres" );
118 /* Allocate structure */
119 p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
120 if( p_filter->p_sys == NULL )
122 msg_Err( p_filter, "out of memory" );
126 p_filter->pf_video_filter = Filter;
131 /*****************************************************************************
132 * Destroy: destroy adjust video thread output method
133 *****************************************************************************
134 * Terminate an output method created by adjustCreateOutputMethod
135 *****************************************************************************/
136 static void Destroy( vlc_object_t *p_this )
138 filter_t *p_filter = (filter_t *)p_this;
139 free( p_filter->p_sys );
142 /*****************************************************************************
143 * Render: displays previously rendered output
144 *****************************************************************************
145 * This function send the currently rendered image to adjust modified image,
146 * waits until it is displayed and switch the two rendering buffers, preparing
148 *****************************************************************************/
149 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
152 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
153 uint8_t *p_out_y, *p_out_u, *p_out_v;
154 int i_simthres = var_GetInteger( p_filter, "colorthres-similaritythres" );
155 int i_satthres = var_GetInteger( p_filter, "colorthres-saturationthres" );
156 int i_color = var_GetInteger( p_filter, "colorthres-color" );
158 if( !p_pic ) return NULL;
160 p_outpic = p_filter->pf_vout_buffer_new( p_filter );
163 msg_Warn( p_filter, "can't get output picture" );
164 if( p_pic->pf_release )
165 p_pic->pf_release( p_pic );
169 p_in_u = p_pic->p[U_PLANE].p_pixels;
170 p_in_v = p_pic->p[V_PLANE].p_pixels;
171 p_in_y = p_pic->p[Y_PLANE].p_pixels;
172 p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
173 * p_pic->p[U_PLANE].i_pitch - 8;
175 p_out_y = p_outpic->p[Y_PLANE].p_pixels;
176 p_out_u = p_outpic->p[U_PLANE].p_pixels;
177 p_out_v = p_outpic->p[V_PLANE].p_pixels;
179 /* Create grayscale version of input */
181 pf_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
182 * p_pic->p[Y_PLANE].i_pitch - 8 );
184 pf_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
185 * p_pic->p[U_PLANE].i_pitch - 8 );
187 pf_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
188 * p_pic->p[U_PLANE].i_pitch - 8 );
191 * Do the U and V planes
193 int i_red = ( i_color & 0xFF0000 ) >> 16;
194 int i_green = ( i_color & 0xFF00 ) >> 8;
195 int i_blue = i_color & 0xFF;
196 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
197 112 * i_blue + 128) >> 8) + 128;
198 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
199 18 * i_blue + 128) >> 8) + 128;
200 int refu = i_u - 0x80; /*bright red*/
201 int refv = i_v - 0x80;
202 int reflength = sqrt(refu*refu+refv*refv);
204 while( p_in_u < p_in_end_u ) {
205 /* Length of color vector */
206 int inu = (*p_in_u) - 0x80;
207 int inv = (*p_in_v) - 0x80;
208 int length = sqrt(inu*inu+inv*inv);
210 int diffu = refu * length - inu *reflength;
211 int diffv = refv * length - inv *reflength;
212 long long int difflen2=diffu*diffu;
213 difflen2 +=diffv*diffv;
214 long long int thres = length*reflength;
216 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
219 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
227 p_outpic->date = p_pic->date;
228 p_outpic->b_force = p_pic->b_force;
229 p_outpic->i_nb_fields = p_pic->i_nb_fields;
230 p_outpic->b_progressive = p_pic->b_progressive;
231 p_outpic->b_top_field_first = p_pic->b_top_field_first;
233 if( p_pic->pf_release )
234 p_pic->pf_release( p_pic );