@ -1,4 +1,5 @@
/*
* Copyright ( c ) 2017 Thomas Mundt < tmundt75 @ gmail . com >
* Copyright ( c ) 2011 Stefano Sabatini
* Copyright ( c ) 2010 Baptiste Coudurier
* Copyright ( c ) 2003 Michael Zucchi < notzed @ ximian . com >
@ -34,8 +35,6 @@
# define OFFSET(x) offsetof(TInterlaceContext, x)
# define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
# define TINTERLACE_FLAG_VLPF 01
# define TINTERLACE_FLAG_EXACT_TB 2
static const AVOption tinterlace_options [ ] = {
{ " mode " , " select interlace mode " , OFFSET ( mode ) , AV_OPT_TYPE_INT , { . i64 = MODE_MERGE } , 0 , MODE_NB - 1 , FLAGS , " mode " } ,
@ -51,6 +50,8 @@ static const AVOption tinterlace_options[] = {
{ " flags " , " set flags " , OFFSET ( flags ) , AV_OPT_TYPE_FLAGS , { . i64 = 0 } , 0 , INT_MAX , 0 , " flags " } ,
{ " low_pass_filter " , " enable vertical low-pass filter " , 0 , AV_OPT_TYPE_CONST , { . i64 = TINTERLACE_FLAG_VLPF } , INT_MIN , INT_MAX , FLAGS , " flags " } ,
{ " vlpf " , " enable vertical low-pass filter " , 0 , AV_OPT_TYPE_CONST , { . i64 = TINTERLACE_FLAG_VLPF } , INT_MIN , INT_MAX , FLAGS , " flags " } ,
{ " complex_filter " , " enable complex vertical low-pass filter " , 0 , AV_OPT_TYPE_CONST , { . i64 = TINTERLACE_FLAG_CVLPF } , INT_MIN , INT_MAX , FLAGS , " flags " } ,
{ " cvlpf " , " enable complex vertical low-pass filter " , 0 , AV_OPT_TYPE_CONST , { . i64 = TINTERLACE_FLAG_CVLPF } , INT_MIN , INT_MAX , FLAGS , " flags " } ,
{ " exact_tb " , " force a timebase which can represent timestamps exactly " , 0 , AV_OPT_TYPE_CONST , { . i64 = TINTERLACE_FLAG_EXACT_TB } , INT_MIN , INT_MAX , FLAGS , " flags " } ,
{ NULL }
@ -102,6 +103,24 @@ static void lowpass_line_c(uint8_t *dstp, ptrdiff_t width, const uint8_t *srcp,
}
}
static void lowpass_line_complex_c ( uint8_t * dstp , ptrdiff_t width , const uint8_t * srcp ,
ptrdiff_t mref , ptrdiff_t pref )
{
const uint8_t * srcp_above = srcp + mref ;
const uint8_t * srcp_below = srcp + pref ;
const uint8_t * srcp_above2 = srcp + mref * 2 ;
const uint8_t * srcp_below2 = srcp + pref * 2 ;
int i ;
for ( i = 0 ; i < width ; i + + ) {
// this calculation is an integer representation of
// '0.75 * current + 0.25 * above + 0.25 * below - 0.125 * above2 - 0.125 * below2'
// '4 +' is for rounding.
dstp [ i ] = av_clip_uint8 ( ( 4 + ( srcp [ i ] < < 2 )
+ ( ( srcp [ i ] + srcp_above [ i ] + srcp_below [ i ] ) < < 1 )
- srcp_above2 [ i ] - srcp_below2 [ i ] ) > > 3 ) ;
}
}
static av_cold void uninit ( AVFilterContext * ctx )
{
TInterlaceContext * tinterlace = ctx - > priv ;
@ -144,12 +163,14 @@ static int config_out_props(AVFilterLink *outlink)
tinterlace - > black_linesize [ i ] * h ) ;
}
}
if ( ( tinterlace - > flags & TINTERLACE_FLAG_VLPF )
if ( ( tinterlace - > flags & TINTERLACE_FLAG_VLPF
| | tinterlace - > flags & TINTERLACE_FLAG_CVLPF )
& & ! ( tinterlace - > mode = = MODE_INTERLEAVE_TOP
| | tinterlace - > mode = = MODE_INTERLEAVE_BOTTOM ) ) {
av_log ( ctx , AV_LOG_WARNING , " low_pass_filter flag ignored with mode %d \n " ,
av_log ( ctx , AV_LOG_WARNING , " low_pass_filter flags ignored with mode %d \n " ,
tinterlace - > mode ) ;
tinterlace - > flags & = ~ TINTERLACE_FLAG_VLPF ;
tinterlace - > flags & = ~ TINTERLACE_FLAG_CVLPF ;
}
tinterlace - > preout_time_base = inlink - > time_base ;
if ( tinterlace - > mode = = MODE_INTERLACEX2 ) {
@ -172,14 +193,19 @@ static int config_out_props(AVFilterLink *outlink)
( tinterlace - > flags & TINTERLACE_FLAG_EXACT_TB ) )
outlink - > time_base = tinterlace - > preout_time_base ;
if ( tinterlace - > flags & TINTERLACE_FLAG_VLPF ) {
if ( tinterlace - > flags & TINTERLACE_FLAG_CVLPF ) {
tinterlace - > lowpass_line = lowpass_line_complex_c ;
if ( ARCH_X86 )
ff_tinterlace_init_x86 ( tinterlace ) ;
} else if ( tinterlace - > flags & TINTERLACE_FLAG_VLPF ) {
tinterlace - > lowpass_line = lowpass_line_c ;
if ( ARCH_X86 )
ff_tinterlace_init_x86 ( tinterlace ) ;
}
av_log ( ctx , AV_LOG_VERBOSE , " mode:%d filter:%s h:%d -> h:%d \n " ,
tinterlace - > mode , ( tinterlace - > flags & TINTERLACE_FLAG_VLPF ) ? " on " : " off " ,
av_log ( ctx , AV_LOG_VERBOSE , " mode:%d filter:%s h:%d -> h:%d \n " , tinterlace - > mode ,
( tinterlace - > flags & TINTERLACE_FLAG_CVLPF ) ? " complex " :
( tinterlace - > flags & TINTERLACE_FLAG_VLPF ) ? " linear " : " off " ,
inlink - > h , outlink - > h ) ;
return 0 ;
@ -223,10 +249,23 @@ void copy_picture_field(TInterlaceContext *tinterlace,
srcp + = src_linesize [ plane ] ;
if ( interleave & & dst_field = = FIELD_LOWER )
dstp + = dst_linesize [ plane ] ;
if ( flags & TINTERLACE_FLAG_VLPF ) {
// Low-pass filtering is required when creating an interlaced destination from
// a progressive source which contains high-frequency vertical detail.
// Filtering will reduce interlace 'twitter' and Moire patterning.
// Low-pass filtering is required when creating an interlaced destination from
// a progressive source which contains high-frequency vertical detail.
// Filtering will reduce interlace 'twitter' and Moire patterning.
if ( flags & TINTERLACE_FLAG_CVLPF ) {
int srcp_linesize = src_linesize [ plane ] * k ;
int dstp_linesize = dst_linesize [ plane ] * ( interleave ? 2 : 1 ) ;
for ( h = lines ; h > 0 ; h - - ) {
ptrdiff_t pref = src_linesize [ plane ] ;
ptrdiff_t mref = - pref ;
if ( h > = ( lines - 1 ) ) mref = 0 ;
else if ( h < = 2 ) pref = 0 ;
tinterlace - > lowpass_line ( dstp , cols , srcp , mref , pref ) ;
dstp + = dstp_linesize ;
srcp + = srcp_linesize ;
}
} else if ( flags & TINTERLACE_FLAG_VLPF ) {
int srcp_linesize = src_linesize [ plane ] * k ;
int dstp_linesize = dst_linesize [ plane ] * ( interleave ? 2 : 1 ) ;
for ( h = lines ; h > 0 ; h - - ) {