@ -31,6 +31,7 @@ typedef struct ChanDelay {
int64_t delay ;
size_t delay_index ;
size_t index ;
unsigned int samples_size ;
uint8_t * samples ;
} ChanDelay ;
@ -48,13 +49,14 @@ typedef struct AudioDelayContext {
void ( * delay_channel ) ( ChanDelay * d , int nb_samples ,
const uint8_t * src , uint8_t * dst ) ;
int ( * resize_channel_samples ) ( ChanDelay * d , int64_t new_delay ) ;
} AudioDelayContext ;
# define OFFSET(x) offsetof(AudioDelayContext, x)
# define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
static const AVOption adelay_options [ ] = {
{ " delays " , " set list of delays for each channel " , OFFSET ( delays ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , A } ,
{ " delays " , " set list of delays for each channel " , OFFSET ( delays ) , AV_OPT_TYPE_STRING , { . str = NULL } , 0 , 0 , A | AV_OPT_FLAG_RUNTIME_PARAM } ,
{ " all " , " use last available delay for remained channels " , OFFSET ( all ) , AV_OPT_TYPE_BOOL , { . i64 = 0 } , 0 , 1 , A } ,
{ NULL }
} ;
@ -96,11 +98,93 @@ DELAY(s32, int32_t, 0)
DELAY ( flt , float , 0 )
DELAY ( dbl , double , 0 )
# define CHANGE_DELAY(name, type, fill) \
static int resize_samples_ # # name # # p ( ChanDelay * d , int64_t new_delay ) \
{ \
type * samples ; \
\
if ( new_delay = = d - > delay ) { \
return 0 ; \
} \
\
if ( new_delay = = 0 ) { \
av_freep ( & d - > samples ) ; \
d - > samples_size = 0 ; \
d - > delay = 0 ; \
d - > index = 0 ; \
d - > delay_index = 0 ; \
return 0 ; \
} \
\
samples = ( type * ) av_fast_realloc ( d - > samples , & d - > samples_size , new_delay * sizeof ( type ) ) ; \
if ( ! samples ) { \
return AVERROR ( ENOMEM ) ; \
} \
\
if ( new_delay < d - > delay ) { \
if ( d - > index > new_delay ) { \
d - > index - = new_delay ; \
memmove ( samples , & samples [ new_delay ] , d - > index * sizeof ( type ) ) ; \
d - > delay_index = new_delay ; \
} else if ( d - > delay_index > d - > index ) { \
memmove ( & samples [ d - > index ] , & samples [ d - > index + ( d - > delay - new_delay ) ] , \
( new_delay - d - > index ) * sizeof ( type ) ) ; \
d - > delay_index - = d - > delay - new_delay ; \
} \
} else { \
size_t block_size ; \
if ( d - > delay_index > = d - > delay ) { \
block_size = ( d - > delay - d - > index ) * sizeof ( type ) ; \
memmove ( & samples [ d - > index + ( new_delay - d - > delay ) ] , & samples [ d - > index ] , block_size ) ; \
d - > delay_index = new_delay ; \
} else { \
d - > delay_index + = new_delay - d - > delay ; \
} \
block_size = ( new_delay - d - > delay ) * sizeof ( type ) ; \
memset ( & samples [ d - > index ] , fill , block_size ) ; \
} \
d - > delay = new_delay ; \
d - > samples = ( void * ) samples ; \
return 0 ; \
}
CHANGE_DELAY ( u8 , uint8_t , 0x80 )
CHANGE_DELAY ( s16 , int16_t , 0 )
CHANGE_DELAY ( s32 , int32_t , 0 )
CHANGE_DELAY ( flt , float , 0 )
CHANGE_DELAY ( dbl , double , 0 )
static int parse_delays ( char * p , char * * saveptr , int64_t * result , AVFilterContext * ctx , int sample_rate ) {
float delay , div ;
int ret ;
char * arg ;
char type = 0 ;
if ( ! ( arg = av_strtok ( p , " | " , saveptr ) ) )
return 1 ;
ret = av_sscanf ( arg , " % " SCNd64 " %c " , result , & type ) ;
if ( ret ! = 2 | | type ! = ' S ' ) {
div = type = = ' s ' ? 1.0 : 1000.0 ;
if ( av_sscanf ( arg , " %f " , & delay ) ! = 1 ) {
av_log ( ctx , AV_LOG_ERROR , " Invalid syntax for delay. \n " ) ;
return AVERROR ( EINVAL ) ;
}
* result = delay * sample_rate / div ;
}
if ( * result < 0 ) {
av_log ( ctx , AV_LOG_ERROR , " Delay must be non negative number. \n " ) ;
return AVERROR ( EINVAL ) ;
}
return 0 ;
}
static int config_input ( AVFilterLink * inlink )
{
AVFilterContext * ctx = inlink - > dst ;
AudioDelayContext * s = ctx - > priv ;
char * p , * arg , * saveptr = NULL ;
char * p , * saveptr = NULL ;
int i ;
s - > chandelay = av_calloc ( inlink - > channels , sizeof ( * s - > chandelay ) ) ;
@ -112,29 +196,14 @@ static int config_input(AVFilterLink *inlink)
p = s - > delays ;
for ( i = 0 ; i < s - > nb_delays ; i + + ) {
ChanDelay * d = & s - > chandelay [ i ] ;
float delay , div ;
char type = 0 ;
int ret ;
if ( ! ( arg = av_strtok ( p , " | " , & saveptr ) ) )
ret = parse_delays ( p , & saveptr , & d - > delay , ctx , inlink - > sample_rate ) ;
if ( ret = = 1 )
break ;
else if ( ret < 0 )
return ret ;
p = NULL ;
ret = av_sscanf ( arg , " % " SCNd64 " %c " , & d - > delay , & type ) ;
if ( ret ! = 2 | | type ! = ' S ' ) {
div = type = = ' s ' ? 1.0 : 1000.0 ;
if ( av_sscanf ( arg , " %f " , & delay ) ! = 1 ) {
av_log ( ctx , AV_LOG_ERROR , " Invalid syntax for delay. \n " ) ;
return AVERROR ( EINVAL ) ;
}
d - > delay = delay * inlink - > sample_rate / div ;
}
if ( d - > delay < 0 ) {
av_log ( ctx , AV_LOG_ERROR , " Delay must be non negative number. \n " ) ;
return AVERROR ( EINVAL ) ;
}
}
if ( s - > all & & i ) {
@ -171,21 +240,81 @@ static int config_input(AVFilterLink *inlink)
d - > samples = av_malloc_array ( d - > delay , s - > block_align ) ;
if ( ! d - > samples )
return AVERROR ( ENOMEM ) ;
d - > samples_size = d - > delay * s - > block_align ;
s - > max_delay = FFMAX ( s - > max_delay , d - > delay ) ;
}
switch ( inlink - > format ) {
case AV_SAMPLE_FMT_U8P : s - > delay_channel = delay_channel_u8p ; break ;
case AV_SAMPLE_FMT_S16P : s - > delay_channel = delay_channel_s16p ; break ;
case AV_SAMPLE_FMT_S32P : s - > delay_channel = delay_channel_s32p ; break ;
case AV_SAMPLE_FMT_FLTP : s - > delay_channel = delay_channel_fltp ; break ;
case AV_SAMPLE_FMT_DBLP : s - > delay_channel = delay_channel_dblp ; break ;
case AV_SAMPLE_FMT_U8P : s - > delay_channel = delay_channel_u8p ;
s - > resize_channel_samples = resize_samples_u8p ; break ;
case AV_SAMPLE_FMT_S16P : s - > delay_channel = delay_channel_s16p ;
s - > resize_channel_samples = resize_samples_s16p ; break ;
case AV_SAMPLE_FMT_S32P : s - > delay_channel = delay_channel_s32p ;
s - > resize_channel_samples = resize_samples_s32p ; break ;
case AV_SAMPLE_FMT_FLTP : s - > delay_channel = delay_channel_fltp ;
s - > resize_channel_samples = resize_samples_fltp ; break ;
case AV_SAMPLE_FMT_DBLP : s - > delay_channel = delay_channel_dblp ;
s - > resize_channel_samples = resize_samples_dblp ; break ;
}
return 0 ;
}
static int process_command ( AVFilterContext * ctx , const char * cmd , const char * args ,
char * res , int res_len , int flags )
{
int ret = AVERROR ( ENOSYS ) ;
AVFilterLink * inlink = ctx - > inputs [ 0 ] ;
AudioDelayContext * s = ctx - > priv ;
if ( ! strcmp ( cmd , " delays " ) ) {
int64_t delay ;
char * p , * saveptr = NULL ;
int64_t all_delay = - 1 ;
int64_t max_delay = 0 ;
char * args_cpy = av_strdup ( args ) ;
if ( args_cpy = = NULL ) {
return AVERROR ( ENOMEM ) ;
}
ret = 0 ;
p = args_cpy ;
if ( ! strncmp ( args , " all: " , 4 ) ) {
p = & args_cpy [ 4 ] ;
ret = parse_delays ( p , & saveptr , & all_delay , ctx , inlink - > sample_rate ) ;
if ( ret = = 1 )
ret = AVERROR ( EINVAL ) ;
else if ( ret = = 0 )
delay = all_delay ;
}
if ( ! ret ) {
for ( int i = 0 ; i < s - > nb_delays ; i + + ) {
ChanDelay * d = & s - > chandelay [ i ] ;
if ( all_delay < 0 ) {
ret = parse_delays ( p , & saveptr , & delay , ctx , inlink - > sample_rate ) ;
if ( ret ! = 0 ) {
ret = 0 ;
break ;
}
p = NULL ;
}
ret = s - > resize_channel_samples ( d , delay ) ;
if ( ret )
break ;
max_delay = FFMAX ( max_delay , d - > delay ) ;
}
s - > max_delay = FFMAX ( s - > max_delay , max_delay ) ;
}
av_freep ( & args_cpy ) ;
}
return ret ;
}
static int filter_frame ( AVFilterLink * inlink , AVFrame * frame )
{
AVFilterContext * ctx = inlink - > dst ;
@ -330,4 +459,5 @@ const AVFilter ff_af_adelay = {
FILTER_SAMPLEFMTS ( AV_SAMPLE_FMT_U8P , AV_SAMPLE_FMT_S16P , AV_SAMPLE_FMT_S32P ,
AV_SAMPLE_FMT_FLTP , AV_SAMPLE_FMT_DBLP ) ,
. flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL ,
. process_command = process_command ,
} ;