]> git.sesse.net Git - vlc/blob - modules/video_filter/colorthres.c
Include vlc_plugin.h as needed
[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 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc/vlc.h>
35 #include <vlc_plugin.h>
36 #include <vlc_sout.h>
37 #include <vlc_vout.h>
38
39 #include "vlc_filter.h"
40
41 /*****************************************************************************
42  * Local prototypes
43  *****************************************************************************/
44 static int  Create    ( vlc_object_t * );
45 static void Destroy   ( vlc_object_t * );
46
47 static picture_t *Filter( filter_t *, picture_t * );
48
49 /*****************************************************************************
50  * Module descriptor
51  *****************************************************************************/
52 #define COLOR_TEXT N_("Color")
53 #define COLOR_LONGTEXT N_("Colors similar to this will be kept, others will be "\
54     "grayscaled. This must be an hexadecimal (like HTML colors). The first two "\
55     "chars are for red, then green, then blue. #000000 = black, #FF0000 = red,"\
56     " #00FF00 = green, #FFFF00 = yellow (red + green), #FFFFFF = white" )
57 static int pi_color_values[] = {
58   0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
59
60 static const char *ppsz_color_descriptions[] = {
61   N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
62
63 #define CFG_PREFIX "colorthres-"
64
65 vlc_module_begin();
66     set_description( _("Color threshold filter") );
67     set_shortname( _("Color threshold" ));
68     set_category( CAT_VIDEO );
69     set_subcategory( SUBCAT_VIDEO_VFILTER );
70     set_capability( "video filter2", 0 );
71     add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
72                  COLOR_LONGTEXT, false );
73         change_integer_list( pi_color_values, ppsz_color_descriptions, 0 );
74     add_integer( CFG_PREFIX "saturationthres", 20, NULL,
75                  _("Saturaton threshold"), "", false );
76     add_integer( CFG_PREFIX "similaritythres", 15, NULL,
77                  _("Similarity threshold"), "", false );
78     set_callbacks( Create, Destroy );
79 vlc_module_end();
80
81 static const char *ppsz_filter_options[] = {
82     "color", "saturationthes", "similaritythres", NULL
83 };
84
85 /*****************************************************************************
86  * filter_sys_t: adjust filter method descriptor
87  *****************************************************************************/
88 struct filter_sys_t
89 {
90 };
91
92 /*****************************************************************************
93  * Create: allocates adjust video thread output method
94  *****************************************************************************
95  * This function allocates and initializes a adjust vout method.
96  *****************************************************************************/
97 static int Create( vlc_object_t *p_this )
98 {
99     filter_t *p_filter = (filter_t *)p_this;
100
101     /* XXX: we might need to add/remove some FOURCCs ... */
102     if(   p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','0')
103        && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','Y','U','V')
104        && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('J','4','2','0')
105        && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','V','1','2')
106
107        && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','2')
108        && p_filter->fmt_in.video.i_chroma != VLC_FOURCC('J','4','2','2') )
109     {
110         msg_Err( p_filter, "Unsupported input chroma (%4s)",
111                  (char*)&(p_filter->fmt_in.video.i_chroma) );
112         return VLC_EGENERIC;
113     }
114
115     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
116     {
117         msg_Err( p_filter, "Input and output chromas don't match" );
118         return VLC_EGENERIC;
119     }
120
121     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
122                        p_filter->p_cfg );
123     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
124     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "similaritythres" );
125     var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "saturationthres" );
126
127     /* Allocate structure */
128     p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
129     if( p_filter->p_sys == NULL )
130     {
131         msg_Err( p_filter, "out of memory" );
132         return VLC_ENOMEM;
133     }
134
135     p_filter->pf_video_filter = Filter;
136
137     return VLC_SUCCESS;
138 }
139
140 /*****************************************************************************
141  * Destroy: destroy adjust video thread output method
142  *****************************************************************************
143  * Terminate an output method created by adjustCreateOutputMethod
144  *****************************************************************************/
145 static void Destroy( vlc_object_t *p_this )
146 {
147     filter_t *p_filter = (filter_t *)p_this;
148     free( p_filter->p_sys );
149 }
150
151 /*****************************************************************************
152  * Render: displays previously rendered output
153  *****************************************************************************
154  * This function send the currently rendered image to adjust modified image,
155  * waits until it is displayed and switch the two rendering buffers, preparing
156  * next frame.
157  *****************************************************************************/
158 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
159 {
160     picture_t *p_outpic;
161     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
162     uint8_t *p_out_y, *p_out_u, *p_out_v;
163     int i_simthres = var_GetInteger( p_filter, "colorthres-similaritythres" );
164     int i_satthres = var_GetInteger( p_filter, "colorthres-saturationthres" );
165     int i_color = var_GetInteger( p_filter, "colorthres-color" );
166
167     if( !p_pic ) return NULL;
168
169     p_outpic = p_filter->pf_vout_buffer_new( p_filter );
170     if( !p_outpic )
171     {
172         msg_Warn( p_filter, "can't get output picture" );
173         if( p_pic->pf_release )
174             p_pic->pf_release( p_pic );
175         return NULL;
176     }
177
178     p_in_u = p_pic->p[U_PLANE].p_pixels;
179     p_in_v = p_pic->p[V_PLANE].p_pixels;
180     p_in_y = p_pic->p[Y_PLANE].p_pixels;
181     p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
182                         * p_pic->p[U_PLANE].i_pitch - 8;
183
184     p_out_y = p_outpic->p[Y_PLANE].p_pixels;
185     p_out_u = p_outpic->p[U_PLANE].p_pixels;
186     p_out_v = p_outpic->p[V_PLANE].p_pixels;
187
188     /* Create grayscale version of input */
189     vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
190                * p_pic->p[Y_PLANE].i_pitch - 8 );
191     vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
192                * p_pic->p[U_PLANE].i_pitch - 8 );
193     vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
194                * p_pic->p[U_PLANE].i_pitch - 8 );
195
196     /*
197      * Do the U and V planes
198      */
199     int i_red = ( i_color & 0xFF0000 ) >> 16;
200     int i_green = ( i_color & 0xFF00 ) >> 8;
201     int i_blue = i_color & 0xFF;
202     int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
203                      112 * i_blue + 128) >> 8) + 128;
204     int i_v = (int8_t)(( 112 * i_red  -  94 * i_green -
205                       18 * i_blue + 128) >> 8) + 128;
206     int refu = i_u - 0x80;         /*bright red*/
207     int refv = i_v - 0x80;
208     int reflength = sqrt(refu*refu+refv*refv);
209
210     while( p_in_u < p_in_end_u ) {
211         /* Length of color vector */
212         int inu = (*p_in_u) - 0x80;
213         int inv = (*p_in_v) - 0x80;
214         int length = sqrt(inu*inu+inv*inv);
215
216         int diffu = refu * length - inu *reflength;
217         int diffv = refv * length - inv *reflength;
218         long long int difflen2=diffu*diffu;
219         difflen2 +=diffv*diffv;
220         long long int thres = length*reflength;
221         thres *= thres;
222         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
223             *p_out_u = *p_in_u;
224             *p_out_v = *p_in_v;
225 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
226         }
227         p_in_u++;
228         p_in_v++;
229         p_out_u++;
230         p_out_v++;
231     }
232
233     p_outpic->date = p_pic->date;
234     p_outpic->b_force = p_pic->b_force;
235     p_outpic->i_nb_fields = p_pic->i_nb_fields;
236     p_outpic->b_progressive = p_pic->b_progressive;
237     p_outpic->b_top_field_first = p_pic->b_top_field_first;
238
239     if( p_pic->pf_release )
240         p_pic->pf_release( p_pic );
241
242     return p_outpic;
243 }