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 <stdlib.h>
00028 #include <string.h>
00029
00030 #include <vlc/vlc.h>
00031 #include <vlc/vout.h>
00032
00033 #include "filter_common.h"
00034
00035 #define TRANSFORM_MODE_HFLIP 1
00036 #define TRANSFORM_MODE_VFLIP 2
00037 #define TRANSFORM_MODE_90 3
00038 #define TRANSFORM_MODE_180 4
00039 #define TRANSFORM_MODE_270 5
00040
00041
00042
00043
00044 static int Create ( vlc_object_t * );
00045 static void Destroy ( vlc_object_t * );
00046
00047 static int Init ( vout_thread_t * );
00048 static void End ( vout_thread_t * );
00049 static void Render ( vout_thread_t *, picture_t * );
00050
00051 static int SendEvents( vlc_object_t *, char const *,
00052 vlc_value_t, vlc_value_t, void * );
00053
00054
00055
00056
00057 #define TYPE_TEXT N_("Transform type")
00058 #define TYPE_LONGTEXT N_("One of '90', '180', '270', 'hflip' and 'vflip'")
00059
00060 static char *type_list[] = { "90", "180", "270", "hflip", "vflip" };
00061 static char *type_list_text[] = { N_("Rotate by 90 degrees"),
00062 N_("Rotate by 180 degrees"), N_("Rotate by 270 degrees"),
00063 N_("Flip horizontally"), N_("Flip vertically") };
00064
00065 vlc_module_begin();
00066 set_description( _("Video transformation filter") );
00067 set_shortname( N_("Transformation"));
00068 set_capability( "video filter", 0 );
00069 set_category( CAT_VIDEO );
00070 set_subcategory( SUBCAT_VIDEO_VFILTER );
00071
00072 add_string( "transform-type", "90", NULL,
00073 TYPE_TEXT, TYPE_LONGTEXT, VLC_FALSE);
00074 change_string_list( type_list, type_list_text, 0);
00075
00076 add_shortcut( "transform" );
00077 set_callbacks( Create, Destroy );
00078 vlc_module_end();
00079
00080
00081
00082
00083
00084
00085
00086 struct vout_sys_t
00087 {
00088 int i_mode;
00089 vlc_bool_t b_rotation;
00090 vout_thread_t *p_vout;
00091 };
00092
00093
00094
00095
00096 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
00097 {
00098 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
00099 }
00100
00101
00102
00103
00104
00105
00106 static int Create( vlc_object_t *p_this )
00107 {
00108 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00109 char *psz_method;
00110
00111
00112 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00113 if( p_vout->p_sys == NULL )
00114 {
00115 msg_Err( p_vout, "out of memory" );
00116 return VLC_ENOMEM;
00117 }
00118
00119 p_vout->pf_init = Init;
00120 p_vout->pf_end = End;
00121 p_vout->pf_manage = NULL;
00122 p_vout->pf_render = Render;
00123 p_vout->pf_display = NULL;
00124 p_vout->pf_control = Control;
00125
00126
00127 psz_method = config_GetPsz( p_vout, "transform-type" );
00128
00129 if( psz_method == NULL )
00130 {
00131 msg_Err( p_vout, "configuration variable %s empty", "transform-type" );
00132 msg_Err( p_vout, "no valid transform mode provided, using '90'" );
00133 p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
00134 p_vout->p_sys->b_rotation = 1;
00135 }
00136 else
00137 {
00138 if( !strcmp( psz_method, "hflip" ) )
00139 {
00140 p_vout->p_sys->i_mode = TRANSFORM_MODE_HFLIP;
00141 p_vout->p_sys->b_rotation = 0;
00142 }
00143 else if( !strcmp( psz_method, "vflip" ) )
00144 {
00145 p_vout->p_sys->i_mode = TRANSFORM_MODE_VFLIP;
00146 p_vout->p_sys->b_rotation = 0;
00147 }
00148 else if( !strcmp( psz_method, "90" ) )
00149 {
00150 p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
00151 p_vout->p_sys->b_rotation = 1;
00152 }
00153 else if( !strcmp( psz_method, "180" ) )
00154 {
00155 p_vout->p_sys->i_mode = TRANSFORM_MODE_180;
00156 p_vout->p_sys->b_rotation = 0;
00157 }
00158 else if( !strcmp( psz_method, "270" ) )
00159 {
00160 p_vout->p_sys->i_mode = TRANSFORM_MODE_270;
00161 p_vout->p_sys->b_rotation = 1;
00162 }
00163 else
00164 {
00165 msg_Err( p_vout, "no valid transform mode provided, using '90'" );
00166 p_vout->p_sys->i_mode = TRANSFORM_MODE_90;
00167 p_vout->p_sys->b_rotation = 1;
00168 }
00169
00170 free( psz_method );
00171 }
00172
00173 return VLC_SUCCESS;
00174 }
00175
00176
00177
00178
00179 static int Init( vout_thread_t *p_vout )
00180 {
00181 int i_index;
00182 picture_t *p_pic;
00183 video_format_t fmt = {0};
00184
00185 I_OUTPUTPICTURES = 0;
00186
00187
00188 p_vout->output.i_chroma = p_vout->render.i_chroma;
00189 p_vout->output.i_width = p_vout->render.i_width;
00190 p_vout->output.i_height = p_vout->render.i_height;
00191 p_vout->output.i_aspect = p_vout->render.i_aspect;
00192 p_vout->fmt_out = p_vout->fmt_in;
00193 fmt = p_vout->fmt_out;
00194
00195
00196 msg_Dbg( p_vout, "spawning the real video output" );
00197
00198 if( p_vout->p_sys->b_rotation )
00199 {
00200 fmt.i_width = p_vout->fmt_out.i_height;
00201 fmt.i_visible_width = p_vout->fmt_out.i_visible_height;
00202 fmt.i_x_offset = p_vout->fmt_out.i_y_offset;
00203
00204 fmt.i_height = p_vout->fmt_out.i_width;
00205 fmt.i_visible_height = p_vout->fmt_out.i_visible_width;
00206 fmt.i_y_offset = p_vout->fmt_out.i_x_offset;
00207
00208 fmt.i_aspect = VOUT_ASPECT_FACTOR *
00209 (uint64_t)VOUT_ASPECT_FACTOR / fmt.i_aspect;
00210
00211 fmt.i_sar_num = p_vout->fmt_out.i_sar_den;
00212 fmt.i_sar_den = p_vout->fmt_out.i_sar_num;
00213
00214 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
00215 }
00216 else
00217 {
00218 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
00219 }
00220
00221
00222 if( p_vout->p_sys->p_vout == NULL )
00223 {
00224 msg_Err( p_vout, "cannot open vout, aborting" );
00225 return VLC_EGENERIC;
00226 }
00227
00228 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
00229
00230 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00231
00232 ADD_PARENT_CALLBACKS( SendEventsToChild );
00233
00234 return VLC_SUCCESS;
00235 }
00236
00237
00238
00239
00240 static void End( vout_thread_t *p_vout )
00241 {
00242 int i_index;
00243
00244
00245 for( i_index = I_OUTPUTPICTURES ; i_index ; )
00246 {
00247 i_index--;
00248 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
00249 }
00250 }
00251
00252
00253
00254
00255
00256
00257 static void Destroy( vlc_object_t *p_this )
00258 {
00259 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00260
00261 if( p_vout->p_sys->p_vout )
00262 {
00263 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00264 vlc_object_detach( p_vout->p_sys->p_vout );
00265 vout_Destroy( p_vout->p_sys->p_vout );
00266 }
00267
00268 DEL_PARENT_CALLBACKS( SendEventsToChild );
00269
00270 free( p_vout->p_sys );
00271 }
00272
00273
00274
00275
00276
00277
00278
00279
00280 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
00281 {
00282 picture_t *p_outpic;
00283 int i_index;
00284
00285
00286 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
00287 == NULL )
00288 {
00289 if( p_vout->b_die || p_vout->b_error )
00290 {
00291 return;
00292 }
00293 msleep( VOUT_OUTMEM_SLEEP );
00294 }
00295
00296 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
00297 vout_LinkPicture( p_vout->p_sys->p_vout, p_outpic );
00298
00299 switch( p_vout->p_sys->i_mode )
00300 {
00301 case TRANSFORM_MODE_90:
00302 for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00303 {
00304 int i_pitch = p_pic->p[i_index].i_pitch;
00305
00306 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00307
00308 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00309 uint8_t *p_out_end = p_out +
00310 p_outpic->p[i_index].i_visible_lines *
00311 p_outpic->p[i_index].i_pitch;
00312
00313 for( ; p_out < p_out_end ; )
00314 {
00315 uint8_t *p_line_end;
00316
00317 p_out_end -= p_outpic->p[i_index].i_pitch
00318 - p_outpic->p[i_index].i_visible_pitch;
00319 p_line_end = p_in + p_pic->p[i_index].i_visible_lines *
00320 i_pitch;
00321
00322 for( ; p_in < p_line_end ; )
00323 {
00324 p_line_end -= i_pitch;
00325 *(--p_out_end) = *p_line_end;
00326 }
00327
00328 p_in++;
00329 }
00330 }
00331 break;
00332
00333 case TRANSFORM_MODE_180:
00334 for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00335 {
00336 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00337 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
00338 * p_pic->p[i_index].i_pitch;
00339
00340 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00341
00342 for( ; p_in < p_in_end ; )
00343 {
00344 uint8_t *p_line_start = p_in_end
00345 - p_pic->p[i_index].i_pitch;
00346 p_in_end -= p_pic->p[i_index].i_pitch
00347 - p_pic->p[i_index].i_visible_pitch;
00348
00349 for( ; p_line_start < p_in_end ; )
00350 {
00351 *p_out++ = *(--p_in_end);
00352 }
00353
00354 p_out += p_outpic->p[i_index].i_pitch
00355 - p_outpic->p[i_index].i_visible_pitch;
00356 }
00357 }
00358 break;
00359
00360 case TRANSFORM_MODE_270:
00361 for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00362 {
00363 int i_pitch = p_pic->p[i_index].i_pitch;
00364
00365 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00366
00367 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00368 uint8_t *p_out_end = p_out +
00369 p_outpic->p[i_index].i_visible_lines *
00370 p_outpic->p[i_index].i_pitch;
00371
00372 for( ; p_out < p_out_end ; )
00373 {
00374 uint8_t *p_in_end;
00375
00376 p_in_end = p_in + p_pic->p[i_index].i_visible_lines *
00377 i_pitch;
00378
00379 for( ; p_in < p_in_end ; )
00380 {
00381 p_in_end -= i_pitch;
00382 *p_out++ = *p_in_end;
00383 }
00384
00385 p_out += p_outpic->p[i_index].i_pitch
00386 - p_outpic->p[i_index].i_visible_pitch;
00387 p_in++;
00388 }
00389 }
00390 break;
00391
00392 case TRANSFORM_MODE_HFLIP:
00393 for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00394 {
00395 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00396 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
00397 * p_pic->p[i_index].i_pitch;
00398
00399 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00400
00401 for( ; p_in < p_in_end ; )
00402 {
00403 p_in_end -= p_pic->p[i_index].i_pitch;
00404 p_vout->p_vlc->pf_memcpy( p_out, p_in_end,
00405 p_pic->p[i_index].i_visible_pitch );
00406 p_out += p_pic->p[i_index].i_pitch;
00407 }
00408 }
00409 break;
00410
00411 case TRANSFORM_MODE_VFLIP:
00412 for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ )
00413 {
00414 uint8_t *p_in = p_pic->p[i_index].p_pixels;
00415 uint8_t *p_in_end = p_in + p_pic->p[i_index].i_visible_lines
00416 * p_pic->p[i_index].i_pitch;
00417
00418 uint8_t *p_out = p_outpic->p[i_index].p_pixels;
00419
00420 for( ; p_in < p_in_end ; )
00421 {
00422 uint8_t *p_line_end = p_in
00423 + p_pic->p[i_index].i_visible_pitch;
00424
00425 for( ; p_in < p_line_end ; )
00426 {
00427 *p_out++ = *(--p_line_end);
00428 }
00429
00430 p_in += p_pic->p[i_index].i_pitch;
00431 }
00432 }
00433 break;
00434
00435 default:
00436 break;
00437 }
00438
00439 vout_UnlinkPicture( p_vout->p_sys->p_vout, p_outpic );
00440
00441 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
00442 }
00443
00444
00445
00446
00447 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
00448 vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
00449 {
00450 vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
00451 vlc_value_t sentval = newval;
00452
00453
00454 if( !strcmp( psz_var, "mouse-x" ) )
00455 {
00456 switch( p_vout->p_sys->i_mode )
00457 {
00458 case TRANSFORM_MODE_270:
00459 sentval.i_int = p_vout->p_sys->p_vout->output.i_width
00460 - sentval.i_int;
00461 case TRANSFORM_MODE_90:
00462 var_Set( p_vout, "mouse-y", sentval );
00463 return VLC_SUCCESS;
00464
00465 case TRANSFORM_MODE_180:
00466 case TRANSFORM_MODE_HFLIP:
00467 sentval.i_int = p_vout->p_sys->p_vout->output.i_width
00468 - sentval.i_int;
00469 break;
00470
00471 case TRANSFORM_MODE_VFLIP:
00472 default:
00473 break;
00474 }
00475 }
00476 else if( !strcmp( psz_var, "mouse-y" ) )
00477 {
00478 switch( p_vout->p_sys->i_mode )
00479 {
00480 case TRANSFORM_MODE_90:
00481 sentval.i_int = p_vout->p_sys->p_vout->output.i_height
00482 - sentval.i_int;
00483 case TRANSFORM_MODE_270:
00484 var_Set( p_vout, "mouse-x", sentval );
00485 return VLC_SUCCESS;
00486
00487 case TRANSFORM_MODE_180:
00488 case TRANSFORM_MODE_VFLIP:
00489 sentval.i_int = p_vout->p_sys->p_vout->output.i_height
00490 - sentval.i_int;
00491 break;
00492
00493 case TRANSFORM_MODE_HFLIP:
00494 default:
00495 break;
00496 }
00497 }
00498
00499 var_Set( p_vout, psz_var, sentval );
00500
00501 return VLC_SUCCESS;
00502 }
00503
00504
00505
00506
00507 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
00508 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00509 {
00510 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00511 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
00512 return VLC_SUCCESS;
00513 }