]> git.sesse.net Git - vlc/blob - modules/video_filter/colorthres.c
m3u: use the album art provided by jamendo along with the m3u files.
[vlc] / modules / video_filter / colorthres.c
1 /*****************************************************************************
2  * colorthres.c: Threshold color based on similarity to reference color
3  *****************************************************************************
4  * Copyright (C) 2000-2009 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Sigmund Augdal <dnumgis@videolan.org>
8  *          Antoine Cellerier <dionoea at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <math.h>
34
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_sout.h>
38
39 #include <vlc_filter.h>
40 #include "filter_picture.h"
41
42 /*****************************************************************************
43  * Local prototypes
44  *****************************************************************************/
45 static int  Create    ( vlc_object_t * );
46 static void Destroy   ( vlc_object_t * );
47
48 static picture_t *Filter( filter_t *, picture_t * );
49 static picture_t *FilterPacked( 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 #define COLOR_HELP N_("Select one color in the video")
60 static const int pi_color_values[] = {
61   0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x0000FF00, 0x000000FF, 0x0000FFFF };
62
63 static const char *const ppsz_color_descriptions[] = {
64   N_("Red"), N_("Fuchsia"), N_("Yellow"), N_("Lime"), N_("Blue"), N_("Aqua") };
65
66 #define CFG_PREFIX "colorthres-"
67
68 vlc_module_begin ()
69     set_description( N_("Color threshold filter") )
70     set_shortname( N_("Color threshold" ))
71     set_help(COLOR_HELP)
72     set_category( CAT_VIDEO )
73     set_subcategory( SUBCAT_VIDEO_VFILTER )
74     set_capability( "video filter2", 0 )
75     add_integer( CFG_PREFIX "color", 0x00FF0000, NULL, COLOR_TEXT,
76                  COLOR_LONGTEXT, false )
77         change_integer_list( pi_color_values, ppsz_color_descriptions, NULL )
78     add_integer( CFG_PREFIX "saturationthres", 20, NULL,
79                  N_("Saturaton threshold"), "", false )
80     add_integer( CFG_PREFIX "similaritythres", 15, NULL,
81                  N_("Similarity threshold"), "", false )
82     set_callbacks( Create, Destroy )
83 vlc_module_end ()
84
85 static const char *const ppsz_filter_options[] = {
86     "color", "saturationthres", "similaritythres", NULL
87 };
88
89 /*****************************************************************************
90  * callback prototypes
91  *****************************************************************************/
92 static int FilterCallback( vlc_object_t *, char const *,
93                            vlc_value_t, vlc_value_t, void * );
94
95
96 /*****************************************************************************
97  * filter_sys_t: adjust filter method descriptor
98  *****************************************************************************/
99 struct filter_sys_t
100 {
101     int i_simthres;
102     int i_satthres;
103     int i_color;
104     vlc_mutex_t lock;
105 };
106
107 /*****************************************************************************
108  * Create: allocates adjust video thread output method
109  *****************************************************************************
110  * This function allocates and initializes a adjust vout method.
111  *****************************************************************************/
112 static int Create( vlc_object_t *p_this )
113 {
114     filter_t *p_filter = (filter_t *)p_this;
115     filter_sys_t *p_sys;
116
117     switch( p_filter->fmt_in.video.i_chroma )
118     {
119         CASE_PLANAR_YUV
120             p_filter->pf_video_filter = Filter;
121             break;
122
123         CASE_PACKED_YUV_422
124             p_filter->pf_video_filter = FilterPacked;
125             break;
126
127         default:
128             msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
129                      (char*)&(p_filter->fmt_in.video.i_chroma) );
130             return VLC_EGENERIC;
131     }
132
133     if( p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
134     {
135         msg_Err( p_filter, "Input and output chromas don't match" );
136         return VLC_EGENERIC;
137     }
138
139     /* Allocate structure */
140     p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
141     if( p_filter->p_sys == NULL )
142         return VLC_ENOMEM;
143
144     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
145                        p_filter->p_cfg );
146     p_sys->i_color = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "color" );
147     p_sys->i_simthres = var_CreateGetIntegerCommand( p_filter,
148                                                      CFG_PREFIX "similaritythres" );
149     p_sys->i_satthres = var_CreateGetIntegerCommand( p_filter,
150                                                      CFG_PREFIX "saturationthres" );
151
152     vlc_mutex_init( &p_sys->lock );
153
154     var_AddCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
155     var_AddCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
156     var_AddCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
157
158     return VLC_SUCCESS;
159 }
160
161 /*****************************************************************************
162  * Destroy: destroy adjust video thread output method
163  *****************************************************************************
164  * Terminate an output method created by adjustCreateOutputMethod
165  *****************************************************************************/
166 static void Destroy( vlc_object_t *p_this )
167 {
168     filter_t *p_filter = (filter_t *)p_this;
169
170     var_DelCallback( p_filter, CFG_PREFIX "color", FilterCallback, NULL );
171     var_DelCallback( p_filter, CFG_PREFIX "similaritythres", FilterCallback, NULL );
172     var_DelCallback( p_filter, CFG_PREFIX "saturationthres", FilterCallback, NULL );
173
174     vlc_mutex_destroy( &p_filter->p_sys->lock );
175     free( p_filter->p_sys );
176 }
177
178 /*****************************************************************************
179  * Render: displays previously rendered output
180  *****************************************************************************
181  * This function send the currently rendered image to adjust modified image,
182  * waits until it is displayed and switch the two rendering buffers, preparing
183  * next frame.
184  *****************************************************************************/
185 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
186 {
187     picture_t *p_outpic;
188     filter_sys_t *p_sys = p_filter->p_sys;
189     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
190     uint8_t *p_out_y, *p_out_u, *p_out_v;
191
192     vlc_mutex_lock( &p_sys->lock );
193     int i_simthres = p_sys->i_simthres;
194     int i_satthres = p_sys->i_satthres;
195     int i_color = p_sys->i_color;
196     vlc_mutex_unlock( &p_sys->lock );
197
198     if( !p_pic ) return NULL;
199
200     p_outpic = filter_NewPicture( p_filter );
201     if( !p_outpic )
202     {
203         picture_Release( p_pic );
204         return NULL;
205     }
206
207     p_in_u = p_pic->p[U_PLANE].p_pixels;
208     p_in_v = p_pic->p[V_PLANE].p_pixels;
209     p_in_y = p_pic->p[Y_PLANE].p_pixels;
210     p_in_end_u = p_in_u + p_pic->p[U_PLANE].i_visible_lines
211                         * p_pic->p[U_PLANE].i_pitch - 8;
212
213     p_out_y = p_outpic->p[Y_PLANE].p_pixels;
214     p_out_u = p_outpic->p[U_PLANE].p_pixels;
215     p_out_v = p_outpic->p[V_PLANE].p_pixels;
216
217     /* Create grayscale version of input */
218     vlc_memcpy( p_out_y, p_in_y, p_pic->p[Y_PLANE].i_visible_lines
219                * p_pic->p[Y_PLANE].i_pitch - 8 );
220     vlc_memset( p_out_u, 0x80, p_pic->p[U_PLANE].i_visible_lines
221                * p_pic->p[U_PLANE].i_pitch - 8 );
222     vlc_memset( p_out_v, 0x80, p_pic->p[U_PLANE].i_visible_lines
223                * p_pic->p[U_PLANE].i_pitch - 8 );
224
225     /*
226      * Do the U and V planes
227      */
228     int i_red = ( i_color & 0xFF0000 ) >> 16;
229     int i_green = ( i_color & 0xFF00 ) >> 8;
230     int i_blue = i_color & 0xFF;
231     int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
232                      112 * i_blue + 128) >> 8) + 128;
233     int i_v = (int8_t)(( 112 * i_red  -  94 * i_green -
234                       18 * i_blue + 128) >> 8) + 128;
235     int refu = i_u - 0x80;         /*bright red*/
236     int refv = i_v - 0x80;
237     int reflength = sqrt(refu*refu+refv*refv);
238
239     while( p_in_u < p_in_end_u ) {
240         /* Length of color vector */
241         int inu = (*p_in_u) - 0x80;
242         int inv = (*p_in_v) - 0x80;
243         int length = sqrt(inu*inu+inv*inv);
244
245         int diffu = refu * length - inu *reflength;
246         int diffv = refv * length - inv *reflength;
247         long long int difflen2=diffu*diffu;
248         difflen2 +=diffv*diffv;
249         long long int thres = length*reflength;
250         thres *= thres;
251         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
252             *p_out_u = *p_in_u;
253             *p_out_v = *p_in_v;
254 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
255         }
256         p_in_u++;
257         p_in_v++;
258         p_out_u++;
259         p_out_v++;
260     }
261
262     return CopyInfoAndRelease( p_outpic, p_pic );
263 }
264
265 static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic )
266 {
267     picture_t *p_outpic;
268     filter_sys_t *p_sys = p_filter->p_sys;
269     uint8_t *p_in_y, *p_in_u, *p_in_v, *p_in_end_u;
270     uint8_t *p_out_y, *p_out_u, *p_out_v;
271
272     vlc_mutex_lock( &p_sys->lock );
273     int i_simthres = p_sys->i_simthres;
274     int i_satthres = p_sys->i_satthres;
275     int i_color = p_sys->i_color;
276     vlc_mutex_unlock( &p_sys->lock );
277
278     if( !p_pic ) return NULL;
279
280     p_outpic = filter_NewPicture( p_filter );
281     if( !p_outpic )
282     {
283         picture_Release( p_pic );
284         return NULL;
285     }
286
287     int i_y_offset, i_u_offset, i_v_offset;
288     GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
289                          &i_y_offset, &i_u_offset, &i_v_offset );
290     p_in_y = p_pic->p->p_pixels+i_y_offset;
291     p_in_u = p_pic->p->p_pixels+i_u_offset;
292     p_in_v = p_pic->p->p_pixels+i_v_offset;
293     p_in_end_u = p_in_u + p_pic->p->i_visible_lines
294                         * p_pic->p->i_pitch - 8;
295
296     p_out_y = p_outpic->p->p_pixels+i_y_offset;
297     p_out_u = p_outpic->p->p_pixels+i_u_offset;
298     p_out_v = p_outpic->p->p_pixels+i_v_offset;
299
300     /* Create grayscale version of input */
301     vlc_memcpy( p_outpic->p->p_pixels, p_pic->p->p_pixels,
302                 p_pic->p->i_visible_lines * p_pic->p->i_pitch - 8 );
303
304     /*
305      * Do the U and V planes
306      */
307     int i_red = ( i_color & 0xFF0000 ) >> 16;
308     int i_green = ( i_color & 0xFF00 ) >> 8;
309     int i_blue = i_color & 0xFF;
310     int i_u = (int8_t)(( -38 * i_red - 74 * i_green +
311                      112 * i_blue + 128) >> 8) + 128;
312     int i_v = (int8_t)(( 112 * i_red  -  94 * i_green -
313                       18 * i_blue + 128) >> 8) + 128;
314     int refu = i_u - 0x80;         /*bright red*/
315     int refv = i_v - 0x80;
316     int reflength = sqrt(refu*refu+refv*refv);
317
318     while( p_in_u < p_in_end_u ) {
319         /* Length of color vector */
320         int inu = (*p_in_u) - 0x80;
321         int inv = (*p_in_v) - 0x80;
322         int length = sqrt(inu*inu+inv*inv);
323
324         int diffu = refu * length - inu *reflength;
325         int diffv = refv * length - inv *reflength;
326         long long int difflen2=diffu*diffu;
327         difflen2 +=diffv*diffv;
328         long long int thres = length*reflength;
329         thres *= thres;
330         if( length > i_satthres && (difflen2*i_simthres< thres ) ) {
331             *p_out_u = *p_in_u;
332             *p_out_v = *p_in_v;
333 //        fprintf(stderr,"keeping color %d %d\n", length, difflen2);
334         }
335         else
336         {
337             *p_out_u = 0x80;
338             *p_out_v = 0x80;
339         }
340         p_in_u+=4;
341         p_in_v+=4;
342         p_out_u+=4;
343         p_out_v+=4;
344     }
345
346     return CopyInfoAndRelease( p_outpic, p_pic );
347 }
348
349 static int FilterCallback ( vlc_object_t *p_this, char const *psz_var,
350                             vlc_value_t oldval, vlc_value_t newval, void *p_data )
351 {
352     (void)oldval;    (void)p_data;
353     filter_t *p_filter = (filter_t*)p_this;
354     filter_sys_t *p_sys = p_filter->p_sys;
355
356     if( !strcmp( psz_var, CFG_PREFIX "color" ) )
357     {
358         vlc_mutex_lock( &p_sys->lock );
359         p_sys->i_color = newval.i_int;
360         vlc_mutex_unlock( &p_sys->lock );
361     }
362     else if( !strcmp( psz_var, CFG_PREFIX "similaritythres" ) )
363     {
364         vlc_mutex_lock( &p_sys->lock );
365         p_sys->i_simthres = newval.i_int;
366         vlc_mutex_unlock( &p_sys->lock );
367     }
368     else /* CFG_PREFIX "saturationthres" */
369     {
370         vlc_mutex_lock( &p_sys->lock );
371         p_sys->i_satthres = newval.i_int;
372         vlc_mutex_unlock( &p_sys->lock );
373     }
374
375     return VLC_SUCCESS;
376 }