📄 deinterlace.c
字号:
#if 0/* Kernel interpolation (1,-5,20,20,-5,1) * Lose a bit more details+add aliasing than edge interpol but avoid * more artifacts */static inline uint8_t clip1( int a ){ if( a <= 0 ) return 0; else if( a >= 255 ) return 255; else return a;}static inline void XDeint8x8Field( uint8_t *dst, int i_dst, uint8_t *src, int i_src ){ int y, x; /* Interlaced */ for( y = 0; y < 8; y += 2 ) { const int i_src2 = i_src*2; memcpy( dst, src, 8 ); dst += i_dst; for( x = 0; x < 8; x++ ) { int pix; pix = 1*(src[-2*i_src2+x]+src[3*i_src2+x]) + -5*(src[-1*i_src2+x]+src[2*i_src2+x]) +20*(src[ 0*i_src2+x]+src[1*i_src2+x]); dst[x] = clip1( ( pix + 16 ) >> 5 ); } dst += 1*i_dst; src += 2*i_src; }}#endif/* NxN arbitray size (and then only use pixel in the NxN block) */static inline int XDeintNxNDetect( uint8_t *src, int i_src, int i_height, int i_width ){ int y, x; int ff, fr; int fc; /* Detect interlacing */ /* FIXME way too simple, need to be more like XDeint8x8Detect */ ff = fr = 0; fc = 0; for( y = 0; y < i_height - 2; y += 2 ) { const uint8_t *s = &src[y*i_src]; for( x = 0; x < i_width; x++ ) { fr += ssd(s[ x] - s[1*i_src+x]); ff += ssd(s[ x] - s[2*i_src+x]); } if( ff < fr && fr > i_width / 2 ) fc++; } return fc < 2 ? false : true;}static inline void XDeintNxNFrame( uint8_t *dst, int i_dst, uint8_t *src, int i_src, int i_width, int i_height ){ int y, x; /* Progressive */ for( y = 0; y < i_height; y += 2 ) { memcpy( dst, src, i_width ); dst += i_dst; if( y < i_height - 2 ) { for( x = 0; x < i_width; x++ ) dst[x] = (src[x] + 2*src[1*i_src+x] + src[2*i_src+x] + 2 ) >> 2; } else { /* Blend last line */ for( x = 0; x < i_width; x++ ) dst[x] = (src[x] + src[1*i_src+x] ) >> 1; } dst += 1*i_dst; src += 2*i_src; }}static inline void XDeintNxNField( uint8_t *dst, int i_dst, uint8_t *src, int i_src, int i_width, int i_height ){ int y, x; /* Interlaced */ for( y = 0; y < i_height; y += 2 ) { memcpy( dst, src, i_width ); dst += i_dst; if( y < i_height - 2 ) { for( x = 0; x < i_width; x++ ) dst[x] = (src[x] + src[2*i_src+x] ) >> 1; } else { /* Blend last line */ for( x = 0; x < i_width; x++ ) dst[x] = (src[x] + src[i_src+x]) >> 1; } dst += 1*i_dst; src += 2*i_src; }}static inline void XDeintNxN( uint8_t *dst, int i_dst, uint8_t *src, int i_src, int i_width, int i_height ){ if( XDeintNxNDetect( src, i_src, i_width, i_height ) ) XDeintNxNField( dst, i_dst, src, i_src, i_width, i_height ); else XDeintNxNFrame( dst, i_dst, src, i_src, i_width, i_height );}static inline int median( int a, int b, int c ){ int min = a, max =a; if( b < min ) min = b; else max = b; if( c < min ) min = c; else if( c > max ) max = c; return a + b + c - min - max;}/* XDeintBand8x8: */static inline void XDeintBand8x8C( uint8_t *dst, int i_dst, uint8_t *src, int i_src, const int i_mbx, int i_modx ){ int x; for( x = 0; x < i_mbx; x++ ) { int s; if( ( s = XDeint8x8DetectC( src, i_src ) ) ) { if( x == 0 || x == i_mbx - 1 ) XDeint8x8FieldEC( dst, i_dst, src, i_src ); else XDeint8x8FieldC( dst, i_dst, src, i_src ); } else { XDeint8x8MergeC( dst, i_dst, &src[0*i_src], 2*i_src, &src[1*i_src], 2*i_src ); } dst += 8; src += 8; } if( i_modx ) XDeintNxN( dst, i_dst, src, i_src, i_modx, 8 );}#ifdef CAN_COMPILE_MMXEXTstatic inline void XDeintBand8x8MMXEXT( uint8_t *dst, int i_dst, uint8_t *src, int i_src, const int i_mbx, int i_modx ){ int x; /* Reset current line */ for( x = 0; x < i_mbx; x++ ) { int s; if( ( s = XDeint8x8DetectMMXEXT( src, i_src ) ) ) { if( x == 0 || x == i_mbx - 1 ) XDeint8x8FieldEMMXEXT( dst, i_dst, src, i_src ); else XDeint8x8FieldMMXEXT( dst, i_dst, src, i_src ); } else { XDeint8x8MergeMMXEXT( dst, i_dst, &src[0*i_src], 2*i_src, &src[1*i_src], 2*i_src ); } dst += 8; src += 8; } if( i_modx ) XDeintNxN( dst, i_dst, src, i_src, i_modx, 8 );}#endifstatic void RenderX( picture_t *p_outpic, picture_t *p_pic ){ int i_plane; /* Copy image and skip lines */ for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) { const int i_mby = ( p_outpic->p[i_plane].i_visible_lines + 7 )/8 - 1; const int i_mbx = p_outpic->p[i_plane].i_visible_pitch/8; const int i_mody = p_outpic->p[i_plane].i_visible_lines - 8*i_mby; const int i_modx = p_outpic->p[i_plane].i_visible_pitch - 8*i_mbx; const int i_dst = p_outpic->p[i_plane].i_pitch; const int i_src = p_pic->p[i_plane].i_pitch; int y, x; for( y = 0; y < i_mby; y++ ) { uint8_t *dst = &p_outpic->p[i_plane].p_pixels[8*y*i_dst]; uint8_t *src = &p_pic->p[i_plane].p_pixels[8*y*i_src];#ifdef CAN_COMPILE_MMXEXT if( vlc_CPU() & CPU_CAPABILITY_MMXEXT ) XDeintBand8x8MMXEXT( dst, i_dst, src, i_src, i_mbx, i_modx ); else#endif XDeintBand8x8C( dst, i_dst, src, i_src, i_mbx, i_modx ); } /* Last line (C only)*/ if( i_mody ) { uint8_t *dst = &p_outpic->p[i_plane].p_pixels[8*y*i_dst]; uint8_t *src = &p_pic->p[i_plane].p_pixels[8*y*i_src]; for( x = 0; x < i_mbx; x++ ) { XDeintNxN( dst, i_dst, src, i_src, 8, i_mody ); dst += 8; src += 8; } if( i_modx ) XDeintNxN( dst, i_dst, src, i_src, i_modx, i_mody ); } }#ifdef CAN_COMPILE_MMXEXT if( vlc_CPU() & CPU_CAPABILITY_MMXEXT ) emms();#endif}/***************************************************************************** * SendEvents: forward mouse and keyboard events to the parent p_vout *****************************************************************************/static int SendEvents( vlc_object_t *p_this, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *_p_vout ){ VLC_UNUSED(p_this); VLC_UNUSED(oldval); vout_thread_t *p_vout = (vout_thread_t *)_p_vout; vlc_value_t sentval = newval; if( !strcmp( psz_var, "mouse-y" ) ) { switch( p_vout->p_sys->i_mode ) { case DEINTERLACE_MEAN: case DEINTERLACE_DISCARD: sentval.i_int *= 2; break; } } var_Set( p_vout, psz_var, sentval ); return VLC_SUCCESS;}/***************************************************************************** * FilterCallback: called when changing the deinterlace method on the fly. *****************************************************************************/static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd, vlc_value_t oldval, vlc_value_t newval, void *p_data ){ VLC_UNUSED(psz_cmd); VLC_UNUSED(p_data); VLC_UNUSED(oldval); vout_thread_t * p_vout = (vout_thread_t *)p_this; int i_old_mode = p_vout->p_sys->i_mode; msg_Dbg( p_vout, "using %s deinterlace mode", newval.psz_string ); vlc_mutex_lock( &p_vout->p_sys->filter_lock ); SetFilterMethod( p_vout, newval.psz_string ); switch( p_vout->render.i_chroma ) { case VLC_FOURCC('I','4','2','2'): vlc_mutex_unlock( &p_vout->p_sys->filter_lock ); return VLC_SUCCESS; break; case VLC_FOURCC('I','4','2','0'): case VLC_FOURCC('I','Y','U','V'): case VLC_FOURCC('Y','V','1','2'): switch( p_vout->p_sys->i_mode ) { case DEINTERLACE_MEAN: case DEINTERLACE_DISCARD: if( ( i_old_mode == DEINTERLACE_MEAN ) || ( i_old_mode == DEINTERLACE_DISCARD ) ) { vlc_mutex_unlock( &p_vout->p_sys->filter_lock ); return VLC_SUCCESS; } break; case DEINTERLACE_BOB: case DEINTERLACE_BLEND: case DEINTERLACE_LINEAR: if( ( i_old_mode == DEINTERLACE_BOB ) || ( i_old_mode == DEINTERLACE_BLEND ) || ( i_old_mode == DEINTERLACE_LINEAR ) ) { vlc_mutex_unlock( &p_vout->p_sys->filter_lock ); return VLC_SUCCESS; } break; } break; default: break; } /* We need to kill the old vout */ if( p_vout->p_sys->p_vout ) { DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents ); vout_CloseAndRelease( p_vout->p_sys->p_vout ); } /* Try to open a new video output */ p_vout->p_sys->p_vout = SpawnRealVout( p_vout ); if( p_vout->p_sys->p_vout == NULL ) { /* Everything failed */ msg_Err( p_vout, "cannot open vout, aborting" ); vlc_mutex_unlock( &p_vout->p_sys->filter_lock ); return VLC_EGENERIC; } ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents ); vlc_mutex_unlock( &p_vout->p_sys->filter_lock ); return VLC_SUCCESS;}/***************************************************************************** * SendEventsToChild: forward events to the child/children vout *****************************************************************************/static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ){ VLC_UNUSED(p_data); VLC_UNUSED(oldval); vout_thread_t *p_vout = (vout_thread_t *)p_this; var_Set( p_vout->p_sys->p_vout, psz_var, newval ); return VLC_SUCCESS;}/***************************************************************************** * video filter2 functions *****************************************************************************/static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic ){ vout_thread_t *p_vout = (vout_thread_t *)p_filter->p_sys; picture_t *p_pic_dst; /* Request output picture */ p_pic_dst = filter_NewPicture( p_filter ); if( p_pic_dst == NULL ) return p_pic; switch( p_vout->p_sys->i_mode ) { case DEINTERLACE_DISCARD:#if 0 RenderDiscard( p_vout, p_pic_dst, p_pic, 0 );#endif msg_Err( p_vout, "discarding lines is not supported yet" ); picture_Release( p_pic_dst ); return p_pic; break; case DEINTERLACE_BOB:#if 0 RenderBob( p_vout, p
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -