]> git.sesse.net Git - vlc/blob - modules/video_filter/colorthres.c
62225a9b7839d78bfe50bfcc1dba47bacf0f8921
[vlc] / modules / video_filter / colorthres.c
1 /*****************************************************************************
2  * colorthres.c: Theshold color based on similarity to reference color
3  *****************************************************************************
4  * Copyright (C) 2000-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sigmund Augdal <dnumgis@videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <errno.h>
28 #include <math.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc_sout.h>
32 #include <vlc_vout.h>
33
34 #include "vlc_filter.h"
35
36 /*****************************************************************************
37  * Local prototypes
38  *****************************************************************************/
39 static int  Create    ( vlc_object_t * );
40 static void Destroy   ( vlc_object_t * );
41
42 static picture_t *Filter( filter_t *, picture_t * );
43
44 /*****************************************************************************
45  * Module descriptor
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 };
54
55 static const char *ppsz_color_descriptions[] = {
56   N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
57
58 #define CFG_PREFIX "colorthres-"
59
60 vlc_module_begin();
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 );
74 vlc_module_end();
75
76 static const char *ppsz_filter_options[] = {
77     "color", "saturationthes", "similaritythres", NULL
78 };
79
80 /*****************************************************************************
81  * filter_sys_t: adjust filter method descriptor
82  *****************************************************************************/
83 struct filter_sys_t
84 {
85 };
86
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 )
93 {
94     filter_t *p_filter = (filter_t *)p_this;
95
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     {
99         msg_Err( p_filter, "Unsupported input chroma (%4s)",
100                  (char*)&(p_filter->fmt_in.video.i_chroma) );
101         return VLC_EGENERIC;
102     }
103
104     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
105     {
106         msg_Err( p_filter, "Input and output chromas don't match" );
107         return VLC_EGENERIC;
108     }
109
110     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
111                        p_filter->p_cfg );
112     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
113     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "similaritythres" );
114     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "saturationthres" );
115
116     /* Allocate structure */
117     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
118     if( p_filter->p_sys == NULL )
119     {
120         msg_Err( p_filter, "out of memory" );
121         return VLC_ENOMEM;
122     }
123
124     p_filter->pf_video_filter = Filter;
125
126     return VLC_SUCCESS;
127 }
128
129 /*****************************************************************************
130  * Destroy: destroy adjust video thread output method
131  *****************************************************************************
132  * Terminate an output method created by adjustCreateOutputMethod
133  *****************************************************************************/
134 static void Destroy( vlc_object_t *p_this )
135 {
136     filter_t *p_filter = (filter_t *)p_this;
137     free( p_filter->p_sys );
138 }
139
140 /*****************************************************************************
141  * Render: displays previously rendered output
142  *****************************************************************************
143  * This function send the currently rendered image to adjust modified image,
144  * waits until it is displayed and switch the two rendering buffers, preparing
145  * next frame.
146  *****************************************************************************/
147 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
148 {
149     picture_t *p_outpic;
150     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
151     uint8_t *p_out_y, *p_out_u, *p_out_v;
152     int i_simthres = var_GetInteger( p_filter, "colorthres-similaritythres" );
153     int i_satthres = var_GetInteger( p_filter, "colorthres-saturationthres" );
154     int i_color = var_GetInteger( p_filter, "colorthres-color" );
155
156     if( !p_pic ) return NULL;
157
158     p_outpic = p_filter->pf_vout_buffer_new( p_filter );
159     if( !p_outpic )
160     {
161         msg_Warn( p_filter, "can't get output picture" );
162         if( p_pic->pf_release )
163             p_pic->pf_release( p_pic );
164         return NULL;
165     }
166
167     p_in_u = p_pic->p[U_PLANE].p_pixels;
168     p_in_v = p_pic->p[V_PLANE].p_pixels;
169     p_in_y = p_pic->p[Y_PLANE].p_pixels;
170     p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
171                         * p_pic->p[U_PLANE].i_pitch - 8;
172
173     p_out_y = p_outpic->p[Y_PLANE].p_pixels;
174     p_out_u = p_outpic->p[U_PLANE].p_pixels;
175     p_out_v = p_outpic->p[V_PLANE].p_pixels;
176
177     /* Create grayscale version of input */
178     p_filter->p_libvlc->
179     pf_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
180                * p_pic->p[Y_PLANE].i_pitch - 8 );
181     p_filter->p_libvlc->
182     pf_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
183                * p_pic->p[U_PLANE].i_pitch - 8 );
184     p_filter->p_libvlc->
185     pf_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
186                * p_pic->p[U_PLANE].i_pitch - 8 );
187
188     /*
189      * Do the U and V planes
190      */
191     int i_red = ( i_color & 0xFF0000 ) >> 16;
192     int i_green = ( i_color & 0xFF00 ) >> 8;
193     int i_blue = i_color & 0xFF;
194     int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
195                      112 * i_blue + 128) >> 8) + 128;
196     int i_v = (int8_t)(( 112 * i_red  -  94 * i_green -
197                       18 * i_blue + 128) >> 8) + 128;
198     int refu = i_u - 0x80;         /*bright red*/
199     int refv = i_v - 0x80;
200     int reflength = sqrt(refu*refu+refv*refv);
201
202     while( p_in_u < p_in_end_u ) {
203         /* Length of color vector */
204         int inu = (*p_in_u) - 0x80;
205         int inv = (*p_in_v) - 0x80;
206         int length = sqrt(inu*inu+inv*inv);
207
208         int diffu = refu * length - inu *reflength;
209         int diffv = refv * length - inv *reflength;
210         long long int difflen2=diffu*diffu;
211         difflen2 +=diffv*diffv;
212         long long int thres = length*reflength;
213         thres *= thres;
214         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
215             *p_out_u = *p_in_u;
216             *p_out_v = *p_in_v;
217 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
218         }
219         p_in_u++;
220         p_in_v++;
221         p_out_u++;
222         p_out_v++;
223     }
224
225     p_outpic->date = p_pic->date;
226     p_outpic->b_force = p_pic->b_force;
227     p_outpic->i_nb_fields = p_pic->i_nb_fields;
228     p_outpic->b_progressive = p_pic->b_progressive;
229     p_outpic->b_top_field_first = p_pic->b_top_field_first;
230
231     if( p_pic->pf_release )
232         p_pic->pf_release( p_pic );
233
234     return p_outpic;
235 }