* ./src/video_output/video_output.c, modules/*: factorized video output
[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.2 2002/11/28 17:35:00 sam 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 = vout_Create( p_vout,
141                      p_vout->render.i_width, p_vout->render.i_height,
142                      p_vout->render.i_chroma, p_vout->render.i_aspect );
143
144     /* Everything failed */
145     if( p_vout->p_sys->p_vout == NULL )
146     {
147         msg_Err( p_vout, "can't open vout, aborting" );
148
149         return( 0 );
150     }
151  
152     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
153
154     return( 0 );
155 }
156
157 /*****************************************************************************
158  * End: terminate adjust video thread output method
159  *****************************************************************************/
160 static void End( vout_thread_t *p_vout )
161 {
162     int i_index;
163
164     /* Free the fake output buffers we allocated */
165     for( i_index = I_OUTPUTPICTURES ; i_index ; )
166     {
167         i_index--;
168         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
169     }
170 }
171
172 /*****************************************************************************
173  * Destroy: destroy adjust video thread output method
174  *****************************************************************************
175  * Terminate an output method created by adjustCreateOutputMethod
176  *****************************************************************************/
177 static void Destroy( vlc_object_t *p_this )
178 {   
179     vout_thread_t *p_vout = (vout_thread_t *)p_this;
180
181     vout_Destroy( p_vout->p_sys->p_vout );
182
183     free( p_vout->p_sys );
184 }
185
186 /*****************************************************************************
187  * Render: displays previously rendered output
188  *****************************************************************************
189  * This function send the currently rendered image to adjust modified image, 
190  * waits until it is displayed and switch the two rendering buffers, preparing
191  * next frame.
192  *****************************************************************************/
193 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
194 {
195     picture_t *p_outpic;
196     int i_index;
197     s32 cont;
198     s32 lum;
199
200     /* Contrast is a fast but cludged function, so I put this gap to be
201 cleaner :) */    
202     s32 dec;
203
204     double hue;
205     int i_sat;
206     int i_Sin;
207     int i_Cos;
208     
209     /* This is a new frame. Get a structure from the video_output. */
210
211     cont = (s32) ( config_GetFloat( p_vout, "Contrast" ) * 255 );
212     lum = (s32) ( ( config_GetFloat( p_vout, "Brightness" ) * 255 ) - 255 );
213     hue =  config_GetInt( p_vout, "Hue" ) * 3.14159 / 180 ; /* convert in radian */
214     i_sat = (int) (  config_GetFloat( p_vout, "Saturation" ) * 256 );
215     
216     dec = 128 - ( cont / 2 );
217     i_Sin = (int) ( sin(hue) * 256);
218     i_Cos = (int) ( cos(hue) * 256);
219
220     
221     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
222               == NULL )
223     {
224         if( p_vout->b_die || p_vout->b_error )
225         {
226             return;
227         }
228         msleep( VOUT_OUTMEM_SLEEP );
229     }   
230
231     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
232     vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
233
234     for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
235     {
236
237      if ( i_index==0 )
238     {
239
240         u8 *p_in, *p_in_end, *p_out;
241
242         p_in = p_pic->p[i_index].p_pixels;
243         p_in_end = p_in + p_pic->p[i_index].i_lines
244                                 * p_pic->p[i_index].i_pitch -8;
245         
246         p_out = p_outpic->p[i_index].p_pixels;
247
248
249         for( ; p_in < p_in_end ; )
250         {
251             /* Do 8 pixels at a time */
252                 *p_out = maxmin( (( *p_in * cont ) >> 8 ) + lum + dec ); p_out++; p_in++;
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         }
261
262         p_in_end += 8;
263
264         for( ; p_in < p_in_end ; )
265         {
266             /* Do 1 pixel at a time */
267                 *p_out = maxmin( (( *p_in * cont ) >> 8 ) + lum + dec ); p_out++; p_in++;
268         }
269     }
270     else
271     {    
272      if ( i_index==1 )
273     {
274
275         u8 *p_in_u, *p_in_v, *p_in_end, *p_out_u, *p_out_v, i_u, i_v;
276
277         p_in_u = p_pic->p[i_index].p_pixels;
278         p_in_v = p_pic->p[i_index + 1].p_pixels;
279         p_in_end = p_in_u + p_pic->p[i_index].i_lines
280                                 * p_pic->p[i_index].i_pitch -8;
281         
282         p_out_u = p_outpic->p[i_index].p_pixels;
283         p_out_v = p_outpic->p[i_index + 1].p_pixels;
284
285
286         for( ; p_in_u < p_in_end ; )
287         {
288             /* Do 8 pixels at a time */
289
290                 i_u = *p_in_u ;
291                 i_v = *p_in_v ;
292                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
293                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
294                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
295
296                 i_u = *p_in_u ;
297                 i_v = *p_in_v ;
298                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
299                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
300                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
301
302                 i_u = *p_in_u ;
303                 i_v = *p_in_v ;
304                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
305                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
306                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
307
308                 i_u = *p_in_u ;
309                 i_v = *p_in_v ;
310                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
311                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
312                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
313
314                 i_u = *p_in_u ;
315                 i_v = *p_in_v ;
316                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
317                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
318                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
319
320                 i_u = *p_in_u ;
321                 i_v = *p_in_v ;
322                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
323                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
324                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
325
326                 i_u = *p_in_u ;
327                 i_v = *p_in_v ;
328                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
329                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
330                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
331
332                 i_u = *p_in_u ;
333                 i_v = *p_in_v ;
334                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
335                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
336                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
337
338
339
340
341         }
342
343         p_in_end += 8;
344
345         for( ; p_in_u < p_in_end ; )
346         {
347             /* Do 1 pixel at a time */
348                 i_u = *p_in_u ;
349                 i_v = *p_in_v ;
350                 *p_out_u = maxmin( (((((i_u * i_Cos + i_v * i_Sin) >> 8) - 128) * i_sat) >> 8) + 128);
351                 *p_out_v = maxmin( (((((i_v * i_Cos - i_u * i_Sin) >> 8 ) - 128) * i_sat) >> 8) + 128);
352                 p_out_u++; p_in_u++; p_out_v++; p_in_v++;
353
354
355         }
356     }
357
358     }
359     
360     
361     }
362
363     vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
364
365     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
366 }