]> git.sesse.net Git - vlc/blob - modules/video_filter/colorthres.c
Revert the so-called whitelisting commits that are actually blacklisting
[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        && 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')
101
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') )
104     {
105         msg_Err( p_filter, "Unsupported input chroma (%4s)",
106                  (char*)&(p_filter->fmt_in.video.i_chroma) );
107         return VLC_EGENERIC;
108     }
109
110     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
111     {
112         msg_Err( p_filter, "Input and output chromas don't match" );
113         return VLC_EGENERIC;
114     }
115
116     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
117                        p_filter->p_cfg );
118     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
119     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "similaritythres" );
120     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "saturationthres" );
121
122     /* Allocate structure */
123     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
124     if( p_filter->p_sys == NULL )
125     {
126         msg_Err( p_filter, "out of memory" );
127         return VLC_ENOMEM;
128     }
129
130     p_filter->pf_video_filter = Filter;
131
132     return VLC_SUCCESS;
133 }
134
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 )
141 {
142     filter_t *p_filter = (filter_t *)p_this;
143     free( p_filter->p_sys );
144 }
145
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
151  * next frame.
152  *****************************************************************************/
153 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
154 {
155     picture_t *p_outpic;
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" );
161
162     if( !p_pic ) return NULL;
163
164     p_outpic = p_filter->pf_vout_buffer_new( p_filter );
165     if( !p_outpic )
166     {
167         msg_Warn( p_filter, "can't get output picture" );
168         if( p_pic->pf_release )
169             p_pic->pf_release( p_pic );
170         return NULL;
171     }
172
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;
178
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;
182
183     /* Create grayscale version of input */
184     p_filter->p_libvlc->
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 );
187     p_filter->p_libvlc->
188     pf_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
189                * p_pic->p[U_PLANE].i_pitch - 8 );
190     p_filter->p_libvlc->
191     pf_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
192                * p_pic->p[U_PLANE].i_pitch - 8 );
193
194     /*
195      * Do the U and V planes
196      */
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);
207
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);
213
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;
219         thres *= thres;
220         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
221             *p_out_u = *p_in_u;
222             *p_out_v = *p_in_v;
223 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
224         }
225         p_in_u++;
226         p_in_v++;
227         p_out_u++;
228         p_out_v++;
229     }
230
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;
236
237     if( p_pic->pf_release )
238         p_pic->pf_release( p_pic );
239
240     return p_outpic;
241 }