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
00031 #include <vlc/vlc.h>
00032 #include <vlc/vout.h>
00033 #include <vlc/sout.h>
00034 #include "vlc_filter.h"
00035
00036 #ifdef HAVE_ALTIVEC_H
00037 # include <altivec.h>
00038 #endif
00039
00040 #ifdef CAN_COMPILE_MMXEXT
00041 # include "mmx.h"
00042 #endif
00043
00044 #include "filter_common.h"
00045
00046 #define DEINTERLACE_DISCARD 1
00047 #define DEINTERLACE_MEAN 2
00048 #define DEINTERLACE_BLEND 3
00049 #define DEINTERLACE_BOB 4
00050 #define DEINTERLACE_LINEAR 5
00051 #define DEINTERLACE_X 6
00052
00053
00054
00055
00056 static int Create ( vlc_object_t * );
00057 static void Destroy ( vlc_object_t * );
00058
00059 static int Init ( vout_thread_t * );
00060 static void End ( vout_thread_t * );
00061 static void Render ( vout_thread_t *, picture_t * );
00062
00063 static void RenderDiscard( vout_thread_t *, picture_t *, picture_t *, int );
00064 static void RenderBob ( vout_thread_t *, picture_t *, picture_t *, int );
00065 static void RenderMean ( vout_thread_t *, picture_t *, picture_t * );
00066 static void RenderBlend ( vout_thread_t *, picture_t *, picture_t * );
00067 static void RenderLinear ( vout_thread_t *, picture_t *, picture_t *, int );
00068 static void RenderX ( vout_thread_t *, picture_t *, picture_t * );
00069
00070 static void MergeGeneric ( void *, const void *, const void *, size_t );
00071 #if defined(CAN_COMPILE_C_ALTIVEC)
00072 static void MergeAltivec ( void *, const void *, const void *, size_t );
00073 #endif
00074 #if defined(CAN_COMPILE_MMXEXT)
00075 static void MergeMMX ( void *, const void *, const void *, size_t );
00076 #endif
00077 #if defined(CAN_COMPILE_SSE)
00078 static void MergeSSE2 ( void *, const void *, const void *, size_t );
00079 #endif
00080 #if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
00081 static void EndMMX ( void );
00082 #endif
00083
00084 static int SendEvents ( vlc_object_t *, char const *,
00085 vlc_value_t, vlc_value_t, void * );
00086
00087 static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method );
00088 static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout );
00089
00090 static int OpenFilter( vlc_object_t *p_this );
00091 static void CloseFilter( vlc_object_t *p_this );
00092
00093
00094
00095
00096 static int FilterCallback ( vlc_object_t *, char const *,
00097 vlc_value_t, vlc_value_t, void * );
00098
00099
00100
00101
00102 #define MODE_TEXT N_("Deinterlace mode")
00103 #define MODE_LONGTEXT N_("Default deinterlace method to use for local playback")
00104
00105 #define SOUT_MODE_TEXT N_("Deinterlace mode")
00106 #define SOUT_MODE_LONGTEXT N_("Default deinterlace methode to use for streaming")
00107
00108 #define FILTER_CFG_PREFIX "sout-deinterlace-"
00109
00110 static char *mode_list[] = { "discard", "blend", "mean", "bob", "linear", "x" };
00111 static char *mode_list_text[] = { N_("Discard"), N_("Blend"), N_("Mean"),
00112 N_("Bob"), N_("Linear"), "X" };
00113
00114 vlc_module_begin();
00115 set_description( _("Deinterlacing video filter") );
00116 set_shortname( N_("Deinterlace" ));
00117 set_capability( "video filter", 0 );
00118 set_category( CAT_VIDEO );
00119 set_subcategory( SUBCAT_VIDEO_VFILTER );
00120
00121 set_section( N_("Display"),NULL);
00122 add_string( "deinterlace-mode", "discard", NULL, MODE_TEXT,
00123 MODE_LONGTEXT, VLC_FALSE );
00124 change_string_list( mode_list, mode_list_text, 0 );
00125
00126 add_shortcut( "deinterlace" );
00127 set_callbacks( Create, Destroy );
00128
00129 add_submodule();
00130 set_capability( "video filter2", 0 );
00131 set_section( N_("Streaming"),NULL);
00132 add_string( FILTER_CFG_PREFIX "mode", "blend", NULL, SOUT_MODE_TEXT,
00133 SOUT_MODE_LONGTEXT, VLC_FALSE );
00134 change_string_list( mode_list, mode_list_text, 0 );
00135 set_callbacks( OpenFilter, CloseFilter );
00136 vlc_module_end();
00137
00138 static const char *ppsz_filter_options[] = {
00139 "mode", NULL
00140 };
00141
00142
00143
00144
00145
00146
00147
00148 struct vout_sys_t
00149 {
00150 int i_mode;
00151 vlc_bool_t b_double_rate;
00152
00153 mtime_t last_date;
00154 mtime_t next_date;
00155
00156 vout_thread_t *p_vout;
00157
00158 vlc_mutex_t filter_lock;
00159
00160 void (*pf_merge) ( void *, const void *, const void *, size_t );
00161 void (*pf_end_merge) ( void );
00162 };
00163
00164
00165
00166
00167 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
00168 {
00169 if( i_query == VOUT_SET_ZOOM )
00170 {
00171 p_vout->p_sys->p_vout->i_window_width = p_vout->i_window_width;
00172 p_vout->p_sys->p_vout->i_window_height = p_vout->i_window_height;
00173 }
00174 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
00175 }
00176
00177
00178
00179
00180
00181
00182 static int Create( vlc_object_t *p_this )
00183 {
00184 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00185 vlc_value_t val;
00186
00187
00188 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
00189 if( p_vout->p_sys == NULL )
00190 {
00191 msg_Err( p_vout, "out of memory" );
00192 return VLC_ENOMEM;
00193 }
00194
00195 p_vout->pf_init = Init;
00196 p_vout->pf_end = End;
00197 p_vout->pf_manage = NULL;
00198 p_vout->pf_render = Render;
00199 p_vout->pf_display = NULL;
00200 p_vout->pf_control = Control;
00201
00202 p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
00203 p_vout->p_sys->b_double_rate = VLC_FALSE;
00204 p_vout->p_sys->last_date = 0;
00205 p_vout->p_sys->p_vout = 0;
00206 vlc_mutex_init( p_vout, &p_vout->p_sys->filter_lock );
00207
00208 #if defined(CAN_COMPILE_C_ALTIVEC)
00209 if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC )
00210 {
00211 p_vout->p_sys->pf_merge = MergeAltivec;
00212 p_vout->p_sys->pf_end_merge = NULL;
00213 }
00214 else
00215 #endif
00216 #if defined(CAN_COMPILE_SSE)
00217 if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_SSE2 )
00218 {
00219 p_vout->p_sys->pf_merge = MergeSSE2;
00220 p_vout->p_sys->pf_end_merge = EndMMX;
00221 }
00222 else
00223 #endif
00224 #if defined(CAN_COMPILE_MMXEXT)
00225 if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
00226 {
00227 p_vout->p_sys->pf_merge = MergeMMX;
00228 p_vout->p_sys->pf_end_merge = EndMMX;
00229 }
00230 else
00231 #endif
00232 {
00233 p_vout->p_sys->pf_merge = MergeGeneric;
00234 p_vout->p_sys->pf_end_merge = NULL;
00235 }
00236
00237
00238 var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING );
00239 var_Change( p_vout, "deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
00240
00241 if( val.psz_string == NULL )
00242 {
00243 msg_Err( p_vout, "configuration variable deinterlace-mode empty" );
00244 msg_Err( p_vout, "no deinterlace mode provided, using \"discard\"" );
00245
00246 val.psz_string = strdup( "discard" );
00247 }
00248
00249 msg_Dbg( p_vout, "using %s deinterlace mode", val.psz_string );
00250
00251 SetFilterMethod( p_vout, val.psz_string );
00252
00253 free( val.psz_string );
00254
00255 return VLC_SUCCESS;
00256 }
00257
00258
00259
00260
00261 static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method )
00262 {
00263 if( !strcmp( psz_method, "discard" ) )
00264 {
00265 p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
00266 p_vout->p_sys->b_double_rate = VLC_FALSE;
00267 }
00268 else if( !strcmp( psz_method, "mean" ) )
00269 {
00270 p_vout->p_sys->i_mode = DEINTERLACE_MEAN;
00271 p_vout->p_sys->b_double_rate = VLC_FALSE;
00272 }
00273 else if( !strcmp( psz_method, "blend" )
00274 || !strcmp( psz_method, "average" )
00275 || !strcmp( psz_method, "combine-fields" ) )
00276 {
00277 p_vout->p_sys->i_mode = DEINTERLACE_BLEND;
00278 p_vout->p_sys->b_double_rate = VLC_FALSE;
00279 }
00280 else if( !strcmp( psz_method, "bob" )
00281 || !strcmp( psz_method, "progressive-scan" ) )
00282 {
00283 p_vout->p_sys->i_mode = DEINTERLACE_BOB;
00284 p_vout->p_sys->b_double_rate = VLC_TRUE;
00285 }
00286 else if( !strcmp( psz_method, "linear" ) )
00287 {
00288 p_vout->p_sys->i_mode = DEINTERLACE_LINEAR;
00289 p_vout->p_sys->b_double_rate = VLC_TRUE;
00290 }
00291 else if( !strcmp( psz_method, "x" ) )
00292 {
00293 p_vout->p_sys->i_mode = DEINTERLACE_X;
00294 p_vout->p_sys->b_double_rate = VLC_FALSE;
00295 }
00296 else
00297 {
00298 msg_Err( p_vout, "no valid deinterlace mode provided, "
00299 "using \"discard\"" );
00300 }
00301
00302 msg_Dbg( p_vout, "using %s deinterlace method", psz_method );
00303 }
00304
00305
00306
00307
00308 static int Init( vout_thread_t *p_vout )
00309 {
00310 int i_index;
00311 picture_t *p_pic;
00312
00313 I_OUTPUTPICTURES = 0;
00314
00315
00316
00317 switch( p_vout->render.i_chroma )
00318 {
00319 case VLC_FOURCC('I','4','2','0'):
00320 case VLC_FOURCC('I','Y','U','V'):
00321 case VLC_FOURCC('Y','V','1','2'):
00322 case VLC_FOURCC('I','4','2','2'):
00323 p_vout->output.i_chroma = p_vout->render.i_chroma;
00324 p_vout->output.i_width = p_vout->render.i_width;
00325 p_vout->output.i_height = p_vout->render.i_height;
00326 p_vout->output.i_aspect = p_vout->render.i_aspect;
00327 p_vout->fmt_out = p_vout->fmt_in;
00328 break;
00329
00330 default:
00331 return VLC_EGENERIC;
00332 break;
00333 }
00334
00335
00336 p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
00337
00338 if( p_vout->p_sys->p_vout == NULL )
00339 {
00340
00341 msg_Err( p_vout, "cannot open vout, aborting" );
00342
00343 return VLC_EGENERIC;
00344 }
00345
00346 var_AddCallback( p_vout, "deinterlace-mode", FilterCallback, NULL );
00347
00348 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
00349
00350 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00351
00352 ADD_PARENT_CALLBACKS( SendEventsToChild );
00353
00354 return VLC_SUCCESS;
00355 }
00356
00357
00358
00359
00360 static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout )
00361 {
00362 vout_thread_t *p_real_vout = NULL;
00363 video_format_t fmt = {0};
00364
00365 msg_Dbg( p_vout, "spawning the real video output" );
00366
00367 fmt = p_vout->fmt_out;
00368
00369 switch( p_vout->render.i_chroma )
00370 {
00371 case VLC_FOURCC('I','4','2','0'):
00372 case VLC_FOURCC('I','Y','U','V'):
00373 case VLC_FOURCC('Y','V','1','2'):
00374 switch( p_vout->p_sys->i_mode )
00375 {
00376 case DEINTERLACE_MEAN:
00377 case DEINTERLACE_DISCARD:
00378 fmt.i_height /= 2; fmt.i_visible_height /= 2; fmt.i_y_offset /= 2;
00379 fmt.i_sar_den *= 2;
00380 p_real_vout = vout_Create( p_vout, &fmt );
00381 break;
00382
00383 case DEINTERLACE_BOB:
00384 case DEINTERLACE_BLEND:
00385 case DEINTERLACE_LINEAR:
00386 case DEINTERLACE_X:
00387 p_real_vout = vout_Create( p_vout, &fmt );
00388 break;
00389 }
00390 break;
00391
00392 case VLC_FOURCC('I','4','2','2'):
00393 fmt.i_chroma = VLC_FOURCC('I','4','2','0');
00394 p_real_vout = vout_Create( p_vout, &fmt );
00395 break;
00396
00397 default:
00398 break;
00399 }
00400
00401 return p_real_vout;
00402 }
00403
00404
00405
00406
00407 static void End( vout_thread_t *p_vout )
00408 {
00409 int i_index;
00410
00411
00412 for( i_index = I_OUTPUTPICTURES ; i_index ; )
00413 {
00414 i_index--;
00415 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
00416 }
00417
00418 if( p_vout->p_sys->p_vout )
00419 {
00420 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
00421 vlc_object_detach( p_vout->p_sys->p_vout );
00422 vout_Destroy( p_vout->p_sys->p_vout );
00423 }
00424
00425 DEL_PARENT_CALLBACKS( SendEventsToChild );
00426 }
00427
00428
00429
00430
00431
00432
00433 static void Destroy( vlc_object_t *p_this )
00434 {
00435 vout_thread_t *p_vout = (vout_thread_t *)p_this;
00436 vlc_mutex_destroy( &p_vout->p_sys->filter_lock );
00437 free( p_vout->p_sys );
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447 static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
00448 {
00449 vout_sys_t *p_sys = p_vout->p_sys;
00450 picture_t *pp_outpic[2];
00451
00452 p_vout->fmt_out.i_x_offset = p_sys->p_vout->fmt_in.i_x_offset =
00453 p_vout->fmt_in.i_x_offset;
00454 p_vout->fmt_out.i_y_offset = p_sys->p_vout->fmt_in.i_y_offset =
00455 p_vout->fmt_in.i_y_offset;
00456 p_vout->fmt_out.i_visible_width = p_sys->p_vout->fmt_in.i_visible_width =
00457 p_vout->fmt_in.i_visible_width;
00458 p_vout->fmt_out.i_visible_height = p_sys->p_vout->fmt_in.i_visible_height =
00459 p_vout->fmt_in.i_visible_height;
00460 if( p_vout->p_sys->i_mode == DEINTERLACE_MEAN ||
00461 p_vout->p_sys->i_mode == DEINTERLACE_DISCARD )
00462 {
00463 p_vout->fmt_out.i_y_offset /= 2; p_sys->p_vout->fmt_in.i_y_offset /= 2;
00464 p_vout->fmt_out.i_visible_height /= 2;
00465 p_sys->p_vout->fmt_in.i_visible_height /= 2;
00466 }
00467
00468 pp_outpic[0] = pp_outpic[1] = NULL;
00469
00470 vlc_mutex_lock( &p_vout->p_sys->filter_lock );
00471
00472
00473 while( ( pp_outpic[0] = vout_CreatePicture( p_vout->p_sys->p_vout,
00474 0, 0, 0 ) )
00475 == NULL )
00476 {
00477 if( p_vout->b_die || p_vout->b_error )
00478 {
00479 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
00480 return;
00481 }
00482 msleep( VOUT_OUTMEM_SLEEP );
00483 }
00484
00485 vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[0], p_pic->date );
00486
00487
00488 if( p_vout->p_sys->b_double_rate )
00489 {
00490 while( ( pp_outpic[1] = vout_CreatePicture( p_vout->p_sys->p_vout,
00491 0, 0, 0 ) )
00492 == NULL )
00493 {
00494 if( p_vout->b_die || p_vout->b_error )
00495 {
00496 vout_DestroyPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
00497 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
00498 return;
00499 }
00500 msleep( VOUT_OUTMEM_SLEEP );
00501 }
00502
00503
00504 if( !p_vout->p_sys->last_date )
00505 {
00506 vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1],
00507 p_pic->date + 20000 );
00508 }
00509 else
00510 {
00511 vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1],
00512 (3 * p_pic->date - p_vout->p_sys->last_date) / 2 );
00513 }
00514 p_vout->p_sys->last_date = p_pic->date;
00515 }
00516
00517 switch( p_vout->p_sys->i_mode )
00518 {
00519 case DEINTERLACE_DISCARD:
00520 RenderDiscard( p_vout, pp_outpic[0], p_pic, 0 );
00521 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
00522 break;
00523
00524 case DEINTERLACE_BOB:
00525 RenderBob( p_vout, pp_outpic[0], p_pic, 0 );
00526 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
00527 RenderBob( p_vout, pp_outpic[1], p_pic, 1 );
00528 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
00529 break;
00530
00531 case DEINTERLACE_LINEAR:
00532 RenderLinear( p_vout, pp_outpic[0], p_pic, 0 );
00533 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
00534 RenderLinear( p_vout, pp_outpic[1], p_pic, 1 );
00535 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
00536 break;
00537
00538 case DEINTERLACE_MEAN:
00539 RenderMean( p_vout, pp_outpic[0], p_pic );
00540 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
00541 break;
00542
00543 case DEINTERLACE_BLEND:
00544 RenderBlend( p_vout, pp_outpic[0], p_pic );
00545 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
00546 break;
00547
00548 case DEINTERLACE_X:
00549 RenderX( p_vout, pp_outpic[0], p_pic );
00550 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
00551 break;
00552 }
00553 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
00554 }
00555
00556
00557
00558
00559 static void RenderDiscard( vout_thread_t *p_vout,
00560 picture_t *p_outpic, picture_t *p_pic, int i_field )
00561 {
00562 int i_plane;
00563
00564
00565 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
00566 {
00567 uint8_t *p_in, *p_out_end, *p_out;
00568 int i_increment;
00569
00570 p_in = p_pic->p[i_plane].p_pixels
00571 + i_field * p_pic->p[i_plane].i_pitch;
00572
00573 p_out = p_outpic->p[i_plane].p_pixels;
00574 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
00575 * p_outpic->p[i_plane].i_visible_lines;
00576
00577 switch( p_vout->render.i_chroma )
00578 {
00579 case VLC_FOURCC('I','4','2','0'):
00580 case VLC_FOURCC('I','Y','U','V'):
00581 case VLC_FOURCC('Y','V','1','2'):
00582
00583 for( ; p_out < p_out_end ; )
00584 {
00585 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00586 p_pic->p[i_plane].i_pitch );
00587
00588 p_out += p_pic->p[i_plane].i_pitch;
00589 p_in += 2 * p_pic->p[i_plane].i_pitch;
00590 }
00591 break;
00592
00593 case VLC_FOURCC('I','4','2','2'):
00594
00595 i_increment = 2 * p_pic->p[i_plane].i_pitch;
00596
00597 if( i_plane == Y_PLANE )
00598 {
00599 for( ; p_out < p_out_end ; )
00600 {
00601 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00602 p_pic->p[i_plane].i_pitch );
00603 p_out += p_pic->p[i_plane].i_pitch;
00604 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00605 p_pic->p[i_plane].i_pitch );
00606 p_out += p_pic->p[i_plane].i_pitch;
00607 p_in += i_increment;
00608 }
00609 }
00610 else
00611 {
00612 for( ; p_out < p_out_end ; )
00613 {
00614 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00615 p_pic->p[i_plane].i_pitch );
00616 p_out += p_pic->p[i_plane].i_pitch;
00617 p_in += i_increment;
00618 }
00619 }
00620 break;
00621
00622 default:
00623 break;
00624 }
00625 }
00626 }
00627
00628
00629
00630
00631 static void RenderBob( vout_thread_t *p_vout,
00632 picture_t *p_outpic, picture_t *p_pic, int i_field )
00633 {
00634 int i_plane;
00635
00636
00637 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
00638 {
00639 uint8_t *p_in, *p_out_end, *p_out;
00640
00641 p_in = p_pic->p[i_plane].p_pixels;
00642 p_out = p_outpic->p[i_plane].p_pixels;
00643 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
00644 * p_outpic->p[i_plane].i_visible_lines;
00645
00646 switch( p_vout->render.i_chroma )
00647 {
00648 case VLC_FOURCC('I','4','2','0'):
00649 case VLC_FOURCC('I','Y','U','V'):
00650 case VLC_FOURCC('Y','V','1','2'):
00651
00652 if( i_field == 1 )
00653 {
00654 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00655 p_pic->p[i_plane].i_pitch );
00656 p_in += p_pic->p[i_plane].i_pitch;
00657 p_out += p_pic->p[i_plane].i_pitch;
00658 }
00659
00660 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
00661
00662 for( ; p_out < p_out_end ; )
00663 {
00664 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00665 p_pic->p[i_plane].i_pitch );
00666
00667 p_out += p_pic->p[i_plane].i_pitch;
00668
00669 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00670 p_pic->p[i_plane].i_pitch );
00671
00672 p_in += 2 * p_pic->p[i_plane].i_pitch;
00673 p_out += p_pic->p[i_plane].i_pitch;
00674 }
00675
00676 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00677 p_pic->p[i_plane].i_pitch );
00678
00679
00680 if( i_field == 0 )
00681 {
00682 p_in += p_pic->p[i_plane].i_pitch;
00683 p_out += p_pic->p[i_plane].i_pitch;
00684 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00685 p_pic->p[i_plane].i_pitch );
00686 }
00687 break;
00688
00689 case VLC_FOURCC('I','4','2','2'):
00690
00691 if( i_field == 1 )
00692 {
00693 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00694 p_pic->p[i_plane].i_pitch );
00695 p_in += p_pic->p[i_plane].i_pitch;
00696 p_out += p_pic->p[i_plane].i_pitch;
00697 }
00698
00699 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
00700
00701 if( i_plane == Y_PLANE )
00702 {
00703 for( ; p_out < p_out_end ; )
00704 {
00705 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00706 p_pic->p[i_plane].i_pitch );
00707
00708 p_out += p_pic->p[i_plane].i_pitch;
00709
00710 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00711 p_pic->p[i_plane].i_pitch );
00712
00713 p_in += 2 * p_pic->p[i_plane].i_pitch;
00714 p_out += p_pic->p[i_plane].i_pitch;
00715 }
00716 }
00717 else
00718 {
00719 for( ; p_out < p_out_end ; )
00720 {
00721 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00722 p_pic->p[i_plane].i_pitch );
00723
00724 p_out += p_pic->p[i_plane].i_pitch;
00725 p_in += 2 * p_pic->p[i_plane].i_pitch;
00726 }
00727 }
00728
00729 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00730 p_pic->p[i_plane].i_pitch );
00731
00732
00733 if( i_field == 0 )
00734 {
00735 p_in += p_pic->p[i_plane].i_pitch;
00736 p_out += p_pic->p[i_plane].i_pitch;
00737 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00738 p_pic->p[i_plane].i_pitch );
00739 }
00740 break;
00741 }
00742 }
00743 }
00744
00745 #define Merge p_vout->p_sys->pf_merge
00746 #define EndMerge if(p_vout->p_sys->pf_end_merge) p_vout->p_sys->pf_end_merge
00747
00748
00749
00750
00751 static void RenderLinear( vout_thread_t *p_vout,
00752 picture_t *p_outpic, picture_t *p_pic, int i_field )
00753 {
00754 int i_plane;
00755
00756
00757 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
00758 {
00759 uint8_t *p_in, *p_out_end, *p_out;
00760
00761 p_in = p_pic->p[i_plane].p_pixels;
00762 p_out = p_outpic->p[i_plane].p_pixels;
00763 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
00764 * p_outpic->p[i_plane].i_visible_lines;
00765
00766
00767 if( i_field == 1 )
00768 {
00769 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00770 p_pic->p[i_plane].i_pitch );
00771 p_in += p_pic->p[i_plane].i_pitch;
00772 p_out += p_pic->p[i_plane].i_pitch;
00773 }
00774
00775 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
00776
00777 for( ; p_out < p_out_end ; )
00778 {
00779 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00780 p_pic->p[i_plane].i_pitch );
00781
00782 p_out += p_pic->p[i_plane].i_pitch;
00783
00784 Merge( p_out, p_in, p_in + 2 * p_pic->p[i_plane].i_pitch,
00785 p_pic->p[i_plane].i_pitch );
00786
00787 p_in += 2 * p_pic->p[i_plane].i_pitch;
00788 p_out += p_pic->p[i_plane].i_pitch;
00789 }
00790
00791 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00792 p_pic->p[i_plane].i_pitch );
00793
00794
00795 if( i_field == 0 )
00796 {
00797 p_in += p_pic->p[i_plane].i_pitch;
00798 p_out += p_pic->p[i_plane].i_pitch;
00799 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00800 p_pic->p[i_plane].i_pitch );
00801 }
00802 }
00803 EndMerge();
00804 }
00805
00806 static void RenderMean( vout_thread_t *p_vout,
00807 picture_t *p_outpic, picture_t *p_pic )
00808 {
00809 int i_plane;
00810
00811
00812 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
00813 {
00814 uint8_t *p_in, *p_out_end, *p_out;
00815
00816 p_in = p_pic->p[i_plane].p_pixels;
00817
00818 p_out = p_outpic->p[i_plane].p_pixels;
00819 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
00820 * p_outpic->p[i_plane].i_visible_lines;
00821
00822
00823 for( ; p_out < p_out_end ; )
00824 {
00825 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
00826 p_pic->p[i_plane].i_pitch );
00827
00828 p_out += p_pic->p[i_plane].i_pitch;
00829 p_in += 2 * p_pic->p[i_plane].i_pitch;
00830 }
00831 }
00832 EndMerge();
00833 }
00834
00835 static void RenderBlend( vout_thread_t *p_vout,
00836 picture_t *p_outpic, picture_t *p_pic )
00837 {
00838 int i_plane;
00839
00840
00841 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
00842 {
00843 uint8_t *p_in, *p_out_end, *p_out;
00844
00845 p_in = p_pic->p[i_plane].p_pixels;
00846
00847 p_out = p_outpic->p[i_plane].p_pixels;
00848 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
00849 * p_outpic->p[i_plane].i_visible_lines;
00850
00851 switch( p_vout->render.i_chroma )
00852 {
00853 case VLC_FOURCC('I','4','2','0'):
00854 case VLC_FOURCC('I','Y','U','V'):
00855 case VLC_FOURCC('Y','V','1','2'):
00856
00857 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00858 p_pic->p[i_plane].i_pitch );
00859 p_out += p_pic->p[i_plane].i_pitch;
00860
00861
00862 for( ; p_out < p_out_end ; )
00863 {
00864 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
00865 p_pic->p[i_plane].i_pitch );
00866
00867 p_out += p_pic->p[i_plane].i_pitch;
00868 p_in += p_pic->p[i_plane].i_pitch;
00869 }
00870 break;
00871
00872 case VLC_FOURCC('I','4','2','2'):
00873
00874 p_vout->p_vlc->pf_memcpy( p_out, p_in,
00875 p_pic->p[i_plane].i_pitch );
00876 p_out += p_pic->p[i_plane].i_pitch;
00877
00878
00879 if( i_plane == Y_PLANE )
00880 {
00881 for( ; p_out < p_out_end ; )
00882 {
00883 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
00884 p_pic->p[i_plane].i_pitch );
00885
00886 p_out += p_pic->p[i_plane].i_pitch;
00887 p_in += p_pic->p[i_plane].i_pitch;
00888 }
00889 }
00890
00891 else
00892 {
00893 for( ; p_out < p_out_end ; )
00894 {
00895 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
00896 p_pic->p[i_plane].i_pitch );
00897
00898 p_out += p_pic->p[i_plane].i_pitch;
00899 p_in += 2*p_pic->p[i_plane].i_pitch;
00900 }
00901 }
00902 break;
00903 }
00904 }
00905 EndMerge();
00906 }
00907
00908 #undef Merge
00909
00910 static void MergeGeneric( void *_p_dest, const void *_p_s1,
00911 const void *_p_s2, size_t i_bytes )
00912 {
00913 uint8_t* p_dest = (uint8_t*)_p_dest;
00914 const uint8_t *p_s1 = (const uint8_t *)_p_s1;
00915 const uint8_t *p_s2 = (const uint8_t *)_p_s2;
00916 uint8_t* p_end = p_dest + i_bytes - 8;
00917
00918 while( p_dest < p_end )
00919 {
00920 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00921 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00922 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00923 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00924 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00925 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00926 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00927 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00928 }
00929
00930 p_end += 8;
00931
00932 while( p_dest < p_end )
00933 {
00934 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00935 }
00936 }
00937
00938 #if defined(CAN_COMPILE_MMXEXT)
00939 static void MergeMMX( void *_p_dest, const void *_p_s1, const void *_p_s2,
00940 size_t i_bytes )
00941 {
00942 uint8_t* p_dest = (uint8_t*)_p_dest;
00943 const uint8_t *p_s1 = (const uint8_t *)_p_s1;
00944 const uint8_t *p_s2 = (const uint8_t *)_p_s2;
00945 uint8_t* p_end = p_dest + i_bytes - 8;
00946 while( p_dest < p_end )
00947 {
00948 __asm__ __volatile__( "movq %2,%%mm1;"
00949 "pavgb %1, %%mm1;"
00950 "movq %%mm1, %0" :"=m" (*p_dest):
00951 "m" (*p_s1),
00952 "m" (*p_s2) );
00953 p_dest += 8;
00954 p_s1 += 8;
00955 p_s2 += 8;
00956 }
00957
00958 p_end += 8;
00959
00960 while( p_dest < p_end )
00961 {
00962 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00963 }
00964 }
00965 #endif
00966
00967 #if defined(CAN_COMPILE_SSE)
00968 static void MergeSSE2( void *_p_dest, const void *_p_s1, const void *_p_s2,
00969 size_t i_bytes )
00970 {
00971 uint8_t* p_dest = (uint8_t*)_p_dest;
00972 const uint8_t *p_s1 = (const uint8_t *)_p_s1;
00973 const uint8_t *p_s2 = (const uint8_t *)_p_s2;
00974 uint8_t* p_end;
00975 while( (ptrdiff_t)p_s1 % 16 )
00976 {
00977 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00978 }
00979 p_end = p_dest + i_bytes - 16;
00980 while( p_dest < p_end )
00981 {
00982 __asm__ __volatile__( "movdqu %2,%%xmm1;"
00983 "pavgb %1, %%xmm1;"
00984 "movdqu %%xmm1, %0" :"=m" (*p_dest):
00985 "m" (*p_s1),
00986 "m" (*p_s2) );
00987 p_dest += 16;
00988 p_s1 += 16;
00989 p_s2 += 16;
00990 }
00991
00992 p_end += 16;
00993
00994 while( p_dest < p_end )
00995 {
00996 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
00997 }
00998 }
00999 #endif
01000
01001 #if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
01002 static void EndMMX( void )
01003 {
01004 __asm__ __volatile__( "emms" :: );
01005 }
01006 #endif
01007
01008 #ifdef CAN_COMPILE_C_ALTIVEC
01009 static void MergeAltivec( void *_p_dest, const void *_p_s1,
01010 const void *_p_s2, size_t i_bytes )
01011 {
01012 uint8_t *p_dest = (uint8_t *)_p_dest;
01013 uint8_t *p_s1 = (uint8_t *)_p_s1;
01014 uint8_t *p_s2 = (uint8_t *)_p_s2;
01015 uint8_t *p_end = p_dest + i_bytes - 15;
01016
01017
01018 while( (int)p_dest & 0xF )
01019 {
01020 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
01021 }
01022
01023 if( ( (int)p_s1 & 0xF ) | ( (int)p_s2 & 0xF ) )
01024 {
01025
01026 vector unsigned char s1v, s2v, destv;
01027 vector unsigned char s1oldv, s2oldv, s1newv, s2newv;
01028 vector unsigned char perm1v, perm2v;
01029
01030 perm1v = vec_lvsl( 0, p_s1 );
01031 perm2v = vec_lvsl( 0, p_s2 );
01032 s1oldv = vec_ld( 0, p_s1 );
01033 s2oldv = vec_ld( 0, p_s2 );
01034
01035 while( p_dest < p_end )
01036 {
01037 s1newv = vec_ld( 16, p_s1 );
01038 s2newv = vec_ld( 16, p_s2 );
01039 s1v = vec_perm( s1oldv, s1newv, perm1v );
01040 s2v = vec_perm( s2oldv, s2newv, perm2v );
01041 s1oldv = s1newv;
01042 s2oldv = s2newv;
01043 destv = vec_avg( s1v, s2v );
01044 vec_st( destv, 0, p_dest );
01045
01046 p_s1 += 16;
01047 p_s2 += 16;
01048 p_dest += 16;
01049 }
01050 }
01051 else
01052 {
01053
01054 vector unsigned char s1v, s2v, destv;
01055
01056 while( p_dest < p_end )
01057 {
01058 s1v = vec_ld( 0, p_s1 );
01059 s2v = vec_ld( 0, p_s2 );
01060 destv = vec_avg( s1v, s2v );
01061 vec_st( destv, 0, p_dest );
01062
01063 p_s1 += 16;
01064 p_s2 += 16;
01065 p_dest += 16;
01066 }
01067 }
01068
01069 p_end += 15;
01070
01071 while( p_dest < p_end )
01072 {
01073 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
01074 }
01075 }
01076 #endif
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098 static inline int ssd( int a ) { return a*a; }
01099 static inline int XDeint8x8DetectC( uint8_t *src, int i_src )
01100 {
01101 int y, x;
01102 int ff, fr;
01103 int fc;
01104
01105
01106 fc = 0;
01107 for( y = 0; y < 7; y += 2 )
01108 {
01109 ff = fr = 0;
01110 for( x = 0; x < 8; x++ )
01111 {
01112 fr += ssd(src[ x] - src[1*i_src+x]) +
01113 ssd(src[i_src+x] - src[2*i_src+x]);
01114 ff += ssd(src[ x] - src[2*i_src+x]) +
01115 ssd(src[i_src+x] - src[3*i_src+x]);
01116 }
01117 if( ff < 6*fr/8 && fr > 32 )
01118 fc++;
01119
01120 src += 2*i_src;
01121 }
01122
01123 return fc < 1 ? VLC_FALSE : VLC_TRUE;
01124 }
01125 #ifdef CAN_COMPILE_MMXEXT
01126 static inline int XDeint8x8DetectMMXEXT( uint8_t *src, int i_src )
01127 {
01128
01129 int y, x;
01130 int32_t ff, fr;
01131 int fc;
01132
01133
01134 fc = 0;
01135 pxor_r2r( mm7, mm7 );
01136 for( y = 0; y < 9; y += 2 )
01137 {
01138 ff = fr = 0;
01139 pxor_r2r( mm5, mm5 );
01140 pxor_r2r( mm6, mm6 );
01141 for( x = 0; x < 8; x+=4 )
01142 {
01143 movd_m2r( src[ x], mm0 );
01144 movd_m2r( src[1*i_src+x], mm1 );
01145 movd_m2r( src[2*i_src+x], mm2 );
01146 movd_m2r( src[3*i_src+x], mm3 );
01147
01148 punpcklbw_r2r( mm7, mm0 );
01149 punpcklbw_r2r( mm7, mm1 );
01150 punpcklbw_r2r( mm7, mm2 );
01151 punpcklbw_r2r( mm7, mm3 );
01152
01153 movq_r2r( mm0, mm4 );
01154
01155 psubw_r2r( mm1, mm0 );
01156 psubw_r2r( mm2, mm4 );
01157
01158 psubw_r2r( mm1, mm2 );
01159 psubw_r2r( mm1, mm3 );
01160
01161 pmaddwd_r2r( mm0, mm0 );
01162 pmaddwd_r2r( mm4, mm4 );
01163 pmaddwd_r2r( mm2, mm2 );
01164 pmaddwd_r2r( mm3, mm3 );
01165 paddd_r2r( mm0, mm2 );
01166 paddd_r2r( mm4, mm3 );
01167 paddd_r2r( mm2, mm5 );
01168 paddd_r2r( mm3, mm6 );
01169 }
01170
01171 movq_r2r( mm5, mm0 );
01172 psrlq_i2r( 32, mm0 );
01173 paddd_r2r( mm0, mm5 );
01174 movd_r2m( mm5, fr );
01175
01176 movq_r2r( mm6, mm0 );
01177 psrlq_i2r( 32, mm0 );
01178 paddd_r2r( mm0, mm6 );
01179 movd_r2m( mm6, ff );
01180
01181 if( ff < 6*fr/8 && fr > 32 )
01182 fc++;
01183
01184 src += 2*i_src;
01185 }
01186 return fc;
01187 }
01188 #endif
01189
01190
01191
01192
01193
01194
01195 #if 0
01196 static inline void XDeint8x8FrameC( uint8_t *dst, int i_dst,
01197 uint8_t *src, int i_src )
01198 {
01199 int y, x;
01200
01201
01202 for( y = 0; y < 8; y += 2 )
01203 {
01204 memcpy( dst, src, 8 );
01205 dst += i_dst;
01206
01207 for( x = 0; x < 8; x++ )
01208 dst[x] = (src[x] + 6*src[1*i_src+x] + src[2*i_src+x] + 4 ) >> 3;
01209 dst += 1*i_dst;
01210 src += 2*i_src;
01211 }
01212 }
01213 #endif
01214 static inline void XDeint8x8MergeC( uint8_t *dst, int i_dst,
01215 uint8_t *src1, int i_src1,
01216 uint8_t *src2, int i_src2 )
01217 {
01218 int y, x;
01219
01220
01221 for( y = 0; y < 8; y += 2 )
01222 {
01223 memcpy( dst, src1, 8 );
01224 dst += i_dst;
01225
01226 for( x = 0; x < 8; x++ )
01227 dst[x] = (src1[x] + 6*src2[x] + src1[i_src1+x] + 4 ) >> 3;
01228 dst += i_dst;
01229
01230 src1 += i_src1;
01231 src2 += i_src2;
01232 }
01233 }
01234
01235 #ifdef CAN_COMPILE_MMXEXT
01236 static inline void XDeint8x8MergeMMXEXT( uint8_t *dst, int i_dst,
01237 uint8_t *src1, int i_src1,
01238 uint8_t *src2, int i_src2 )
01239 {
01240 static const uint64_t m_4 = I64C(0x0004000400040004);
01241 int y, x;
01242
01243
01244 pxor_r2r( mm7, mm7 );
01245 for( y = 0; y < 8; y += 2 )
01246 {
01247 for( x = 0; x < 8; x +=4 )
01248 {
01249 movd_m2r( src1[x], mm0 );
01250 movd_r2m( mm0, dst[x] );
01251
01252 movd_m2r( src2[x], mm1 );
01253 movd_m2r( src1[i_src1+x], mm2 );
01254
01255 punpcklbw_r2r( mm7, mm0 );
01256 punpcklbw_r2r( mm7, mm1 );
01257 punpcklbw_r2r( mm7, mm2 );
01258 paddw_r2r( mm1, mm1 );
01259 movq_r2r( mm1, mm3 );
01260 paddw_r2r( mm3, mm3 );
01261 paddw_r2r( mm2, mm0 );
01262 paddw_r2r( mm3, mm1 );
01263 paddw_m2r( m_4, mm1 );
01264 paddw_r2r( mm1, mm0 );
01265 psraw_i2r( 3, mm0 );
01266 packuswb_r2r( mm7, mm0 );
01267 movd_r2m( mm0, dst[i_dst+x] );
01268 }
01269 dst += 2*i_dst;
01270 src1 += i_src1;
01271 src2 += i_src2;
01272 }
01273 }
01274
01275 #endif
01276
01277
01278 static inline void XDeint8x8Set( uint8_t *dst, int i_dst, uint8_t v )
01279 {
01280 int y;
01281 for( y = 0; y < 8; y++ )
01282 memset( &dst[y*i_dst], v, 8 );
01283 }
01284
01285
01286
01287
01288
01289
01290 static inline void XDeint8x8FieldEC( uint8_t *dst, int i_dst,
01291 uint8_t *src, int i_src )
01292 {
01293 int y, x;
01294
01295
01296 for( y = 0; y < 8; y += 2 )
01297 {
01298 memcpy( dst, src, 8 );
01299 dst += i_dst;
01300
01301 for( x = 0; x < 8; x++ )
01302 dst[x] = (src[x] + src[2*i_src+x] ) >> 1;
01303 dst += 1*i_dst;
01304 src += 2*i_src;
01305 }
01306 }
01307 #ifdef CAN_COMPILE_MMXEXT
01308 static inline void XDeint8x8FieldEMMXEXT( uint8_t *dst, int i_dst,
01309 uint8_t *src, int i_src )
01310 {
01311 int y;
01312
01313
01314 for( y = 0; y < 8; y += 2 )
01315 {
01316 movq_m2r( src[0], mm0 );
01317 movq_r2m( mm0, dst[0] );
01318 dst += i_dst;
01319
01320 movq_m2r( src[2*i_src], mm1 );
01321 pavgb_r2r( mm1, mm0 );
01322
01323 movq_r2m( mm0, dst[0] );
01324
01325 dst += 1*i_dst;
01326 src += 2*i_src;
01327 }
01328 }
01329 #endif
01330
01331
01332
01333
01334 static inline void XDeint8x8FieldC( uint8_t *dst, int i_dst,
01335 uint8_t *src, int i_src )
01336 {
01337 int y, x;
01338
01339
01340 for( y = 0; y < 8; y += 2 )
01341 {
01342 memcpy( dst, src, 8 );
01343 dst += i_dst;
01344
01345 for( x = 0; x < 8; x++ )
01346 {
01347 uint8_t *src2 = &src[2*i_src];
01348
01349
01350 const int c0 = abs(src[x-4]-src2[x-2]) + abs(src[x-3]-src2[x-1]) +
01351 abs(src[x-2]-src2[x+0]) + abs(src[x-1]-src2[x+1]) +
01352 abs(src[x+0]-src2[x+2]) + abs(src[x+1]-src2[x+3]) +
01353 abs(src[x+2]-src2[x+4]) + abs(src[x+3]-src2[x+5]);
01354
01355 const int c1 = abs(src[x-3]-src2[x-3]) + abs(src[x-2]-src2[x-2]) +
01356 abs(src[x-1]-src2[x-1]) + abs(src[x+0]-src2[x+0]) +
01357 abs(src[x+1]-src2[x+1]) + abs(src[x+2]-src2[x+2]) +
01358 abs(src[x+3]-src2[x+3]) + abs(src[x+4]-src2[x+4]);
01359
01360 const int c2 = abs(src[x-2]-src2[x-4]) + abs(src[x-1]-src2[x-3]) +
01361 abs(src[x+0]-src2[x-2]) + abs(src[x+1]-src2[x-1]) +
01362 abs(src[x+2]-src2[x+0]) + abs(src[x+3]-src2[x+1]) +
01363 abs(src[x+4]-src2[x+2]) + abs(src[x+5]-src2[x+3]);
01364
01365 if( c0 < c1 && c1 <= c2 )
01366 dst[x] = (src[x-1] + src2[x+1]) >> 1;
01367 else if( c2 < c1 && c1 <= c0 )
01368 dst[x] = (src[x+1] + src2[x-1]) >> 1;
01369 else
01370 dst[x] = (src[x+0] + src2[x+0]) >> 1;
01371 }
01372
01373 dst += 1*i_dst;
01374 src += 2*i_src;
01375 }
01376 }
01377 #ifdef CAN_COMPILE_MMXEXT
01378 static inline void XDeint8x8FieldMMXEXT( uint8_t *dst, int i_dst,
01379 uint8_t *src, int i_src )
01380 {
01381 int y, x;
01382
01383
01384 for( y = 0; y < 8; y += 2 )
01385 {
01386 memcpy( dst, src, 8 );
01387 dst += i_dst;
01388
01389 for( x = 0; x < 8; x++ )
01390 {
01391 uint8_t *src2 = &src[2*i_src];
01392 int32_t c0, c1, c2;
01393
01394 movq_m2r( src[x-2], mm0 );
01395 movq_m2r( src[x-3], mm1 );
01396 movq_m2r( src[x-4], mm2 );
01397
01398 psadbw_m2r( src2[x-4], mm0 );
01399 psadbw_m2r( src2[x-3], mm1 );
01400 psadbw_m2r( src2[x-2], mm2 );
01401
01402 movd_r2m( mm0, c2 );
01403 movd_r2m( mm1, c1 );
01404 movd_r2m( mm2, c0 );
01405
01406 if( c0 < c1 && c1 <= c2 )
01407 dst[x] = (src[x-1] + src2[x+1]) >> 1;
01408 else if( c2 < c1 && c1 <= c0 )
01409 dst[x] = (src[x+1] + src2[x-1]) >> 1;
01410 else
01411 dst[x] = (src[x+0] + src2[x+0]) >> 1;
01412 }
01413
01414 dst += 1*i_dst;
01415 src += 2*i_src;
01416 }
01417 }
01418 #endif
01419
01420 #if 0
01421 static inline int XDeint8x8SsdC( uint8_t *pix1, int i_pix1,
01422 uint8_t *pix2, int i_pix2 )
01423 {
01424 int y, x;
01425 int s = 0;
01426
01427 for( y = 0; y < 8; y++ )
01428 for( x = 0; x < 8; x++ )
01429 s += ssd( pix1[y*i_pix1+x] - pix2[y*i_pix2+x] );
01430 return s;
01431 }
01432
01433 #ifdef CAN_COMPILE_MMXEXT
01434 static inline int XDeint8x8SsdMMXEXT( uint8_t *pix1, int i_pix1,
01435 uint8_t *pix2, int i_pix2 )
01436 {
01437 int y;
01438 int32_t s;
01439
01440 pxor_r2r( mm7, mm7 );
01441 pxor_r2r( mm6, mm6 );
01442
01443 for( y = 0; y < 8; y++ )
01444 {
01445 movq_m2r( pix1[0], mm0 );
01446 movq_m2r( pix2[0], mm1 );
01447
01448 movq_r2r( mm0, mm2 );
01449 movq_r2r( mm1, mm3 );
01450
01451 punpcklbw_r2r( mm7, mm0 );
01452 punpckhbw_r2r( mm7, mm2 );
01453 punpcklbw_r2r( mm7, mm1 );
01454 punpckhbw_r2r( mm7, mm3 );
01455
01456 psubw_r2r( mm1, mm0 );
01457 psubw_r2r( mm3, mm2 );
01458
01459 pmaddwd_r2r( mm0, mm0 );
01460 pmaddwd_r2r( mm2, mm2 );
01461
01462 paddd_r2r( mm2, mm0 );
01463 paddd_r2r( mm0, mm6 );
01464
01465 pix1 += i_pix1;
01466 pix2 += i_pix2;
01467 }
01468
01469 movq_r2r( mm6, mm7 );
01470 psrlq_i2r( 32, mm7 );
01471 paddd_r2r( mm6, mm7 );
01472 movd_r2m( mm7, s );
01473
01474 return s;
01475 }
01476 #endif
01477 #endif
01478
01479 #if 0
01480
01481 #ifdef CAN_COMPILE_MMXEXT
01482
01483
01484
01485
01486 static inline void XDeintMC( uint8_t *dst, int i_dst,
01487 uint8_t *src, int i_src,
01488 int mvx, int mvy,
01489 int i_width, int i_height )
01490 {
01491 const int d4x = mvx&0x03;
01492 const int d4y = mvy&0x03;
01493
01494 const int cA = (4-d4x)*(4-d4y);
01495 const int cB = d4x *(4-d4y);
01496 const int cC = (4-d4x)*d4y;
01497 const int cD = d4x *d4y;
01498
01499 int y, x;
01500 uint8_t *srcp;
01501
01502
01503 src += (mvy >> 2) * i_src + (mvx >> 2);
01504 srcp = &src[i_src];
01505
01506 for( y = 0; y < i_height; y++ )
01507 {
01508 for( x = 0; x < i_width; x++ )
01509 {
01510 dst[x] = ( cA*src[x] + cB*src[x+1] +
01511 cC*srcp[x] + cD*srcp[x+1] + 8 ) >> 4;
01512 }
01513 dst += i_dst;
01514
01515 src = srcp;
01516 srcp += i_src;
01517 }
01518 }
01519 static int XDeint8x4SadMMXEXT( uint8_t *pix1, int i_pix1,
01520 uint8_t *pix2, int i_pix2 )
01521 {
01522 int32_t s;
01523
01524 movq_m2r( pix1[0*i_pix1], mm0 );
01525 movq_m2r( pix1[1*i_pix1], mm1 );
01526
01527 psadbw_m2r( pix2[0*i_pix2], mm0 );
01528 psadbw_m2r( pix2[1*i_pix2], mm1 );
01529
01530 movq_m2r( pix1[2*i_pix1], mm2 );
01531 movq_m2r( pix1[3*i_pix1], mm3 );
01532 psadbw_m2r( pix2[2*i_pix2], mm2 );
01533 psadbw_m2r( pix2[3*i_pix2], mm3 );
01534
01535 paddd_r2r( mm1, mm0 );
01536 paddd_r2r( mm3, mm2 );
01537 paddd_r2r( mm2, mm0 );
01538 movd_r2m( mm0, s );
01539
01540 return s;
01541 }
01542
01543 static inline int XDeint8x4TestQpel( uint8_t *src, int i_src,
01544 uint8_t *ref, int i_stride,
01545 int mx, int my,
01546 int xmax, int ymax )
01547 {
01548 uint8_t buffer[8*4];
01549
01550 if( abs(mx) >= 4*xmax || abs(my) >= 4*ymax )
01551 return 255*255*255;
01552
01553 XDeintMC( buffer, 8, ref, i_stride, mx, my, 8, 4 );
01554 return XDeint8x4SadMMXEXT( src, i_src, buffer, 8 );
01555 }
01556 static inline int XDeint8x4TestInt( uint8_t *src, int i_src,
01557 uint8_t *ref, int i_stride,
01558 int mx, int my,
01559 int xmax, int ymax )
01560 {
01561 if( abs(mx) >= xmax || abs(my) >= ymax )
01562 return 255*255*255;
01563
01564 return XDeint8x4SadMMXEXT( src, i_src, &ref[my*i_stride+mx], i_stride );
01565 }
01566
01567 static inline void XDeint8x8FieldMotion( uint8_t *dst, int i_dst,
01568 uint8_t *src, int i_src,
01569 int *mpx, int *mpy,
01570 int xmax, int ymax )
01571 {
01572 static const int dx[8] = { 0, 0, -1, 1, -1, -1, 1, 1 };
01573 static const int dy[8] = {-1, 1, 0, 0, -1, 1, -1, 1 };
01574 uint8_t *next = &src[i_src];
01575 const int i_src2 = 2*i_src;
01576 int mvx, mvy;
01577 int mvs, s;
01578 int i_step;
01579
01580 uint8_t *rec = &dst[i_dst];
01581
01582
01583 XDeint8x8FieldMMXEXT( dst, i_dst, src, i_src );
01584
01585
01586
01587
01588
01589 if( xmax > 4 ) xmax = 4;
01590 if( ymax > 4 ) ymax = 4;
01591
01592
01593 mvx = mvy = 0;
01594 mvs = XDeint8x4SadMMXEXT( rec, i_src2, next, i_src2 );
01595
01596
01597 if( (s=XDeint8x4TestInt( rec, i_src2, next, i_src2, *mpx, *mpy, xmax, ymax)) < mvs )
01598 {
01599 mvs = s;
01600 mvx = *mpx;
01601 mvy = *mpy;
01602 }
01603
01604 for( i_step = 0; i_step < 4; i_step++ )
01605 {
01606 int c = 4;
01607 int s;
01608 int i;
01609
01610 for( i = 0; i < 4; i++ )
01611 {
01612 s = XDeint8x4TestInt( rec, i_src2,
01613 next, i_src2, mvx+dx[i], mvy+dy[i],
01614 xmax, ymax );
01615 if( s < mvs )
01616 {
01617 mvs = s;
01618 c = i;
01619 }
01620 }
01621 if( c == 4 )
01622 break;
01623
01624 mvx += dx[c];
01625 mvy += dy[c];
01626 }
01627 *mpx = mvx;
01628 *mpy = mvy;
01629
01630 mvx <<= 2;
01631 mvy <<= 2;
01632
01633 if( mvs > 4 && mvs < 256 )
01634 {
01635
01636
01637 for( i_step = 0; i_step < 4; i_step++ )
01638 {
01639 int c = 8;
01640 int s;
01641 int i;
01642
01643 for( i = 0; i < 8; i++ )
01644 {
01645 s = XDeint8x4TestQpel( rec, i_src2, next, i_src2,
01646 mvx+dx[i], mvy+dy[i],
01647 xmax, ymax );
01648 if( s < mvs )
01649 {
01650 mvs = s;
01651 c = i;
01652 }
01653 }
01654 if( c == 8 )
01655 break;
01656
01657 mvx += dx[c];
01658 mvy += dy[c];
01659 }
01660 }
01661
01662 if( mvs < 128 )
01663 {
01664 uint8_t buffer[8*4];
01665 XDeintMC( buffer, 8, next, i_src2, mvx, mvy, 8, 4 );
01666 XDeint8x8MergeMMXEXT( dst, i_dst, src, 2*i_src, buffer, 8 );
01667
01668
01669 }
01670 }
01671 #endif
01672 #endif
01673
01674 #if 0
01675
01676
01677
01678
01679 static inline uint8_t clip1( int a )
01680 {
01681 if( a <= 0 )
01682 return 0;
01683 else if( a >= 255 )
01684 return 255;
01685 else
01686 return a;
01687 }
01688 static inline void XDeint8x8Field( uint8_t *dst, int i_dst,
01689 uint8_t *src, int i_src )
01690 {
01691 int y, x;
01692
01693
01694 for( y = 0; y < 8; y += 2 )
01695 {
01696 const int i_src2 = i_src*2;
01697
01698 memcpy( dst, src, 8 );
01699 dst += i_dst;
01700
01701 for( x = 0; x < 8; x++ )
01702 {
01703 int pix;
01704
01705 pix = 1*(src[-2*i_src2+x]+src[3*i_src2+x]) +
01706 -5*(src[-1*i_src2+x]+src[2*i_src2+x])
01707 +20*(src[ 0*i_src2+x]+src[1*i_src2+x]);
01708
01709 dst[x] = clip1( ( pix + 16 ) >> 5 );
01710 }
01711
01712 dst += 1*i_dst;
01713 src += 2*i_src;
01714 }
01715 }
01716
01717 #endif
01718
01719
01720
01721 static inline int XDeintNxNDetect( uint8_t *src, int i_src,
01722 int i_height, int i_width )
01723 {
01724 int y, x;
01725 int ff, fr;
01726 int fc;
01727
01728
01729
01730
01731 ff = fr = 0;
01732 fc = 0;
01733 for( y = 0; y < i_height - 2; y += 2 )
01734 {
01735 const uint8_t *s = &src[y*i_src];
01736 for( x = 0; x < i_width; x++ )
01737 {
01738 fr += ssd(s[ x] - s[1*i_src+x]);
01739 ff += ssd(s[ x] - s[2*i_src+x]);
01740 }
01741 if( ff < fr && fr > i_width / 2 )
01742 fc++;
01743 }
01744
01745 return fc < 2 ? VLC_FALSE : VLC_TRUE;
01746 }
01747
01748 static inline void XDeintNxNFrame( uint8_t *dst, int i_dst,
01749 uint8_t *src, int i_src,
01750 int i_width, int i_height )
01751 {
01752 int y, x;
01753
01754
01755 for( y = 0; y < i_height; y += 2 )
01756 {
01757 memcpy( dst, src, i_width );
01758 dst += i_dst;
01759
01760 if( y < i_height - 2 )
01761 {
01762 for( x = 0; x < i_width; x++ )
01763 dst[x] = (src[x] + 2*src[1*i_src+x] + src[2*i_src+x] + 2 ) >> 2;
01764 }
01765 else
01766 {
01767
01768 for( x = 0; x < i_width; x++ )
01769 dst[x] = (src[x] + src[1*i_src+x] ) >> 1;
01770 }
01771 dst += 1*i_dst;
01772 src += 2*i_src;
01773 }
01774 }
01775
01776 static inline void XDeintNxNField( uint8_t *dst, int i_dst,
01777 uint8_t *src, int i_src,
01778 int i_width, int i_height )
01779 {
01780 int y, x;
01781
01782
01783 for( y = 0; y < i_height; y += 2 )
01784 {
01785 memcpy( dst, src, i_width );
01786 dst += i_dst;
01787
01788 if( y < i_height - 2 )
01789 {
01790 for( x = 0; x < i_width; x++ )
01791 dst[x] = (src[x] + src[2*i_src+x] ) >> 1;
01792 }
01793 else
01794 {
01795
01796 for( x = 0; x < i_width; x++ )
01797 dst[x] = (src[x] + src[i_src+x]) >> 1;
01798 }
01799 dst += 1*i_dst;
01800 src += 2*i_src;
01801 }
01802 }
01803
01804 static inline void XDeintNxN( uint8_t *dst, int i_dst, uint8_t *src, int i_src,
01805 int i_width, int i_height )
01806 {
01807 if( XDeintNxNDetect( src, i_src, i_width, i_height ) )
01808 XDeintNxNField( dst, i_dst, src, i_src, i_width, i_height );
01809 else
01810 XDeintNxNFrame( dst, i_dst, src, i_src, i_width, i_height );
01811 }
01812
01813
01814 static inline int median( int a, int b, int c )
01815 {
01816 int min = a, max =a;
01817 if( b < min )
01818 min = b;
01819 else
01820 max = b;
01821
01822 if( c < min )
01823 min = c;
01824 else if( c > max )
01825 max = c;
01826
01827 return a + b + c - min - max;
01828 }
01829
01830
01831
01832
01833 static inline void XDeintBand8x8C( uint8_t *dst, int i_dst,
01834 uint8_t *src, int i_src,
01835 const int i_mbx, int i_modx )
01836 {
01837 int x;
01838
01839 for( x = 0; x < i_mbx; x++ )
01840 {
01841 int s;
01842 if( ( s = XDeint8x8DetectC( src, i_src ) ) )
01843 {
01844 if( x == 0 || x == i_mbx - 1 )
01845 XDeint8x8FieldEC( dst, i_dst, src, i_src );
01846 else
01847 XDeint8x8FieldC( dst, i_dst, src, i_src );
01848 }
01849 else
01850 {
01851 XDeint8x8MergeC( dst, i_dst,
01852 &src[0*i_src], 2*i_src,
01853 &src[1*i_src], 2*i_src );
01854 }
01855
01856 dst += 8;
01857 src += 8;
01858 }
01859
01860 if( i_modx )
01861 XDeintNxN( dst, i_dst, src, i_src, i_modx, 8 );
01862 }
01863 #ifdef CAN_COMPILE_MMXEXT
01864 static inline void XDeintBand8x8MMXEXT( uint8_t *dst, int i_dst,
01865 uint8_t *src, int i_src,
01866 const int i_mbx, int i_modx )
01867 {
01868 int x;
01869
01870
01871 for( x = 0; x < i_mbx; x++ )
01872 {
01873 int s;
01874 if( ( s = XDeint8x8DetectMMXEXT( src, i_src ) ) )
01875 {
01876 if( x == 0 || x == i_mbx - 1 )
01877 XDeint8x8FieldEMMXEXT( dst, i_dst, src, i_src );
01878 else
01879 XDeint8x8FieldMMXEXT( dst, i_dst, src, i_src );
01880 }
01881 else
01882 {
01883 XDeint8x8MergeMMXEXT( dst, i_dst,
01884 &src[0*i_src], 2*i_src,
01885 &src[1*i_src], 2*i_src );
01886 }
01887
01888 dst += 8;
01889 src += 8;
01890 }
01891
01892 if( i_modx )
01893 XDeintNxN( dst, i_dst, src, i_src, i_modx, 8 );
01894 }
01895 #endif
01896
01897 static void RenderX( vout_thread_t *p_vout,
01898 picture_t *p_outpic, picture_t *p_pic )
01899 {
01900 int i_plane;
01901
01902
01903 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
01904 {
01905 const int i_mby = ( p_outpic->p[i_plane].i_visible_lines + 7 )/8 - 1;
01906 const int i_mbx = p_outpic->p[i_plane].i_visible_pitch/8;
01907
01908 const int i_mody = p_outpic->p[i_plane].i_visible_lines - 8*i_mby;
01909 const int i_modx = p_outpic->p[i_plane].i_visible_pitch - 8*i_mbx;
01910
01911 const int i_dst = p_outpic->p[i_plane].i_pitch;
01912 const int i_src = p_pic->p[i_plane].i_pitch;
01913
01914 int y, x;
01915
01916 for( y = 0; y < i_mby; y++ )
01917 {
01918 uint8_t *dst = &p_outpic->p[i_plane].p_pixels[8*y*i_dst];
01919 uint8_t *src = &p_pic->p[i_plane].p_pixels[8*y*i_src];
01920
01921 #ifdef CAN_COMPILE_MMXEXT
01922 if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT )
01923 XDeintBand8x8MMXEXT( dst, i_dst, src, i_src, i_mbx, i_modx );
01924 else
01925 #endif
01926 XDeintBand8x8C( dst, i_dst, src, i_src, i_mbx, i_modx );
01927 }
01928
01929
01930 if( i_mody )
01931 {
01932 uint8_t *dst = &p_outpic->p[i_plane].p_pixels[8*y*i_dst];
01933 uint8_t *src = &p_pic->p[i_plane].p_pixels[8*y*i_src];
01934
01935 for( x = 0; x < i_mbx; x++ )
01936 {
01937 XDeintNxN( dst, i_dst, src, i_src, 8, i_mody );
01938
01939 dst += 8;
01940 src += 8;
01941 }
01942
01943 if( i_modx )
01944 XDeintNxN( dst, i_dst, src, i_src, i_modx, i_mody );
01945 }
01946 }
01947
01948 #ifdef CAN_COMPILE_MMXEXT
01949 if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_MMXEXT )
01950 emms();
01951 #endif
01952 }
01953
01954
01955
01956
01957 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
01958 vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
01959 {
01960 vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
01961 vlc_value_t sentval = newval;
01962
01963 if( !strcmp( psz_var, "mouse-y" ) )
01964 {
01965 switch( p_vout->p_sys->i_mode )
01966 {
01967 case DEINTERLACE_MEAN:
01968 case DEINTERLACE_DISCARD:
01969 sentval.i_int *= 2;
01970 break;
01971 }
01972 }
01973
01974 var_Set( p_vout, psz_var, sentval );
01975
01976 return VLC_SUCCESS;
01977 }
01978
01979
01980
01981
01982 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
01983 vlc_value_t oldval, vlc_value_t newval,
01984 void *p_data )
01985 {
01986 vout_thread_t * p_vout = (vout_thread_t *)p_this;
01987 int i_old_mode = p_vout->p_sys->i_mode;
01988
01989 msg_Dbg( p_vout, "using %s deinterlace mode", newval.psz_string );
01990
01991 vlc_mutex_lock( &p_vout->p_sys->filter_lock );
01992
01993 SetFilterMethod( p_vout, newval.psz_string );
01994
01995 switch( p_vout->render.i_chroma )
01996 {
01997 case VLC_FOURCC('I','4','2','2'):
01998 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
01999 return VLC_SUCCESS;
02000 break;
02001
02002 case VLC_FOURCC('I','4','2','0'):
02003 case VLC_FOURCC('I','Y','U','V'):
02004 case VLC_FOURCC('Y','V','1','2'):
02005 switch( p_vout->p_sys->i_mode )
02006 {
02007 case DEINTERLACE_MEAN:
02008 case DEINTERLACE_DISCARD:
02009 if( ( i_old_mode == DEINTERLACE_MEAN )
02010 || ( i_old_mode == DEINTERLACE_DISCARD ) )
02011 {
02012 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
02013 return VLC_SUCCESS;
02014 }
02015 break;
02016
02017 case DEINTERLACE_BOB:
02018 case DEINTERLACE_BLEND:
02019 case DEINTERLACE_LINEAR:
02020 if( ( i_old_mode == DEINTERLACE_BOB )
02021 || ( i_old_mode == DEINTERLACE_BLEND )
02022 || ( i_old_mode == DEINTERLACE_LINEAR ) )
02023 {
02024 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
02025 return VLC_SUCCESS;
02026 }
02027 break;
02028 }
02029 break;
02030
02031 default:
02032 break;
02033 }
02034
02035
02036
02037 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
02038
02039 vlc_object_detach( p_vout->p_sys->p_vout );
02040 vout_Destroy( p_vout->p_sys->p_vout );
02041
02042
02043 p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
02044
02045 if( p_vout->p_sys->p_vout == NULL )
02046 {
02047
02048 msg_Err( p_vout, "cannot open vout, aborting" );
02049
02050 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
02051 return VLC_EGENERIC;
02052 }
02053
02054 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
02055
02056 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
02057 return VLC_SUCCESS;
02058 }
02059
02060
02061
02062
02063 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
02064 vlc_value_t oldval, vlc_value_t newval, void *p_data )
02065 {
02066 vout_thread_t *p_vout = (vout_thread_t *)p_this;
02067 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
02068 return VLC_SUCCESS;
02069 }
02070
02071
02072
02073
02074
02075 static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic )
02076 {
02077 vout_thread_t *p_vout = (vout_thread_t *)p_filter->p_sys;
02078 picture_t *p_pic_dst;
02079
02080
02081 p_pic_dst = p_filter->pf_vout_buffer_new( p_filter );
02082 if( p_pic_dst == NULL )
02083 {
02084 msg_Warn( p_filter, "can't get output picture" );
02085 return NULL;
02086 }
02087
02088 switch( p_vout->p_sys->i_mode )
02089 {
02090 case DEINTERLACE_DISCARD:
02091 #if 0
02092 RenderDiscard( p_vout, p_pic_dst, p_pic, 0 );
02093 #endif
02094 msg_Err( p_vout, "discarding lines is not supported yet" );
02095 p_pic_dst->pf_release( p_pic_dst );
02096 return p_pic;
02097 break;
02098
02099 case DEINTERLACE_BOB:
02100 #if 0
02101 RenderBob( p_vout, pp_outpic[0], p_pic, 0 );
02102 RenderBob( p_vout, pp_outpic[1], p_pic, 1 );
02103 break;
02104 #endif
02105
02106 case DEINTERLACE_LINEAR:
02107 #if 0
02108 RenderLinear( p_vout, pp_outpic[0], p_pic, 0 );
02109 RenderLinear( p_vout, pp_outpic[1], p_pic, 1 );
02110 #endif
02111 msg_Err( p_vout, "doubling the frame rate is not supported yet" );
02112 p_pic_dst->pf_release( p_pic_dst );
02113 return p_pic;
02114 break;
02115
02116 case DEINTERLACE_MEAN:
02117 RenderMean( p_vout, p_pic_dst, p_pic );
02118 break;
02119
02120 case DEINTERLACE_BLEND:
02121 RenderBlend( p_vout, p_pic_dst, p_pic );
02122 break;
02123
02124 case DEINTERLACE_X:
02125 RenderX( p_vout, p_pic_dst, p_pic );
02126 break;
02127 }
02128
02129 p_pic_dst->date = p_pic->date;
02130 p_pic_dst->b_force = p_pic->b_force;
02131 p_pic_dst->i_nb_fields = p_pic->i_nb_fields;
02132 p_pic_dst->b_progressive = VLC_TRUE;
02133 p_pic_dst->b_top_field_first = p_pic->b_top_field_first;
02134
02135 p_pic->pf_release( p_pic );
02136 return p_pic_dst;
02137 }
02138
02139
02140
02141
02142 static int OpenFilter( vlc_object_t *p_this )
02143 {
02144 filter_t *p_filter = (filter_t*)p_this;
02145 vout_thread_t *p_vout;
02146 vlc_value_t val;
02147
02148 if( ( p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','4','2','0') &&
02149 p_filter->fmt_in.video.i_chroma != VLC_FOURCC('I','Y','U','V') &&
02150 p_filter->fmt_in.video.i_chroma != VLC_FOURCC('Y','V','1','2') ) ||
02151 p_filter->fmt_in.video.i_chroma != p_filter->fmt_out.video.i_chroma )
02152 {
02153 return VLC_EGENERIC;
02154 }
02155
02156
02157
02158 p_vout = vlc_object_create( p_filter, sizeof(vout_thread_t) );
02159 vlc_object_attach( p_vout, p_filter );
02160 p_filter->p_sys = (filter_sys_t *)p_vout;
02161 p_vout->render.i_chroma = p_filter->fmt_in.video.i_chroma;
02162
02163 sout_CfgParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options,
02164 p_filter->p_cfg );
02165 var_Get( p_filter, FILTER_CFG_PREFIX "mode", &val );
02166 var_Create( p_filter, "deinterlace-mode", VLC_VAR_STRING );
02167 var_Set( p_filter, "deinterlace-mode", val );
02168
02169 if ( Create( VLC_OBJECT(p_vout) ) != VLC_SUCCESS )
02170 {
02171 vlc_object_detach( p_vout );
02172 vlc_object_release( p_vout );
02173 return VLC_EGENERIC;
02174 }
02175
02176 p_filter->pf_video_filter = Deinterlace;
02177
02178 msg_Dbg( p_filter, "deinterlacing" );
02179
02180 return VLC_SUCCESS;
02181 }
02182
02183
02184
02185
02186 static void CloseFilter( vlc_object_t *p_this )
02187 {
02188 filter_t *p_filter = (filter_t*)p_this;
02189 vout_thread_t *p_vout = (vout_thread_t *)p_filter->p_sys;
02190
02191 Destroy( VLC_OBJECT(p_vout) );
02192 vlc_object_detach( p_vout );
02193 vlc_object_release( p_vout );
02194 }
02195