@ -38,6 +38,7 @@ enum DisplayMode { COMBINED, SEPARATE, NB_MODES };
enum DisplayScale { LINEAR , SQRT , CBRT , LOG , NB_SCALES } ;
enum ColorMode { CHANNEL , INTENSITY , NB_CLMODES } ;
enum WindowFunc { WFUNC_NONE , WFUNC_HANN , WFUNC_HAMMING , WFUNC_BLACKMAN , NB_WFUNC } ;
enum SlideMode { REPLACE , SCROLL , FULLFRAME , NB_SLIDES } ;
typedef struct {
const AVClass * class ;
@ -55,8 +56,6 @@ typedef struct {
RDFTContext * rdft ; ///< Real Discrete Fourier Transform context
int rdft_bits ; ///< number of bits (RDFT window size = 1<<rdft_bits)
FFTSample * * rdft_data ; ///< bins holder for each (displayed) channels
int filled ; ///< number of samples (per channel) filled in current rdft_buffer
int consumed ; ///< number of samples (per channel) consumed from the input frame
float * window_func_lut ; ///< Window function LUT
enum WindowFunc win_func ;
float * combine_buffer ; ///< color combining buffer (3 * h items)
@ -68,7 +67,10 @@ typedef struct {
static const AVOption showspectrum_options [ ] = {
{ " size " , " set video size " , OFFSET ( w ) , AV_OPT_TYPE_IMAGE_SIZE , { . str = " 640x512 " } , 0 , 0 , FLAGS } ,
{ " s " , " set video size " , OFFSET ( w ) , AV_OPT_TYPE_IMAGE_SIZE , { . str = " 640x512 " } , 0 , 0 , FLAGS } ,
{ " slide " , " set sliding mode " , OFFSET ( sliding ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , 1 , FLAGS } ,
{ " slide " , " set sliding mode " , OFFSET ( sliding ) , AV_OPT_TYPE_INT , { . i64 = 0 } , 0 , NB_SLIDES , FLAGS , " slide " } ,
{ " replace " , " replace old colums with new " , 0 , AV_OPT_TYPE_CONST , { . i64 = REPLACE } , 0 , 0 , FLAGS , " slide " } ,
{ " scroll " , " scroll from right to left " , 0 , AV_OPT_TYPE_CONST , { . i64 = SCROLL } , 0 , 0 , FLAGS , " slide " } ,
{ " fullframe " , " return full frames " , 0 , AV_OPT_TYPE_CONST , { . i64 = FULLFRAME } , 0 , 0 , FLAGS , " slide " } ,
{ " mode " , " set channel display mode " , OFFSET ( mode ) , AV_OPT_TYPE_INT , { . i64 = COMBINED } , COMBINED , NB_MODES - 1 , FLAGS , " mode " } ,
{ " combined " , " combined mode " , 0 , AV_OPT_TYPE_CONST , { . i64 = COMBINED } , 0 , 0 , FLAGS , " mode " } ,
{ " separate " , " separate mode " , 0 , AV_OPT_TYPE_CONST , { . i64 = SEPARATE } , 0 , 0 , FLAGS , " mode " } ,
@ -175,6 +177,11 @@ static int config_output(AVFilterLink *outlink)
av_rdft_end ( s - > rdft ) ;
s - > rdft = av_rdft_init ( rdft_bits , DFT_R2C ) ;
if ( ! s - > rdft ) {
av_log ( ctx , AV_LOG_ERROR , " Unable to create RDFT context. "
" The window size might be too high. \n " ) ;
return AVERROR ( EINVAL ) ;
}
s - > rdft_bits = rdft_bits ;
/* RDFT buffers: x2 for each (display) channel buffer.
@ -199,7 +206,6 @@ static int config_output(AVFilterLink *outlink)
if ( ! s - > rdft_data [ i ] )
return AVERROR ( ENOMEM ) ;
}
s - > filled = 0 ;
/* pre-calc windowing function */
s - > window_func_lut =
@ -246,6 +252,13 @@ static int config_output(AVFilterLink *outlink)
if ( s - > xpos > = outlink - > w )
s - > xpos = 0 ;
outlink - > frame_rate = av_make_q ( inlink - > sample_rate , win_size ) ;
if ( s - > sliding = = FULLFRAME )
outlink - > frame_rate . den * = outlink - > w ;
inlink - > min_samples = inlink - > max_samples = inlink - > partial_buf_size =
win_size ;
s - > combine_buffer =
av_realloc_f ( s - > combine_buffer , outlink - > h * 3 ,
sizeof ( * s - > combine_buffer ) ) ;
@ -255,36 +268,33 @@ static int config_output(AVFilterLink *outlink)
return 0 ;
}
inline static int push_frame ( AVFilterLink * outlink )
{
ShowSpectrumContext * s = outlink - > src - > priv ;
s - > xpos + + ;
if ( s - > xpos > = outlink - > w )
s - > xpos = 0 ;
s - > filled = 0 ;
s - > req_fullfilled = 1 ;
return ff_filter_frame ( outlink , av_frame_clone ( s - > outpicref ) ) ;
}
static int request_frame ( AVFilterLink * outlink )
{
ShowSpectrumContext * s = outlink - > src - > priv ;
AVFilterLink * inlink = outlink - > src - > inputs [ 0 ] ;
unsigned i ;
int ret ;
s - > req_fullfilled = 0 ;
do {
ret = ff_request_frame ( inlink ) ;
if ( ret = = AVERROR_EOF & & s - > sliding = = FULLFRAME & & s - > xpos > 0 & &
s - > outpicref ) {
for ( i = 0 ; i < outlink - > h ; i + + ) {
memset ( s - > outpicref - > data [ 0 ] + i * s - > outpicref - > linesize [ 0 ] + s - > xpos , 0 , outlink - > w - s - > xpos ) ;
memset ( s - > outpicref - > data [ 1 ] + i * s - > outpicref - > linesize [ 1 ] + s - > xpos , 128 , outlink - > w - s - > xpos ) ;
memset ( s - > outpicref - > data [ 2 ] + i * s - > outpicref - > linesize [ 2 ] + s - > xpos , 128 , outlink - > w - s - > xpos ) ;
}
ret = ff_filter_frame ( outlink , s - > outpicref ) ;
s - > outpicref = NULL ;
s - > req_fullfilled = 1 ;
}
} while ( ! s - > req_fullfilled & & ret > = 0 ) ;
if ( ret = = AVERROR_EOF & & s - > outpicref )
push_frame ( outlink ) ;
return ret ;
}
static int plot_spectrum_column ( AVFilterLink * inlink , AVFrame * insamples , int nb_samples )
static int plot_spectrum_column ( AVFilterLink * inlink , AVFrame * insamples )
{
int ret ;
AVFilterContext * ctx = inlink - > dst ;
@ -297,26 +307,21 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb
const int nb_freq = 1 < < ( s - > rdft_bits - 1 ) ;
const int win_size = nb_freq < < 1 ;
const double w = 1. / ( sqrt ( nb_freq ) * 32768. ) ;
int h = s - > channel_height ;
int ch , plane , n , y ;
const int start = s - > filled ;
const int add_samples = FFMIN ( win_size - start , nb_samples ) ;
av_assert0 ( insamples - > nb_samples = = win_size ) ;
/* fill RDFT input with the number of samples available */
for ( ch = 0 ; ch < s - > nb_display_channels ; ch + + ) {
const int16_t * p = ( int16_t * ) insamples - > extended_data [ ch ] ;
p + = s - > consumed ;
for ( n = 0 ; n < add_samples ; n + + )
s - > rdft_data [ ch ] [ start + n ] = p [ n ] * s - > window_func_lut [ start + n ] ;
for ( n = 0 ; n < win_size ; n + + )
s - > rdft_data [ ch ] [ n ] = p [ n ] * s - > window_func_lut [ n ] ;
}
s - > filled + = add_samples ;
/* complete RDFT window size? */
if ( s - > filled = = win_size ) {
/* channel height */
int h = s - > channel_height ;
/* TODO reindent */
/* run RDFT on each samples set */
for ( ch = 0 ; ch < s - > nb_display_channels ; ch + + )
@ -445,7 +450,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb
}
/* copy to output */
if ( s - > sliding ) {
if ( s - > sliding = = SCROLL ) {
for ( plane = 0 ; plane < 3 ; plane + + ) {
for ( y = 0 ; y < outlink - > h ; y + + ) {
uint8_t * p = outpicref - > data [ plane ] +
@ -465,32 +470,32 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples, int nb
}
}
outpicref - > pts = insamples - > pts +
av_rescale_q ( s - > consumed ,
( AVRational ) { 1 , inlink - > sample_rate } ,
outlink - > time_base ) ;
ret = push_frame ( outlink ) ;
if ( ret < 0 )
return ret ;
}
if ( s - > sliding ! = FULLFRAME | | s - > xpos = = 0 )
outpicref - > pts = insamples - > pts ;
s - > xpos + + ;
if ( s - > xpos > = outlink - > w )
s - > xpos = 0 ;
if ( s - > sliding ! = FULLFRAME | | s - > xpos = = 0 ) {
s - > req_fullfilled = 1 ;
ret = ff_filter_frame ( outlink , av_frame_clone ( s - > outpicref ) ) ;
if ( ret < 0 )
return ret ;
}
return add_samples ;
return win_size ;
}
static int filter_frame ( AVFilterLink * inlink , AVFrame * insamples )
{
AVFilterContext * ctx = inlink - > dst ;
ShowSpectrumContext * s = ctx - > priv ;
int ret = 0 , left_samples = insamples - > nb_samples ;
unsigned win_size = 1 < < s - > rdft_bits ;
int ret = 0 ;
s - > consumed = 0 ;
while ( left_samples ) {
int ret = plot_spectrum_column ( inlink , insamples , left_samples ) ;
if ( ret < 0 )
break ;
s - > consumed + = ret ;
left_samples - = ret ;
}
av_assert0 ( insamples - > nb_samples < = win_size ) ;
if ( insamples - > nb_samples = = win_size )
ret = plot_spectrum_column ( inlink , insamples ) ;
av_frame_free ( & insamples ) ;
return ret ;