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