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 *****************************************************************************/
34 #include "vlc_filter.h"
36 /*****************************************************************************
38 *****************************************************************************/
39 static int Create ( vlc_object_t * );
40 static void Destroy ( vlc_object_t * );
42 static picture_t *Filter( filter_t *, picture_t * );
44 /*****************************************************************************
46 *****************************************************************************/
47 #define COLOR_TEXT N_("Color")
48 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
49 "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
50 "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
51 " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
52 static int pi_color_values[] = {
53 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
55 static const char *ppsz_color_descriptions[] = {
56 N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
58 #define CFG_PREFIX "colorthres-"
61 set_description( _("Color threshold filter") );
62 set_shortname( _("Color threshold" ));
63 set_category( CAT_VIDEO );
64 set_subcategory( SUBCAT_VIDEO_VFILTER );
65 set_capability( "video filter2", 0 );
66 add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
67 COLOR_LONGTEXT, VLC_FALSE );
68 change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
69 add_integer( CFG_PREFIX "saturationthres", 20, NULL,
70 _("Saturaton threshold"), "", VLC_FALSE );
71 add_integer( CFG_PREFIX "similaritythres", 15, NULL,
72 _("Similarity threshold"), "", VLC_FALSE );
73 set_callbacks( Create, Destroy );
76 static const char *ppsz_filter_options[] = {
77 "color", "saturationthes", "similaritythres", NULL
80 /*****************************************************************************
81 * filter_sys_t: adjust filter method descriptor
82 *****************************************************************************/
87 /*****************************************************************************
88 * Create: allocates adjust video thread output method
89 *****************************************************************************
90 * This function allocates and initializes a adjust vout method.
91 *****************************************************************************/
92 static int Create( vlc_object_t *p_this )
94 filter_t *p_filter = (filter_t *)p_this;
96 /* XXX: we might need to add/remove some FOURCCs ... */
97 if( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','0')
98 && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','Y','U','V')
99 && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('J','4','2','0')
100 && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','V','1','2')
102 && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','2')
103 && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('J','4','2','2') )
105 msg_Err( p_filter, "Unsupported input chroma (%4s)",
106 (char*)&(p_filter->fmt_in.video.i_chroma) );
110 if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
112 msg_Err( p_filter, "Input and output chromas don't match" );
116 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
118 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
119 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "similaritythres" );
120 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "saturationthres" );
122 /* Allocate structure */
123 p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
124 if( p_filter->p_sys == NULL )
126 msg_Err( p_filter, "out of memory" );
130 p_filter->pf_video_filter = Filter;
135 /*****************************************************************************
136 * Destroy: destroy adjust video thread output method
137 *****************************************************************************
138 * Terminate an output method created by adjustCreateOutputMethod
139 *****************************************************************************/
140 static void Destroy( vlc_object_t *p_this )
142 filter_t *p_filter = (filter_t *)p_this;
143 free( p_filter->p_sys );
146 /*****************************************************************************
147 * Render: displays previously rendered output
148 *****************************************************************************
149 * This function send the currently rendered image to adjust modified image,
150 * waits until it is displayed and switch the two rendering buffers, preparing
152 *****************************************************************************/
153 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
156 uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
157 uint8_t *p_out_y, *p_out_u, *p_out_v;
158 int i_simthres = var_GetInteger( p_filter, "colorthres-similaritythres" );
159 int i_satthres = var_GetInteger( p_filter, "colorthres-saturationthres" );
160 int i_color = var_GetInteger( p_filter, "colorthres-color" );
162 if( !p_pic ) return NULL;
164 p_outpic = p_filter->pf_vout_buffer_new( p_filter );
167 msg_Warn( p_filter, "can't get output picture" );
168 if( p_pic->pf_release )
169 p_pic->pf_release( p_pic );
173 p_in_u = p_pic->p[U_PLANE].p_pixels;
174 p_in_v = p_pic->p[V_PLANE].p_pixels;
175 p_in_y = p_pic->p[Y_PLANE].p_pixels;
176 p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
177 * p_pic->p[U_PLANE].i_pitch - 8;
179 p_out_y = p_outpic->p[Y_PLANE].p_pixels;
180 p_out_u = p_outpic->p[U_PLANE].p_pixels;
181 p_out_v = p_outpic->p[V_PLANE].p_pixels;
183 /* Create grayscale version of input */
185 pf_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
186 * p_pic->p[Y_PLANE].i_pitch - 8 );
188 pf_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
189 * p_pic->p[U_PLANE].i_pitch - 8 );
191 pf_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
192 * p_pic->p[U_PLANE].i_pitch - 8 );
195 * Do the U and V planes
197 int i_red = ( i_color & 0xFF0000 ) >> 16;
198 int i_green = ( i_color & 0xFF00 ) >> 8;
199 int i_blue = i_color & 0xFF;
200 int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
201 112 * i_blue + 128) >> 8) + 128;
202 int i_v = (int8_t)(( 112 * i_red - 94 * i_green -
203 18 * i_blue + 128) >> 8) + 128;
204 int refu = i_u - 0x80; /*bright red*/
205 int refv = i_v - 0x80;
206 int reflength = sqrt(refu*refu+refv*refv);
208 while( p_in_u < p_in_end_u ) {
209 /* Length of color vector */
210 int inu = (*p_in_u) - 0x80;
211 int inv = (*p_in_v) - 0x80;
212 int length = sqrt(inu*inu+inv*inv);
214 int diffu = refu * length - inu *reflength;
215 int diffv = refv * length - inv *reflength;
216 long long int difflen2=diffu*diffu;
217 difflen2 +=diffv*diffv;
218 long long int thres = length*reflength;
220 if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
223 // fprintf(stderr,"keeping color %d %d\n", length, difflen2);
231 p_outpic->date = p_pic->date;
232 p_outpic->b_force = p_pic->b_force;
233 p_outpic->i_nb_fields = p_pic->i_nb_fields;
234 p_outpic->b_progressive = p_pic->b_progressive;
235 p_outpic->b_top_field_first = p_pic->b_top_field_first;
237 if( p_pic->pf_release )
238 p_pic->pf_release( p_pic );