* added a i_min, i_max, f_min and f_max in module_config_t structure
[vlc.git] / modules / video_filter / adjust.c
1 /*****************************************************************************
2  * adjust.c : Contrast/Hue/Saturation/Brightness video plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000, 2001 VideoLAN
5  * $Id: adjust.c,v 1.5 2003/01/06 00:37:30 garf Exp $
6  *
7  * Authors: Simon Latapie <garf@via.ecp.fr>, Samuel Hocevar <sam@zoy.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., 59 Temple Place - Suite 330, Boston, MA  02111, 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/vout.h>
34
35 #include "filter_common.h"
36
37
38 #define eight_times( x )    x x x x x x x x
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 static int  Create    ( vlc_object_t * );
44 static void Destroy   ( vlc_object_t * );
45
46 static int  Init      ( vout_thread_t * );
47 static void End       ( vout_thread_t * );
48 static void Render    ( vout_thread_t *, picture_t * );
49
50 /*****************************************************************************
51  * Module descriptor
52  *****************************************************************************/
53
54 #define CONT_TEXT N_("Contrast")
55 #define CONT_LONGTEXT N_("Default to 1")
56 #define HUE_TEXT N_("Hue")
57 #define HUE_LONGTEXT N_("Between 0 and 360. Default to 0")
58 #define SAT_TEXT N_("Saturation")
59 #define SAT_LONGTEXT N_("Default to 1")
60 #define LUM_TEXT N_("Brightness")
61 #define LUM_LONGTEXT N_("Default to 1")
62
63
64 vlc_module_begin();
65     add_category_hint( N_("Miscellaneous"), NULL );
66     add_float_with_range( "Contrast", 1.0, 0.0, 2.0, NULL, CONT_TEXT, CONT_LONGTEXT );
67     add_float_with_range( "Brightness", 1.0, 0.0, 2.0, NULL, LUM_TEXT, LUM_LONGTEXT );
68     add_integer_with_range( "Hue", 0, 0, 360, NULL, HUE_TEXT, HUE_LONGTEXT );
69     add_float_with_range( "Saturation", 1.0, 0.0, 3.0, NULL, SAT_TEXT, SAT_LONGTEXT );
70     set_description( _("Contrast/Hue/Saturation/Brightness filter") );
71     set_capability( "video filter", 0 );
72     add_shortcut( "adjust" );
73     set_callbacks( Create, Destroy );
74 vlc_module_end();
75
76 /*****************************************************************************
77  * vout_sys_t: adjust video output method descriptor
78  *****************************************************************************
79  * This structure is part of the video output thread descriptor.
80  * It describes the adjust specific properties of an output thread.
81  *****************************************************************************/
82 struct vout_sys_t
83 {
84         vout_thread_t *p_vout;
85 };
86
87 inline static int32_t maxmin( int32_t a )
88 {
89     if ( a > 255 )
90         return 255;
91     else if ( a < 0 )
92         return 0;
93     else
94         return a;
95 }
96
97
98 /*****************************************************************************
99  * Create: allocates adjust video thread output method
100  *****************************************************************************
101  * This function allocates and initializes a adjust vout method.
102  *****************************************************************************/
103 static int Create( vlc_object_t *p_this )
104 {
105     vout_thread_t *p_vout = (vout_thread_t *)p_this;
106
107     /* Allocate structure */
108     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
109     if( p_vout->p_sys == NULL )
110     {
111         msg_Err( p_vout, "out of memory" );
112         return( 1 );
113     }
114
115     p_vout->pf_init = Init;
116     p_vout->pf_end = End;
117     p_vout->pf_manage = NULL;
118     p_vout->pf_render = Render;
119     p_vout->pf_display = NULL;
120
121     return( 0 );
122 }
123
124 /*****************************************************************************
125  * Init: initialize adjust video thread output method
126  *****************************************************************************/
127 static int Init( vout_thread_t *p_vout )
128 {
129     int i_index;
130     picture_t *p_pic;
131
132     I_OUTPUTPICTURES = 0;
133
134     /* Initialize the output structure */
135     p_vout->output.i_chroma = p_vout->render.i_chroma;
136     p_vout->output.i_width  = p_vout->render.i_width;
137     p_vout->output.i_height = p_vout->render.i_height;
138     p_vout->output.i_aspect = p_vout->render.i_aspect;
139
140     /* Try to open the real video output */
141     msg_Dbg( p_vout, "spawning the real video output" );
142
143     p_vout->p_sys->p_vout = vout_Create( p_vout,
144                      p_vout->render.i_width, p_vout->render.i_height,
145                      p_vout->render.i_chroma, p_vout->render.i_aspect );
146
147     /* Everything failed */
148     if( p_vout->p_sys->p_vout == NULL )
149     {
150         msg_Err( p_vout, "can't open vout, aborting" );
151
152         return( 0 );
153     }
154  
155     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
156
157     return( 0 );
158 }
159
160 /*****************************************************************************
161  * End: terminate adjust video thread output method
162  *****************************************************************************/
163 static void End( vout_thread_t *p_vout )
164 {
165     int i_index;
166
167     /* Free the fake output buffers we allocated */
168     for( i_index = I_OUTPUTPICTURES ; i_index ; )
169     {
170         i_index--;
171         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
172     }
173 }
174
175 /*****************************************************************************
176  * Destroy: destroy adjust video thread output method
177  *****************************************************************************
178  * Terminate an output method created by adjustCreateOutputMethod
179  *****************************************************************************/
180 static void Destroy( vlc_object_t *p_this )
181 {   
182     vout_thread_t *p_vout = (vout_thread_t *)p_this;
183
184     vout_Destroy( p_vout->p_sys->p_vout );
185
186     free( p_vout->p_sys );
187 }
188
189 /*****************************************************************************
190  * Render: displays previously rendered output
191  *****************************************************************************
192  * This function send the currently rendered image to adjust modified image, 
193  * waits until it is displayed and switch the two rendering buffers, preparing
194  * next frame.
195  *****************************************************************************/
196 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
197 {
198     picture_t *p_outpic;
199     int i_index;
200     s32 cont;
201     s32 lum;
202
203     /* Contrast is a fast but cludged function, so I put this gap to be
204 cleaner :) */    
205     s32 dec;
206
207     double hue;
208     int i_sat;
209     int i_Sin;
210     int i_Cos;
211     int p_lum_func[256];
212     int i;
213     
214     /* This is a new frame. Get a structure from the video_output. */
215
216     cont = (s32) ( config_GetFloat( p_vout, "Contrast" ) * 255 );
217     lum = (s32) ( ( config_GetFloat( p_vout, "Brightness" ) * 255 ) - 255 );
218     hue =  config_GetInt( p_vout, "Hue" ) * 3.14159 / 180 ; /* convert in radian */
219     i_sat = (int) (  config_GetFloat( p_vout, "Saturation" ) * 256 );
220     
221     dec = 128 - ( cont / 2 );
222     i_Sin = (int) ( sin(hue) * 256);
223     i_Cos = (int) ( cos(hue) * 256);
224
225     
226     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
227               == NULL )
228     {
229         if( p_vout->b_die || p_vout->b_error )
230         {
231             return;
232         }
233         msleep( VOUT_OUTMEM_SLEEP );
234     }   
235
236     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
237     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
238
239     for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
240     {
241
242      if ( i_index==0 )
243     {
244
245         u8 *p_in, *p_in_end, *p_out;
246
247         p_in = p_pic->p[i_index].p_pixels;
248         p_in_end = p_in + p_pic->p[i_index].i_lines
249                                 * p_pic->p[i_index].i_pitch -8;
250         
251         p_out = p_outpic->p[i_index].p_pixels;
252
253         for( i = 0 ; i < 256 ; i++ )
254         {
255             p_lum_func[ i ] = maxmin( (( i * cont ) >> 8 ) + lum + dec );
256         }
257
258         
259         for( ; p_in < p_in_end ; )
260         {
261             /* Do 8 pixels at a time */
262
263             eight_times( *p_out = p_lum_func[ *p_in ]; p_out++; p_in++; )
264
265         }
266
267         p_in_end += 8;
268
269         for( ; p_in < p_in_end ; )
270         {
271             /* Do 1 pixel at a time */
272                 *p_out = p_lum_func[ *p_in ]; p_out++; p_in++;
273         }
274     }
275     else
276     {    
277      if ( i_index==1 )
278     {
279
280         u8 *p_in_u, *p_in_v, *p_in_end, *p_out_u, *p_out_v, i_u, i_v;
281         s32 cospsin, cosmsin;
282
283         p_in_u = p_pic->p[i_index].p_pixels;
284         p_in_v = p_pic->p[i_index + 1].p_pixels;
285         p_in_end = p_in_u + p_pic->p[i_index].i_lines
286                                 * p_pic->p[i_index].i_pitch -8;
287         
288         p_out_u = p_outpic->p[i_index].p_pixels;
289         p_out_v = p_outpic->p[i_index + 1].p_pixels;
290
291         cospsin = 32768 * ( cos(hue) + sin(hue) );
292         cosmsin = 32768 * ( cos(hue) - sin(hue) );
293
294         if ( i_sat > 256 )
295         {
296             for( ; p_in_u < p_in_end ; )
297             {
298                 /* Do 8 pixels at a time */
299
300        eight_times( i_u = *p_in_u ;
301                     i_v = *p_in_v ;
302                     *p_out_u = maxmin( (( ((i_u * i_Cos + i_v * i_Sin - cospsin) >> 8)  * i_sat) >> 8) + 128);
303                     *p_out_v = maxmin( (( ((i_v * i_Cos - i_u * i_Sin - cosmsin) >> 8)  * i_sat) >> 8) + 128);
304                     p_out_u++; p_in_u++; p_out_v++; p_in_v++; )
305
306             }
307
308             p_in_end += 8;
309
310             for( ; p_in_u < p_in_end ; )
311             {
312                 /* Do 1 pixel at a time */
313                     i_u = *p_in_u ;
314                     i_v = *p_in_v ;
315                     *p_out_u = maxmin( (( ((i_u * i_Cos + i_v * i_Sin - cospsin) >> 8)  * i_sat) >> 8) + 128);
316                     *p_out_v = maxmin( (( ((i_v * i_Cos - i_u * i_Sin - cosmsin) >> 8)  * i_sat) >> 8) + 128);
317                     p_out_u++; p_in_u++; p_out_v++; p_in_v++;
318
319
320             }
321         }
322         else
323         {
324             for( ; p_in_u < p_in_end ; )
325             {
326                 /* Do 8 pixels at a time */
327
328        eight_times( i_u = *p_in_u ;
329                     i_v = *p_in_v ;
330                     *p_out_u = (( ((i_u * i_Cos + i_v * i_Sin - cospsin) >> 8)  * i_sat) >> 8) + 128;
331                     *p_out_v = (( ((i_v * i_Cos - i_u * i_Sin - cosmsin) >> 8)  * i_sat) >> 8) + 128;
332                     p_out_u++; p_in_u++; p_out_v++; p_in_v++; )
333
334             }
335
336             p_in_end += 8;
337
338             for( ; p_in_u < p_in_end ; )
339             {
340                 /* Do 1 pixel at a time */
341                     i_u = *p_in_u ;
342                     i_v = *p_in_v ;
343                     *p_out_u = (( ((i_u * i_Cos + i_v * i_Sin - cospsin) >> 8)  * i_sat) >> 8) + 128;
344                     *p_out_v = (( ((i_v * i_Cos - i_u * i_Sin - cosmsin) >> 8)  * i_sat) >> 8) + 128;
345                     p_out_u++; p_in_u++; p_out_v++; p_in_v++;
346
347             }
348         }
349     }
350
351     }
352     
353     
354     }
355
356     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
357
358     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
359 }