diff --git a/configure b/configure index 3f75f07d25..87416d407c 100755 --- a/configure +++ b/configure @@ -3661,10 +3661,6 @@ showfreqs_filter_deps="avcodec" showfreqs_filter_select="fft" showspatial_filter_deps="avcodec" showspatial_filter_select="fft" -showspectrum_filter_deps="avcodec" -showspectrum_filter_select="fft" -showspectrumpic_filter_deps="avcodec" -showspectrumpic_filter_select="fft" signature_filter_deps="gpl avcodec avformat" sinc_filter_deps="avcodec" sinc_filter_select="rdft" @@ -7291,7 +7287,6 @@ enabled scale2ref_filter && prepend avfilter_deps "swscale" enabled sofalizer_filter && prepend avfilter_deps "avcodec" enabled showcqt_filter && prepend avfilter_deps "avformat avcodec swscale" enabled showfreqs_filter && prepend avfilter_deps "avcodec" -enabled showspectrum_filter && prepend avfilter_deps "avcodec" enabled signature_filter && prepend avfilter_deps "avcodec avformat" enabled smartblur_filter && prepend avfilter_deps "swscale" enabled spectrumsynth_filter && prepend avfilter_deps "avcodec" diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 4544bef0bd..cec5915f90 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -28,7 +28,7 @@ #include -#include "libavcodec/avfft.h" +#include "libavutil/tx.h" #include "libavutil/audio_fifo.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -72,11 +72,14 @@ typedef struct ShowSpectrumContext { int start, stop; ///< zoom mode int data; int xpos; ///< x position (current column) - FFTContext **fft; ///< Fast Fourier Transform context - FFTContext **ifft; ///< Inverse Fast Fourier Transform context - int fft_bits; ///< number of bits (FFT window size = 1<combine_buffer); if (s->fft) { for (i = 0; i < s->nb_display_channels; i++) - av_fft_end(s->fft[i]); + av_tx_uninit(&s->fft[i]); } av_freep(&s->fft); if (s->ifft) { for (i = 0; i < s->nb_display_channels; i++) - av_fft_end(s->ifft[i]); + av_tx_uninit(&s->ifft[i]); } av_freep(&s->ifft); if (s->fft_data) { @@ -318,6 +321,11 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->fft_data[i]); } av_freep(&s->fft_data); + if (s->fft_in) { + for (i = 0; i < s->nb_display_channels; i++) + av_freep(&s->fft_in[i]); + } + av_freep(&s->fft_in); if (s->fft_scratch) { for (i = 0; i < s->nb_display_channels; i++) av_freep(&s->fft_scratch[i]); @@ -386,19 +394,20 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo /* fill FFT input with the number of samples available */ const float *p = (float *)fin->extended_data[ch]; - for (n = 0; n < s->win_size; n++) { - s->fft_data[ch][n].re = p[n] * window_func_lut[n]; - s->fft_data[ch][n].im = 0; - } - if (s->stop) { float theta, phi, psi, a, b, S, c; - FFTComplex *g = s->fft_data[ch]; - FFTComplex *h = s->fft_scratch[ch]; + AVComplexFloat *f = s->fft_in[ch]; + AVComplexFloat *g = s->fft_data[ch]; + AVComplexFloat *h = s->fft_scratch[ch]; int L = s->buf_size; int N = s->win_size; int M = s->win_size / 2; + for (n = 0; n < s->win_size; n++) { + s->fft_data[ch][n].re = p[n] * window_func_lut[n]; + s->fft_data[ch][n].im = 0; + } + phi = 2.f * M_PI * (s->stop - s->start) / (float)inlink->sample_rate / (M - 1); theta = 2.f * M_PI * s->start / (float)inlink->sample_rate; @@ -417,11 +426,6 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo h[n].im = sinf((L - n) * (L - n) / 2.f * phi); } - for (int n = 0; n < N; n++) { - g[n].re = s->fft_data[ch][n].re; - g[n].im = s->fft_data[ch][n].im; - } - for (int n = N; n < L; n++) { g[n].re = 0.f; g[n].im = 0.f; @@ -437,11 +441,11 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo g[n].im = b; } - av_fft_permute(s->fft[ch], h); - av_fft_calc(s->fft[ch], h); + memcpy(f, h, s->buf_size * sizeof(*f)); + s->tx_fn(s->fft[ch], h, f, sizeof(float)); - av_fft_permute(s->fft[ch], g); - av_fft_calc(s->fft[ch], g); + memcpy(f, g, s->buf_size * sizeof(*f)); + s->tx_fn(s->fft[ch], g, f, sizeof(float)); for (int n = 0; n < L; n++) { c = g[n].re; @@ -453,8 +457,8 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo g[n].im = b / L; } - av_fft_permute(s->ifft[ch], g); - av_fft_calc(s->ifft[ch], g); + memcpy(f, g, s->buf_size * sizeof(*f)); + s->itx_fn(s->ifft[ch], g, f, sizeof(float)); for (int k = 0; k < M; k++) { psi = k * k / 2.f * phi; @@ -466,9 +470,13 @@ static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jo s->fft_data[ch][k].im = b; } } else { + for (n = 0; n < s->win_size; n++) { + s->fft_in[ch][n].re = p[n] * window_func_lut[n]; + s->fft_in[ch][n].im = 0; + } + /* run FFT on each samples set */ - av_fft_permute(s->fft[ch], s->fft_data[ch]); - av_fft_calc(s->fft[ch], s->fft_data[ch]); + s->tx_fn(s->fft[ch], s->fft_data[ch], s->fft_in[ch], sizeof(float)); } return 0; @@ -986,7 +994,7 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowSpectrumContext *s = ctx->priv; - int i, fft_bits, h, w; + int i, fft_size, h, w, ret; float overlap; switch (s->fscale) { @@ -996,7 +1004,7 @@ static int config_output(AVFilterLink *outlink) } s->stop = FFMIN(s->stop, inlink->sample_rate / 2); - if (s->stop && s->stop <= s->start) { + if ((s->stop || s->start) && s->stop <= s->start) { av_log(ctx, AV_LOG_ERROR, "Stop frequency should be greater than start.\n"); return AVERROR(EINVAL); } @@ -1022,14 +1030,14 @@ static int config_output(AVFilterLink *outlink) if (s->orientation == VERTICAL) { /* FFT window size (precision) according to the requested output frame height */ - for (fft_bits = 1; 1 << fft_bits < 2 * h; fft_bits++); + fft_size = h * 2; } else { /* FFT window size (precision) according to the requested output frame width */ - for (fft_bits = 1; 1 << fft_bits < 2 * w; fft_bits++); + fft_size = w * 2; } - s->win_size = 1 << fft_bits; - s->buf_size = s->win_size << !!s->stop; + s->win_size = fft_size; + s->buf_size = FFALIGN(s->win_size << (!!s->stop), 512); if (!s->fft) { s->fft = av_calloc(inlink->channels, sizeof(*s->fft)); @@ -1046,39 +1054,42 @@ static int config_output(AVFilterLink *outlink) } /* (re-)configuration if the video output changed (or first init) */ - if (fft_bits != s->fft_bits) { + if (fft_size != s->fft_size) { AVFrame *outpicref; - s->fft_bits = fft_bits; + s->fft_size = fft_size; /* FFT buffers: x2 for each (display) channel buffer. * Note: we use free and malloc instead of a realloc-like function to * make sure the buffer is aligned in memory for the FFT functions. */ for (i = 0; i < s->nb_display_channels; i++) { if (s->stop) { - av_fft_end(s->ifft[i]); + av_tx_uninit(&s->ifft[i]); av_freep(&s->fft_scratch[i]); } - av_fft_end(s->fft[i]); + av_tx_uninit(&s->fft[i]); + av_freep(&s->fft_in[i]); av_freep(&s->fft_data[i]); } av_freep(&s->fft_data); s->nb_display_channels = inlink->channels; for (i = 0; i < s->nb_display_channels; i++) { - s->fft[i] = av_fft_init(fft_bits + !!s->stop, 0); + float scale; + + ret = av_tx_init(&s->fft[i], &s->tx_fn, AV_TX_FLOAT_FFT, 0, fft_size << (!!s->stop), &scale, 0); if (s->stop) { - s->ifft[i] = av_fft_init(fft_bits + !!s->stop, 1); - if (!s->ifft[i]) { + ret = av_tx_init(&s->ifft[i], &s->itx_fn, AV_TX_FLOAT_FFT, 1, fft_size << (!!s->stop), &scale, 0); + if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Unable to create Inverse FFT context. " "The window size might be too high.\n"); - return AVERROR(EINVAL); + return ret; } } - if (!s->fft[i]) { + if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. " "The window size might be too high.\n"); - return AVERROR(EINVAL); + return ret; } } @@ -1110,6 +1121,9 @@ static int config_output(AVFilterLink *outlink) return AVERROR(ENOMEM); } + s->fft_in = av_calloc(s->nb_display_channels, sizeof(*s->fft_in)); + if (!s->fft_in) + return AVERROR(ENOMEM); s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data)); if (!s->fft_data) return AVERROR(ENOMEM); @@ -1117,6 +1131,10 @@ static int config_output(AVFilterLink *outlink) if (!s->fft_scratch) return AVERROR(ENOMEM); for (i = 0; i < s->nb_display_channels; i++) { + s->fft_in[i] = av_calloc(s->buf_size, sizeof(**s->fft_in)); + if (!s->fft_in[i]) + return AVERROR(ENOMEM); + s->fft_data[i] = av_calloc(s->buf_size, sizeof(**s->fft_data)); if (!s->fft_data[i]) return AVERROR(ENOMEM);