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