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