summaryrefslogtreecommitdiff
path: root/libavfilter/avf_showspectrum.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2021-07-24 14:22:38 +0200
committerPaul B Mahol <onemda@gmail.com>2021-07-24 16:49:53 +0200
commit014ace8f98cc4a1a88e7a6d5890cef628eb9e8b0 (patch)
tree441fe0cd84dc886c79310540da79749563035834 /libavfilter/avf_showspectrum.c
parent88b6342c2ba425977aecba2955a256613dddec13 (diff)
avfilter/avf_showspectrum: switch to TX FFT from avutil
Diffstat (limited to 'libavfilter/avf_showspectrum.c')
-rw-r--r--libavfilter/avf_showspectrum.c106
1 files changed, 62 insertions, 44 deletions
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);