[FFmpeg-cvslog] avfilter/avf_showspectrum: switch to TX FFT from avutil

Paul B Mahol git at videolan.org
Sat Jul 24 18:02:05 EEST 2021


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sat Jul 24 14:22:38 2021 +0200| [014ace8f98cc4a1a88e7a6d5890cef628eb9e8b0] | committer: Paul B Mahol

avfilter/avf_showspectrum: switch to TX FFT from avutil

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=014ace8f98cc4a1a88e7a6d5890cef628eb9e8b0
---

 configure                      |   5 --
 libavfilter/avf_showspectrum.c | 106 ++++++++++++++++++++++++-----------------
 2 files changed, 62 insertions(+), 49 deletions(-)

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 <math.h>
 
-#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<<fft_bits)
-    FFTComplex **fft_data;      ///< bins holder for each (displayed) channels
-    FFTComplex **fft_scratch;   ///< scratch buffers
+    AVTXContext **fft;          ///< Fast Fourier Transform context
+    AVTXContext **ifft;         ///< Inverse Fast Fourier Transform context
+    av_tx_fn tx_fn;
+    av_tx_fn itx_fn;
+    int fft_size;               ///< number of coeffs (FFT window size)
+    AVComplexFloat **fft_in;    ///< input FFT coeffs
+    AVComplexFloat **fft_data;  ///< bins holder for each (displayed) channels
+    AVComplexFloat **fft_scratch;///< scratch buffers
     float *window_func_lut;     ///< Window function LUT
     float **magnitudes;
     float **phases;
@@ -305,12 +308,12 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_freep(&s->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);



More information about the ffmpeg-cvslog mailing list