9c3c2d242eba73fba8de84e1292fb4bc1da82721
[vlc.git] / 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
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <errno.h>
33 #include <math.h>
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_sout.h>
38 #include <vlc_vout.h>
39
40 #include "vlc_filter.h"
41 #include "filter_picture.h"
42
43 /*****************************************************************************
44  * Local prototypes
45  *****************************************************************************/
46 static int  Create    ( vlc_object_t * );
47 static void Destroy   ( vlc_object_t * );
48
49 static picture_t *Filter( filter_t *, picture_t * );
50
51 /*****************************************************************************
52  * Module descriptor
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 static const int pi_color_values[] = {
60   0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
61
62 static const char *const ppsz_color_descriptions[] = {
63   N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
64
65 #define CFG_PREFIX "colorthres-"
66
67 vlc_module_begin ()
68     set_description( N_("Color threshold filter") )
69     set_shortname( N_("Color threshold" ))
70     set_category( CAT_VIDEO )
71     set_subcategory( SUBCAT_VIDEO_VFILTER )
72     set_capability( "video filter2", 0 )
73     add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
74                  COLOR_LONGTEXT, false )
75         change_integer_list( pi_color_values, ppsz_color_descriptions, NULL )
76     add_integer( CFG_PREFIX "saturationthres", 20, NULL,
77                  _("Saturaton threshold"), "", false )
78     add_integer( CFG_PREFIX "similaritythres", 15, NULL,
79                  _("Similarity threshold"), "", false )
80     set_callbacks( Create, Destroy )
81 vlc_module_end ()
82
83 static const char *const ppsz_filter_options[] = {
84     "color", "saturationthes", "similaritythres", NULL
85 };
86
87 /*****************************************************************************
88  * filter_sys_t: adjust filter method descriptor
89  *****************************************************************************/
90 struct filter_sys_t
91 {
92 };
93
94 /*****************************************************************************
95  * Create: allocates adjust video thread output method
96  *****************************************************************************
97  * This function allocates and initializes a adjust vout method.
98  *****************************************************************************/
99 static int Create( vlc_object_t *p_this )
100 {
101     filter_t *p_filter = (filter_t *)p_this;
102
103     switch( p_filter->fmt_in.video.i_chroma )
104     {
105         CASE_PLANAR_YUV
106             break;
107
108         default:
109             msg_Err( p_filter, "Unsupported input chroma (%4s)",
110                      (char*)&(p_filter->fmt_in.video.i_chroma) );
111             return VLC_EGENERIC;
112     }
113
114     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
115     {
116         msg_Err( p_filter, "Input and output chromas don't match" );
117         return VLC_EGENERIC;
118     }
119
120     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
121                        p_filter->p_cfg );
122     var_Create( p_filter, CFG_PREFIX "color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
123     var_Create( p_filter, CFG_PREFIX "similaritythres", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
124     var_Create( p_filter, CFG_PREFIX "saturationthes", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT | VLC_VAR_ISCOMMAND );
125
126     /* Allocate structure */
127     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
128     if( p_filter->p_sys == NULL )
129         return VLC_ENOMEM;
130
131     p_filter->pf_video_filter = Filter;
132
133     return VLC_SUCCESS;
134 }
135
136 /*****************************************************************************
137  * Destroy: destroy adjust video thread output method
138  *****************************************************************************
139  * Terminate an output method created by adjustCreateOutputMethod
140  *****************************************************************************/
141 static void Destroy( vlc_object_t *p_this )
142 {
143     filter_t *p_filter = (filter_t *)p_this;
144     free( p_filter->p_sys );
145 }
146
147 /*****************************************************************************
148  * Render: displays previously rendered output
149  *****************************************************************************
150  * This function send the currently rendered image to adjust modified image,
151  * waits until it is displayed and switch the two rendering buffers, preparing
152  * next frame.
153  *****************************************************************************/
154 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
155 {
156     picture_t *p_outpic;
157     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
158     uint8_t *p_out_y, *p_out_u, *p_out_v;
159     int i_simthres = var_GetInteger( p_filter, "colorthres-similaritythres" );
160     int i_satthres = var_GetInteger( p_filter, "colorthres-saturationthres" );
161     int i_color = var_GetInteger( p_filter, "colorthres-color" );
162
163     if( !p_pic ) return NULL;
164
165     p_outpic = filter_NewPicture( p_filter );
166     if( !p_outpic )
167     {
168         picture_Release( p_pic );
169         return NULL;
170     }
171
172     p_in_u = p_pic->p[U_PLANE].p_pixels;
173     p_in_v = p_pic->p[V_PLANE].p_pixels;
174     p_in_y = p_pic->p[Y_PLANE].p_pixels;
175     p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
176                         * p_pic->p[U_PLANE].i_pitch - 8;
177
178     p_out_y = p_outpic->p[Y_PLANE].p_pixels;
179     p_out_u = p_outpic->p[U_PLANE].p_pixels;
180     p_out_v = p_outpic->p[V_PLANE].p_pixels;
181
182     /* Create grayscale version of input */
183     vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
184                * p_pic->p[Y_PLANE].i_pitch - 8 );
185     vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
186                * p_pic->p[U_PLANE].i_pitch - 8 );
187     vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
188                * p_pic->p[U_PLANE].i_pitch - 8 );
189
190     /*
191      * Do the U and V planes
192      */
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);
203
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);
209
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;
215         thres *= thres;
216         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
217             *p_out_u = *p_in_u;
218             *p_out_v = *p_in_v;
219 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
220         }
221         p_in_u++;
222         p_in_v++;
223         p_out_u++;
224         p_out_v++;
225     }
226
227     return CopyInfoAndRelease( p_outpic, p_pic );
228 }