00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <errno.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <math.h>
00031
00032 #include <vlc/vlc.h>
00033 #include <vlc/vout.h>
00034
00035 #include "filter_common.h"
00036
00037 #ifndef M_PI
00038 # define M_PI 3.14159265358979323846
00039 #endif
00040
00041 #define eight_times( x ) x x x x x x x x
00042
00043
00044
00045
00046 static int Create ( vlc_object_t * );
00047 static void Destroy ( vlc_object_t * );
00048
00049 static int Init ( vout_thread_t * );
00050 static void End ( vout_thread_t * );
00051 static void Render ( vout_thread_t *, picture_t * );
00052
00053 static int SendEvents( vlc_object_t *, char const *,
00054 vlc_value_t, vlc_value_t, void * );
00055
00056
00057
00058
00059
00060 #define CONT_TEXT N_("Image contrast (0-2)")
00061 #define CONT_LONGTEXT N_("Set the image contrast, between 0 and 2. Defaults to 1")
00062 #define HUE_TEXT N_("Image hue (0-360)")
00063 #define HUE_LONGTEXT N_("Set the image hue, between 0 and 360. Defaults to 0")
00064 #define SAT_TEXT N_("Image saturation (0-3)")
00065 #define SAT_LONGTEXT N_("Set the image saturation, between 0 and 3. Defaults to 1")
00066 #define LUM_TEXT N_("Image brightness (0-2)")
00067 #define LUM_LONGTEXT N_("Set the image brightness, between 0 and 2. Defaults to 1")
00068 #define GAMMA_TEXT N_("Image gamma (0-10)")
00069 #define GAMMA_LONGTEXT N_("Set the image gamma, between 0.01 and 10. Defaults to 1")
00070
00071
00072 vlc_module_begin();
00073 set_description( _("Image properties filter") );
00074 set_shortname( N_("Image adjust" ));
00075 set_category( CAT_VIDEO );
00076 set_subcategory( SUBCAT_VIDEO_VFILTER );
00077 set_capability( "video filter", 0 );
00078
00079 add_float_with_range( "contrast", 1.0, 0.0, 2.0, NULL, CONT_TEXT, CONT_LONGTEXT, VLC_FALSE );
00080 add_float_with_range( "brightness", 1.0, 0.0, 2.0, NULL, LUM_TEXT, LUM_LONGTEXT, VLC_FALSE );
00081 add_integer_with_range( "hue", 0, 0, 360, NULL, HUE_TEXT, HUE_LONGTEXT, VLC_FALSE );
00082 add_float_with_range( "saturation", 1.0, 0.0, 3.0, NULL, SAT_TEXT, SAT_LONGTEXT, VLC_FALSE );
00083 add_float_with_range( "gamma", 1.0, 0.01, 10.0, NULL, GAMMA_TEXT, GAMMA_LONGTEXT, VLC_FALSE );
00084
00085 add_shortcut( "adjust" );
00086 set_callbacks( Create, Destroy );
00087 vlc_module_end();
00088
00089
00090
00091
00092
00093
00094
00095 struct vout_sys_t
00096 {
00097 vout_thread_t *p_vout;
00098 };
00099
00100 inline static int32_t clip( int32_t a )
00101 {
00102 return (a > 255) ? 255 : (a < 0) ? 0 : a;
00103 }
00104
00105
00106
00107
00108 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
00109 {
00110 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
00111 }
00112
00113
00114
00115
00116
00117
00118 static int Create( vlc_object_t *p_this )
00119 {
00120 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00121
00122
00123 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00124 if( p_vout->p_sys == NULL )
00125 {
00126 msg_Err( p_vout, "out of memory" );
00127 return VLC_ENOMEM;
00128 }
00129
00130 p_vout->pf_init = Init;
00131 p_vout->pf_end = End;
00132 p_vout->pf_manage = NULL;
00133 p_vout->pf_render = Render;
00134 p_vout->pf_display = NULL;
00135 p_vout->pf_control = Control;
00136
00137 var_Create( p_vout, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
00138 var_Create( p_vout, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
00139 var_Create( p_vout, "hue", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
00140 var_Create( p_vout, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
00141 var_Create( p_vout, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
00142
00143 return VLC_SUCCESS;
00144 }
00145
00146
00147
00148
00149 static int Init( vout_thread_t *p_vout )
00150 {
00151 int i_index;
00152 picture_t *p_pic;
00153 video_format_t fmt = {0};
00154
00155 I_OUTPUTPICTURES = 0;
00156
00157
00158 p_vout->output.i_chroma = p_vout->render.i_chroma;
00159 p_vout->output.i_width = p_vout->render.i_width;
00160 p_vout->output.i_height = p_vout->render.i_height;
00161 p_vout->output.i_aspect = p_vout->render.i_aspect;
00162
00163 fmt.i_width = fmt.i_visible_width = p_vout->render.i_width;
00164 fmt.i_height = fmt.i_visible_height = p_vout->render.i_height;
00165 fmt.i_x_offset = fmt.i_y_offset = 0;
00166 fmt.i_chroma = p_vout->render.i_chroma;
00167 fmt.i_aspect = p_vout->render.i_aspect;
00168 fmt.i_sar_num = p_vout->render.i_aspect * fmt.i_height / fmt.i_width;
00169 fmt.i_sar_den = VOUT_ASPECT_FACTOR;
00170
00171
00172 msg_Dbg( p_vout, "spawning the real video output" );
00173
00174 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
00175
00176
00177 if( p_vout->p_sys->p_vout == NULL )
00178 {
00179 msg_Err( p_vout, "can't open vout, aborting" );
00180
00181 return VLC_EGENERIC;
00182 }
00183
00184 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
00185
00186 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00187
00188 ADD_PARENT_CALLBACKS( SendEventsToChild );
00189
00190 return VLC_SUCCESS;
00191 }
00192
00193
00194
00195
00196 static void End( vout_thread_t *p_vout )
00197 {
00198 int i_index;
00199
00200
00201 for( i_index = I_OUTPUTPICTURES ; i_index ; )
00202 {
00203 i_index--;
00204 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
00205 }
00206 }
00207
00208
00209
00210
00211
00212
00213 static void Destroy( vlc_object_t *p_this )
00214 {
00215 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00216
00217 if( p_vout->p_sys->p_vout )
00218 {
00219 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00220 vlc_object_detach( p_vout->p_sys->p_vout );
00221 vout_Destroy( p_vout->p_sys->p_vout );
00222 }
00223
00224 DEL_PARENT_CALLBACKS( SendEventsToChild );
00225
00226 free( p_vout->p_sys );
00227 }
00228
00229
00230
00231
00232
00233
00234
00235
00236 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
00237 {
00238 int pi_luma[256];
00239 int pi_gamma[256];
00240
00241 picture_t *p_outpic;
00242 uint8_t *p_in, *p_in_v, *p_in_end, *p_line_end;
00243 uint8_t *p_out, *p_out_v;
00244
00245 double f_hue;
00246 double f_gamma;
00247 int32_t i_cont, i_lum;
00248 int i_sat, i_sin, i_cos, i_x, i_y;
00249 int i;
00250 vlc_value_t val;
00251
00252
00253 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
00254 == NULL )
00255 {
00256 if( p_vout->b_die || p_vout->b_error )
00257 {
00258 return;
00259 }
00260 msleep( VOUT_OUTMEM_SLEEP );
00261 }
00262
00263 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
00264 vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
00265
00266
00267 var_Get( p_vout, "contrast", &val );
00268 i_cont = (int) ( val.f_float * 255 );
00269 var_Get( p_vout, "brightness", &val );
00270 i_lum = (int) (( val.f_float - 1.0 ) * 255 );
00271 var_Get( p_vout, "hue", &val );
00272 f_hue = (float) ( val.i_int * M_PI / 180 );
00273 var_Get( p_vout, "saturation", &val );
00274 i_sat = (int) (val.f_float * 256 );
00275 var_Get( p_vout, "gamma", &val );
00276 f_gamma = 1.0 / val.f_float;
00277
00278
00279
00280 i_lum += 128 - i_cont / 2;
00281
00282
00283 for( i = 0 ; i < 256 ; i++ )
00284 {
00285 pi_gamma[ i ] = clip( pow(i / 255.0, f_gamma) * 255.0);
00286 }
00287
00288
00289 for( i = 0 ; i < 256 ; i++ )
00290 {
00291 pi_luma[ i ] = pi_gamma[clip( i_lum + i_cont * i / 256)];
00292 }
00293
00294
00295
00296
00297
00298 p_in = p_pic->p[0].p_pixels;
00299 p_in_end = p_in + p_pic->p[0].i_visible_lines * p_pic->p[0].i_pitch - 8;
00300
00301 p_out = p_outpic->p[0].p_pixels;
00302
00303 for( ; p_in < p_in_end ; )
00304 {
00305 p_line_end = p_in + p_pic->p[0].i_visible_pitch - 8;
00306
00307 for( ; p_in < p_line_end ; )
00308 {
00309
00310 *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
00311 *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
00312 *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
00313 *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ];
00314 }
00315
00316 p_line_end += 8;
00317
00318 for( ; p_in < p_line_end ; )
00319 {
00320 *p_out++ = pi_luma[ *p_in++ ];
00321 }
00322
00323 p_in += p_pic->p[0].i_pitch - p_pic->p[0].i_visible_pitch;
00324 p_out += p_outpic->p[0].i_pitch - p_outpic->p[0].i_visible_pitch;
00325 }
00326
00327
00328
00329
00330
00331 p_in = p_pic->p[1].p_pixels;
00332 p_in_v = p_pic->p[2].p_pixels;
00333 p_in_end = p_in + p_pic->p[1].i_visible_lines * p_pic->p[1].i_pitch - 8;
00334
00335 p_out = p_outpic->p[1].p_pixels;
00336 p_out_v = p_outpic->p[2].p_pixels;
00337
00338 i_sin = sin(f_hue) * 256;
00339 i_cos = cos(f_hue) * 256;
00340
00341 i_x = ( cos(f_hue) + sin(f_hue) ) * 32768;
00342 i_y = ( cos(f_hue) - sin(f_hue) ) * 32768;
00343
00344 if ( i_sat > 256 )
00345 {
00346 #define WRITE_UV_CLIP() \
00347 i_u = *p_in++ ; i_v = *p_in_v++ ; \
00348 *p_out++ = clip( (( ((i_u * i_cos + i_v * i_sin - i_x) >> 8) \
00349 * i_sat) >> 8) + 128); \
00350 *p_out_v++ = clip( (( ((i_v * i_cos - i_u * i_sin - i_y) >> 8) \
00351 * i_sat) >> 8) + 128)
00352
00353 uint8_t i_u, i_v;
00354
00355 for( ; p_in < p_in_end ; )
00356 {
00357 p_line_end = p_in + p_pic->p[1].i_visible_pitch - 8;
00358
00359 for( ; p_in < p_line_end ; )
00360 {
00361
00362 WRITE_UV_CLIP(); WRITE_UV_CLIP();
00363 WRITE_UV_CLIP(); WRITE_UV_CLIP();
00364 WRITE_UV_CLIP(); WRITE_UV_CLIP();
00365 WRITE_UV_CLIP(); WRITE_UV_CLIP();
00366 }
00367
00368 p_line_end += 8;
00369
00370 for( ; p_in < p_line_end ; )
00371 {
00372 WRITE_UV_CLIP();
00373 }
00374
00375 p_in += p_pic->p[1].i_pitch - p_pic->p[1].i_visible_pitch;
00376 p_in_v += p_pic->p[2].i_pitch - p_pic->p[2].i_visible_pitch;
00377 p_out += p_outpic->p[1].i_pitch - p_outpic->p[1].i_visible_pitch;
00378 p_out_v += p_outpic->p[2].i_pitch - p_outpic->p[2].i_visible_pitch;
00379 }
00380 }
00381 else
00382 {
00383 #define WRITE_UV() \
00384 i_u = *p_in++ ; i_v = *p_in_v++ ; \
00385 *p_out++ = (( ((i_u * i_cos + i_v * i_sin - i_x) >> 8) \
00386 * i_sat) >> 8) + 128; \
00387 *p_out_v++ = (( ((i_v * i_cos - i_u * i_sin - i_y) >> 8) \
00388 * i_sat) >> 8) + 128
00389
00390 uint8_t i_u, i_v;
00391
00392 for( ; p_in < p_in_end ; )
00393 {
00394 p_line_end = p_in + p_pic->p[1].i_visible_pitch - 8;
00395
00396 for( ; p_in < p_line_end ; )
00397 {
00398
00399 WRITE_UV(); WRITE_UV(); WRITE_UV(); WRITE_UV();
00400 WRITE_UV(); WRITE_UV(); WRITE_UV(); WRITE_UV();
00401 }
00402
00403 p_line_end += 8;
00404
00405 for( ; p_in < p_line_end ; )
00406 {
00407 WRITE_UV();
00408 }
00409
00410 p_in += p_pic->p[1].i_pitch - p_pic->p[1].i_visible_pitch;
00411 p_in_v += p_pic->p[2].i_pitch - p_pic->p[2].i_visible_pitch;
00412 p_out += p_outpic->p[1].i_pitch - p_outpic->p[1].i_visible_pitch;
00413 p_out_v += p_outpic->p[2].i_pitch - p_outpic->p[2].i_visible_pitch;
00414 }
00415 }
00416
00417 vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
00418
00419 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
00420 }
00421
00422
00423
00424
00425 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
00426 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00427 {
00428 var_Set( (vlc_object_t *)p_data, psz_var, newval );
00429
00430 return VLC_SUCCESS;
00431 }
00432
00433
00434
00435
00436 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
00437 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00438 {
00439 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00440 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
00441 return VLC_SUCCESS;
00442 }